@@ -9,9 +9,10 @@ const uint8ArrayToString = require('uint8arrays/to-string')
9
9
10
10
const peerUtils = require ( '../utils/creators/peer' )
11
11
12
- const { MemoryDatastore } = require ( 'interface-datastore' )
12
+ const { MemoryDatastore, Key } = require ( 'interface-datastore' )
13
13
const Keychain = require ( '../../src/keychain' )
14
14
const PeerId = require ( 'peer-id' )
15
+ const crypto = require ( 'libp2p-crypto' )
15
16
16
17
describe ( 'keychain' , ( ) => {
17
18
const passPhrase = 'this is not a secure phrase'
@@ -492,6 +493,88 @@ describe('keychain', () => {
492
493
expect ( key ) . to . have . property ( 'id' , rsaKeyInfo . id )
493
494
} )
494
495
} )
496
+
497
+ describe ( 'rotate keychain passphrase' , ( ) => {
498
+ let oldPass
499
+ let kc
500
+ let options
501
+ let ds
502
+ before ( async ( ) => {
503
+ ds = new MemoryDatastore ( )
504
+ oldPass = `hello-${ Date . now ( ) } -${ Date . now ( ) } `
505
+ options = {
506
+ pass : oldPass ,
507
+ dek : {
508
+ salt : '3Nd/Ya4ENB3bcByNKptb4IR' ,
509
+ iterationCount : 10000 ,
510
+ keyLength : 64 ,
511
+ hash : 'sha2-512'
512
+ }
513
+ }
514
+ kc = new Keychain ( ds , options )
515
+ await ds . open ( )
516
+ } )
517
+
518
+ it ( 'should validate newPass is a string' , async ( ) => {
519
+ try {
520
+ await kc . rotateKeychainPass ( oldPass , 1234567890 )
521
+ } catch ( err ) {
522
+ expect ( err ) . to . exist ( )
523
+ }
524
+ } )
525
+
526
+ it ( 'should validate oldPass is a string' , async ( ) => {
527
+ try {
528
+ await kc . rotateKeychainPass ( 1234 , 'newInsecurePassword1' )
529
+ } catch ( err ) {
530
+ expect ( err ) . to . exist ( )
531
+ }
532
+ } )
533
+
534
+ it ( 'should validate newPass is at least 20 characters' , async ( ) => {
535
+ try {
536
+ await kc . rotateKeychainPass ( oldPass , 'not20Chars' )
537
+ } catch ( err ) {
538
+ expect ( err ) . to . exist ( )
539
+ }
540
+ } )
541
+
542
+ it ( 'can rotate keychain passphrase' , async ( ) => {
543
+ await kc . createKey ( 'keyCreatedWithOldPassword' , 'rsa' , 2048 )
544
+ await kc . rotateKeychainPass ( oldPass , 'newInsecurePassphrase' )
545
+
546
+ // Get Key PEM from datastore
547
+ const dsname = new Key ( '/pkcs8/' + 'keyCreatedWithOldPassword' )
548
+ const res = await ds . get ( dsname )
549
+ const pem = uint8ArrayToString ( res )
550
+
551
+ const oldDek = options . pass
552
+ ? crypto . pbkdf2 (
553
+ options . pass ,
554
+ options . dek . salt ,
555
+ options . dek . iterationCount ,
556
+ options . dek . keyLength ,
557
+ options . dek . hash )
558
+ : ''
559
+
560
+ // eslint-disable-next-line no-constant-condition
561
+ const newDek = 'newInsecurePassphrase'
562
+ ? crypto . pbkdf2 (
563
+ 'newInsecurePassphrase' ,
564
+ options . dek . salt ,
565
+ options . dek . iterationCount ,
566
+ options . dek . keyLength ,
567
+ options . dek . hash )
568
+ : ''
569
+
570
+ // Dek with old password should not work:
571
+ await expect ( kc . importKey ( 'keyWhosePassChanged' , pem , oldDek ) )
572
+ . to . eventually . be . rejected ( )
573
+ // Dek with new password should work:
574
+ await expect ( kc . importKey ( 'keyWhosePasswordChanged' , pem , newDek ) )
575
+ . to . eventually . have . property ( 'name' , 'keyWhosePasswordChanged' )
576
+ } ) . timeout ( 10000 )
577
+ } )
495
578
} )
496
579
497
580
describe ( 'libp2p.keychain' , ( ) => {
0 commit comments