@@ -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,40 @@ 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 && ! length ) {
39
+ return str
40
+ }
41
+ if ( str . toLowerCase ( ) . startsWith ( '0x' ) ) {
42
+ str = str . slice ( 2 )
43
+ }
44
+ if ( ! / ^ [ 0 - 9 a - f ] { 2 } ( [ 0 - 9 a - f ] { 2 } ) * $ / i. test ( str ) ) {
45
+ const howMany = typeof length === 'number' ? length : 'empty or a non-zero even number of'
46
+ throw new Error ( `Invalid ${ paramName } , string must be ${ howMany } hex characters` )
47
+ }
48
+ if ( typeof length === 'number' && str . length !== length ) {
49
+ throw new Error ( `Invalid ${ paramName } , string must be ${ length } hex characters` )
50
+ }
51
+ return str
52
+ }
53
+
54
+ function validateBuffer ( paramName : string , buff : Buffer , length ?: number ) {
55
+ if ( ! Buffer . isBuffer ( buff ) ) {
56
+ const howManyHex =
57
+ typeof length === 'number' ? `${ length * 2 } ` : 'empty or a non-zero even number of'
58
+ const howManyBytes = typeof length === 'number' ? ` (${ length } bytes)` : ''
59
+ throw new Error (
60
+ `Invalid ${ paramName } , must be a string (${ howManyHex } hex characters) or buffer${ howManyBytes } ` ,
61
+ )
62
+ }
63
+ if ( typeof length === 'number' && buff . length !== length ) {
64
+ throw new Error ( `Invalid ${ paramName } , buffer must be ${ length } bytes` )
65
+ }
66
+ return buff
67
+ }
68
+
69
+ function mergeToV3ParamsWithDefaults ( params ?: Partial < V3Params > ) : V3ParamsStrict {
70
+ const v3Defaults : V3ParamsStrict = {
26
71
cipher : 'aes-128-ctr' ,
27
72
kdf : 'scrypt' ,
28
73
salt : randomBytes ( 32 ) ,
@@ -38,17 +83,38 @@ function mergeToV3ParamsWithDefaults(params?: Partial<V3Params>): V3Params {
38
83
if ( ! params ) {
39
84
return v3Defaults
40
85
}
86
+
87
+ if ( typeof params . salt === 'string' ) {
88
+ params . salt = Buffer . from ( validateHexString ( 'salt' , params . salt ) , 'hex' )
89
+ }
90
+ if ( typeof params . iv === 'string' ) {
91
+ params . iv = Buffer . from ( validateHexString ( 'iv' , params . iv , 32 ) , 'hex' )
92
+ }
93
+ if ( typeof params . uuid === 'string' ) {
94
+ params . uuid = Buffer . from ( validateHexString ( 'uuid' , params . uuid , 32 ) , 'hex' )
95
+ }
96
+
97
+ if ( params . salt ) {
98
+ validateBuffer ( 'salt' , params . salt )
99
+ }
100
+ if ( params . iv ) {
101
+ validateBuffer ( 'iv' , params . iv , 16 )
102
+ }
103
+ if ( params . uuid ) {
104
+ validateBuffer ( 'uuid' , params . uuid , 16 )
105
+ }
106
+
41
107
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 ,
108
+ cipher : params . cipher || v3Defaults . cipher ,
109
+ kdf : params . kdf || v3Defaults . kdf ,
110
+ salt : params . salt || v3Defaults . salt ,
111
+ iv : params . iv || v3Defaults . iv ,
112
+ uuid : params . uuid || v3Defaults . uuid ,
113
+ dklen : params . dklen || v3Defaults . dklen ,
114
+ c : params . c || v3Defaults . c ,
115
+ n : params . n || v3Defaults . n ,
116
+ r : params . r || v3Defaults . r ,
117
+ p : params . p || v3Defaults . p ,
52
118
}
53
119
}
54
120
@@ -60,6 +126,14 @@ const enum KDFFunctions {
60
126
}
61
127
62
128
interface ScryptKDFParams {
129
+ dklen : number
130
+ n : number
131
+ p : number
132
+ r : number
133
+ salt : Buffer
134
+ }
135
+
136
+ interface ScryptKDFParamsOut {
63
137
dklen : number
64
138
n : number
65
139
p : number
@@ -68,27 +142,35 @@ interface ScryptKDFParams {
68
142
}
69
143
70
144
interface PBKDFParams {
145
+ c : number
146
+ dklen : number
147
+ prf : string
148
+ salt : Buffer
149
+ }
150
+
151
+ interface PBKDFParamsOut {
71
152
c : number
72
153
dklen : number
73
154
prf : string
74
155
salt : string
75
156
}
76
157
77
158
type KDFParams = ScryptKDFParams | PBKDFParams
159
+ type KDFParamsOut = ScryptKDFParamsOut | PBKDFParamsOut
78
160
79
- function kdfParamsForPBKDF ( opts : V3Params ) : PBKDFParams {
161
+ function kdfParamsForPBKDF ( opts : V3ParamsStrict ) : PBKDFParams {
80
162
return {
81
163
dklen : opts . dklen ,
82
- salt : opts . salt . toString ( 'hex' ) ,
164
+ salt : opts . salt ,
83
165
c : opts . c ,
84
166
prf : 'hmac-sha256' ,
85
167
}
86
168
}
87
169
88
- function kdfParamsForScrypt ( opts : V3Params ) : ScryptKDFParams {
170
+ function kdfParamsForScrypt ( opts : V3ParamsStrict ) : ScryptKDFParams {
89
171
return {
90
172
dklen : opts . dklen ,
91
- salt : opts . salt . toString ( 'hex' ) ,
173
+ salt : opts . salt ,
92
174
n : opts . n ,
93
175
r : opts . r ,
94
176
p : opts . p ,
@@ -130,7 +212,7 @@ interface V3Keystore {
130
212
}
131
213
ciphertext : string
132
214
kdf : string
133
- kdfparams : KDFParams
215
+ kdfparams : KDFParamsOut
134
216
mac : string
135
217
}
136
218
id : string
@@ -361,6 +443,7 @@ export default class Wallet {
361
443
362
444
// public instance methods
363
445
446
+ // tslint:disable-next-line
364
447
public getPrivateKey ( ) : Buffer {
365
448
return this . privKey
366
449
}
@@ -369,6 +452,7 @@ export default class Wallet {
369
452
return ethUtil . bufferToHex ( this . privKey )
370
453
}
371
454
455
+ // tslint:disable-next-line
372
456
public getPublicKey ( ) : Buffer {
373
457
return this . pubKey
374
458
}
@@ -394,9 +478,9 @@ export default class Wallet {
394
478
throw new Error ( 'This is a public key only wallet' )
395
479
}
396
480
397
- const v3Params : V3Params = mergeToV3ParamsWithDefaults ( opts )
481
+ const v3Params : V3ParamsStrict = mergeToV3ParamsWithDefaults ( opts )
398
482
399
- let kdfParams : PBKDFParams | ScryptKDFParams
483
+ let kdfParams : KDFParams
400
484
let derivedKey : Buffer
401
485
switch ( v3Params . kdf ) {
402
486
case KDFFunctions . PBKDF :
@@ -449,7 +533,10 @@ export default class Wallet {
449
533
cipherparams : { iv : v3Params . iv . toString ( 'hex' ) } ,
450
534
cipher : v3Params . cipher ,
451
535
kdf : v3Params . kdf ,
452
- kdfparams : kdfParams ,
536
+ kdfparams : {
537
+ ...kdfParams ,
538
+ salt : kdfParams . salt . toString ( 'hex' ) ,
539
+ } ,
453
540
mac : mac . toString ( 'hex' ) ,
454
541
} ,
455
542
}
0 commit comments