100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
lappend ::auto_path [file join [file dirname [info script]] lib [platform::identify]]
lappend ::auto_path [file join [file dirname [info script]] lib [platform::generic]]
lappend ::auto_path [file join [file dirname [info script]] lib]
package require pki
package require pki::pkcs11
package require aes
# Backports for older versions of "pki"
proc ::pki::pkcs::parse_public_key {key {password ""}} {
array set parsed_key [::pki::_parse_pem $key "-----BEGIN PUBLIC KEY-----" "-----END PUBLIC KEY-----" $password]
set key_seq $parsed_key(data)
|
>
|
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
lappend ::auto_path [file join [file dirname [info script]] lib [platform::identify]]
lappend ::auto_path [file join [file dirname [info script]] lib [platform::generic]]
lappend ::auto_path [file join [file dirname [info script]] lib]
package require pki
package require pki::pkcs11
package require aes
package require sha256
# Backports for older versions of "pki"
proc ::pki::pkcs::parse_public_key {key {password ""}} {
array set parsed_key [::pki::_parse_pem $key "-----BEGIN PUBLIC KEY-----" "-----END PUBLIC KEY-----" $password]
set key_seq $parsed_key(data)
|
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
lappend slotInfo [list handle $handle id $slotID prompt $slotPromptForPIN cert $cert pubkey $pubkey]
}
}
return $slotInfo
}
proc _addPassword {name password publicKeys} {
set fd [open "/dev/urandom" r]
fconfigure $fd -translation binary
db eval {DELETE FROM passwords WHERE name = $name;}
foreach publicKey $publicKeys {
set key [read $fd 16]
if {[string length $key] != 16} {
close $fd
return -code error "ERROR: Short read from random device"
}
set publicKeyItem [::pki::pkcs::parse_public_key [binary decode base64 $publicKey]]
set encryptedKey [binary encode base64 [::pki::encrypt -pub -binary -- $key $publicKeyItem]]
set encryptedPass [binary encode base64 [::aes::aes -dir encrypt -key $key -- $password]]
db eval {INSERT INTO passwords (name, encryptedPass, encryptedKey, publicKey) VALUES ($name, @encryptedPass, @encryptedKey, @publicKey);}
}
close $fd
}
proc _prompt {prompt} {
puts -nonewline $prompt
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
>
>
>
|
|
|
>
>
>
|
>
|
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
|
lappend slotInfo [list handle $handle id $slotID prompt $slotPromptForPIN cert $cert pubkey $pubkey]
}
}
return $slotInfo
}
proc _verifyPassword {name password} {
set publicKeys [list]
db eval {SELECT publicKey, verification FROM passwords WHERE name = $name} row {
set salt [dict get $row(verification) salt]
set hashAlgorithm [dict get $row(verification) hashAlgorithm]
set publicKey $row(publicKey)
set plaintext "${salt}|${publicKey}|${password}"
switch -- $hashAlgorithm {
"sha256" {
set verificationHash [sha2::sha256 -hex -- $plaintext]
}
default {
return -code error "Unknown hashing algorithm: $hashAlgorithm"
}
}
set row(verificationHash) [dict get $row(verification) hash]
if {$verificationHash ne $row(verificationHash)} {
puts stderr "FAILED: verification failed for $name with public key $publicKey -- it will not get the new password."
continue
}
lappend publicKeys $publicKey
}
return $publicKeys
}
proc _addPassword {name password publicKeys} {
set fd [open "/dev/urandom" r]
fconfigure $fd -translation binary
set keySize 16
# Pad the password with 0 bytes until it is a multiple of the key size
set blockPassword $password
append blockPassword [string repeat "\x00" [expr {-[string length $password] % $keySize}]]
db transaction {
db eval {DELETE FROM passwords WHERE name = $name;}
foreach publicKey $publicKeys {
set key [read $fd $keySize]
if {[string length $key] != $keySize} {
close $fd
return -code error "ERROR: Short read from random device"
}
set salt [read $fd $keySize]
set salt [binary encode base64 $salt]
set publicKeyItem [::pki::pkcs::parse_public_key [binary decode base64 $publicKey]]
set encryptedKey [binary encode base64 [::pki::encrypt -pub -binary -- $key $publicKeyItem]]
set encryptedPass [binary encode base64 [::aes::aes -dir encrypt -key $key -- $blockPassword]]
set verificationHash [sha2::sha256 -hex -- "${salt}|${publicKey}|${password}"]
set verification [list salt $salt hashAlgorithm sha256 hash $verificationHash]
db eval {INSERT INTO passwords (name, encryptedPass, encryptedKey, publicKey, verification) VALUES ($name, @encryptedPass, @encryptedKey, @publicKey, @verification);}
}
}
close $fd
}
proc _prompt {prompt} {
puts -nonewline $prompt
|
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
|
set prompted($slotInfo(id)) 1
}
db eval {SELECT encryptedPass, encryptedKey FROM passwords WHERE name = $name AND publicKey = $pubkey;} row {
set key [::pki::decrypt -binary -priv -- [binary decode base64 $row(encryptedKey)] $slotInfo(cert)]
set password [::aes::aes -dir decrypt -key $key -- [binary decode base64 $row(encryptedPass)]]
return $password
}
}
return -code error "No valid keys"
}
proc _modifyPublicKeys {passwordName userNames sql} {
|
|
|
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
|
set prompted($slotInfo(id)) 1
}
db eval {SELECT encryptedPass, encryptedKey FROM passwords WHERE name = $name AND publicKey = $pubkey;} row {
set key [::pki::decrypt -binary -priv -- [binary decode base64 $row(encryptedKey)] $slotInfo(cert)]
set password [::aes::aes -dir decrypt -key $key -- [binary decode base64 $row(encryptedPass)]]
return [string trimright $password "\x00"]
}
}
return -code error "No valid keys"
}
proc _modifyPublicKeys {passwordName userNames sql} {
|
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
|
}
proc updatePassword {passwordName password} {
if {$password eq ""} {
set password [_prompt "Please enter the new password: "]
}
db eval {SELECT publicKey FROM passwords WHERE name = $passwordName;} row {
lappend publicKeys $row(publicKey)
}
_addPassword $passwordName $password $publicKeys
}
proc deletePassword {passwordName} {
db eval {DELETE FROM passwords WHERE name = $passwordName;}
|
>
|
>
|
>
>
|
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
|
}
proc updatePassword {passwordName password} {
if {$password eq ""} {
set password [_prompt "Please enter the new password: "]
}
set oldPassword [_getPassword $passwordName]
set publicKeys [_verifyPassword $passwordName $oldPassword]
if {[llength $publicKeys] == 0} {
puts stderr "Warning: This will delete the password since there are no valid public keys."
}
_addPassword $passwordName $password $publicKeys
}
proc deletePassword {passwordName} {
db eval {DELETE FROM passwords WHERE name = $passwordName;}
|
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
|
### MAIN
sqlite3 db $passwordFile
db eval {
CREATE TABLE IF NOT EXISTS users(name, publicKey BLOB);
CREATE TABLE IF NOT EXISTS passwords(name, encryptedPass BLOB, encryptedKey BLOB, publicKey BLOB);
}
if {$action in $validCommands} {
if {[catch {
$action {*}$argv
} error]} {
puts stderr "Error: $error"
|
|
|
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
|
### MAIN
sqlite3 db $passwordFile
db eval {
CREATE TABLE IF NOT EXISTS users(name, publicKey BLOB);
CREATE TABLE IF NOT EXISTS passwords(name, encryptedPass BLOB, encryptedKey BLOB, publicKey BLOB, verification BLOB);
}
if {$action in $validCommands} {
if {[catch {
$action {*}$argv
} error]} {
puts stderr "Error: $error"
|