@@ -9,6 +9,19 @@ const uuidv4 = require('uuid/v4')
9
9
// parameters for the toV3() method
10
10
11
11
interface V3Params {
12
+ kdf : string
13
+ cipher : string
14
+ salt : string | Buffer
15
+ iv : string | Buffer
16
+ uuid : string | Buffer
17
+ dklen : number
18
+ c : number
19
+ n : number
20
+ r : number
21
+ p : number
22
+ }
23
+
24
+ interface V3ParamsStrict {
12
25
kdf : string
13
26
cipher : string
14
27
salt : Buffer
@@ -21,8 +34,43 @@ interface V3Params {
21
34
p : number
22
35
}
23
36
24
- function mergeToV3ParamsWithDefaults ( params ?: Partial < V3Params > ) : V3Params {
25
- const v3Defaults : V3Params = {
37
+ function validateHexString ( paramName : string , str : string , length ?: number ) {
38
+ if ( str . toLowerCase ( ) . startsWith ( '0x' ) ) {
39
+ str = str . slice ( 2 )
40
+ }
41
+ if ( ! str && ! length ) {
42
+ return str
43
+ }
44
+ if ( ( length as number ) % 2 ) {
45
+ throw new Error ( `Invalid length argument, must be an even number` )
46
+ }
47
+ if ( typeof length === 'number' && str . length !== length ) {
48
+ throw new Error ( `Invalid ${ paramName } , string must be ${ length } hex characters` )
49
+ }
50
+ if ( ! / ^ ( [ 0 - 9 a - f ] { 2 } ) + $ / i. test ( str ) ) {
51
+ const howMany = typeof length === 'number' ? length : 'empty or a non-zero even number of'
52
+ throw new Error ( `Invalid ${ paramName } , string must be ${ howMany } hex characters` )
53
+ }
54
+ return str
55
+ }
56
+
57
+ function validateBuffer ( paramName : string , buff : Buffer , length ?: number ) {
58
+ if ( ! Buffer . isBuffer ( buff ) ) {
59
+ const howManyHex =
60
+ typeof length === 'number' ? `${ length * 2 } ` : 'empty or a non-zero even number of'
61
+ const howManyBytes = typeof length === 'number' ? ` (${ length } bytes)` : ''
62
+ throw new Error (
63
+ `Invalid ${ paramName } , must be a string (${ howManyHex } hex characters) or buffer${ howManyBytes } ` ,
64
+ )
65
+ }
66
+ if ( typeof length === 'number' && buff . length !== length ) {
67
+ throw new Error ( `Invalid ${ paramName } , buffer must be ${ length } bytes` )
68
+ }
69
+ return buff
70
+ }
71
+
72
+ function mergeToV3ParamsWithDefaults ( params ?: Partial < V3Params > ) : V3ParamsStrict {
73
+ const v3Defaults : V3ParamsStrict = {
26
74
cipher : 'aes-128-ctr' ,
27
75
kdf : 'scrypt' ,
28
76
salt : randomBytes ( 32 ) ,
@@ -38,17 +86,30 @@ function mergeToV3ParamsWithDefaults(params?: Partial<V3Params>): V3Params {
38
86
if ( ! params ) {
39
87
return v3Defaults
40
88
}
89
+
90
+ if ( typeof params . salt === 'string' ) {
91
+ params . salt = Buffer . from ( validateHexString ( 'salt' , params . salt ) , 'hex' )
92
+ }
93
+ if ( typeof params . iv === 'string' ) {
94
+ params . iv = Buffer . from ( validateHexString ( 'iv' , params . iv , 32 ) , 'hex' )
95
+ }
96
+ if ( typeof params . uuid === 'string' ) {
97
+ params . uuid = Buffer . from ( validateHexString ( 'uuid' , params . uuid , 32 ) , 'hex' )
98
+ }
99
+
100
+ if ( params . salt ) {
101
+ validateBuffer ( 'salt' , params . salt )
102
+ }
103
+ if ( params . iv ) {
104
+ validateBuffer ( 'iv' , params . iv , 16 )
105
+ }
106
+ if ( params . uuid ) {
107
+ validateBuffer ( 'uuid' , params . uuid , 16 )
108
+ }
109
+
41
110
return {
42
- cipher : params . cipher || 'aes-128-ctr' ,
43
- kdf : params . kdf || 'scrypt' ,
44
- salt : params . salt || randomBytes ( 32 ) ,
45
- iv : params . iv || randomBytes ( 16 ) ,
46
- uuid : params . uuid || randomBytes ( 16 ) ,
47
- dklen : params . dklen || 32 ,
48
- c : params . c || 262144 ,
49
- n : params . n || 262144 ,
50
- r : params . r || 8 ,
51
- p : params . p || 1 ,
111
+ ...v3Defaults ,
112
+ ...( params as V3ParamsStrict ) ,
52
113
}
53
114
}
54
115
@@ -60,6 +121,14 @@ const enum KDFFunctions {
60
121
}
61
122
62
123
interface ScryptKDFParams {
124
+ dklen : number
125
+ n : number
126
+ p : number
127
+ r : number
128
+ salt : Buffer
129
+ }
130
+
131
+ interface ScryptKDFParamsOut {
63
132
dklen : number
64
133
n : number
65
134
p : number
@@ -68,27 +137,35 @@ interface ScryptKDFParams {
68
137
}
69
138
70
139
interface PBKDFParams {
140
+ c : number
141
+ dklen : number
142
+ prf : string
143
+ salt : Buffer
144
+ }
145
+
146
+ interface PBKDFParamsOut {
71
147
c : number
72
148
dklen : number
73
149
prf : string
74
150
salt : string
75
151
}
76
152
77
153
type KDFParams = ScryptKDFParams | PBKDFParams
154
+ type KDFParamsOut = ScryptKDFParamsOut | PBKDFParamsOut
78
155
79
- function kdfParamsForPBKDF ( opts : V3Params ) : PBKDFParams {
156
+ function kdfParamsForPBKDF ( opts : V3ParamsStrict ) : PBKDFParams {
80
157
return {
81
158
dklen : opts . dklen ,
82
- salt : opts . salt . toString ( 'hex' ) ,
159
+ salt : opts . salt ,
83
160
c : opts . c ,
84
161
prf : 'hmac-sha256' ,
85
162
}
86
163
}
87
164
88
- function kdfParamsForScrypt ( opts : V3Params ) : ScryptKDFParams {
165
+ function kdfParamsForScrypt ( opts : V3ParamsStrict ) : ScryptKDFParams {
89
166
return {
90
167
dklen : opts . dklen ,
91
- salt : opts . salt . toString ( 'hex' ) ,
168
+ salt : opts . salt ,
92
169
n : opts . n ,
93
170
r : opts . r ,
94
171
p : opts . p ,
@@ -130,7 +207,7 @@ interface V3Keystore {
130
207
}
131
208
ciphertext : string
132
209
kdf : string
133
- kdfparams : KDFParams
210
+ kdfparams : KDFParamsOut
134
211
mac : string
135
212
}
136
213
id : string
@@ -361,6 +438,7 @@ export default class Wallet {
361
438
362
439
// public instance methods
363
440
441
+ // tslint:disable-next-line
364
442
public getPrivateKey ( ) : Buffer {
365
443
return this . privKey
366
444
}
@@ -369,6 +447,7 @@ export default class Wallet {
369
447
return ethUtil . bufferToHex ( this . privKey )
370
448
}
371
449
450
+ // tslint:disable-next-line
372
451
public getPublicKey ( ) : Buffer {
373
452
return this . pubKey
374
453
}
@@ -394,16 +473,16 @@ export default class Wallet {
394
473
throw new Error ( 'This is a public key only wallet' )
395
474
}
396
475
397
- const v3Params : V3Params = mergeToV3ParamsWithDefaults ( opts )
476
+ const v3Params : V3ParamsStrict = mergeToV3ParamsWithDefaults ( opts )
398
477
399
- let kdfParams : PBKDFParams | ScryptKDFParams
478
+ let kdfParams : KDFParams
400
479
let derivedKey : Buffer
401
480
switch ( v3Params . kdf ) {
402
481
case KDFFunctions . PBKDF :
403
482
kdfParams = kdfParamsForPBKDF ( v3Params )
404
483
derivedKey = crypto . pbkdf2Sync (
405
484
Buffer . from ( password ) ,
406
- v3Params . salt ,
485
+ kdfParams . salt ,
407
486
kdfParams . c ,
408
487
kdfParams . dklen ,
409
488
'sha256' ,
@@ -414,7 +493,7 @@ export default class Wallet {
414
493
// FIXME: support progress reporting callback
415
494
derivedKey = scryptsy (
416
495
Buffer . from ( password ) ,
417
- v3Params . salt ,
496
+ kdfParams . salt ,
418
497
kdfParams . n ,
419
498
kdfParams . r ,
420
499
kdfParams . p ,
@@ -449,7 +528,10 @@ export default class Wallet {
449
528
cipherparams : { iv : v3Params . iv . toString ( 'hex' ) } ,
450
529
cipher : v3Params . cipher ,
451
530
kdf : v3Params . kdf ,
452
- kdfparams : kdfParams ,
531
+ kdfparams : {
532
+ ...kdfParams ,
533
+ salt : kdfParams . salt . toString ( 'hex' ) ,
534
+ } ,
453
535
mac : mac . toString ( 'hex' ) ,
454
536
} ,
455
537
}
0 commit comments