@@ -9,17 +9,11 @@ import CryptoSwift
9
9
import Foundation
10
10
11
11
public class EthereumKeystoreV3 : AbstractKeystore {
12
- public typealias Params = KeystoreParamsV3
13
- public var keystoreParams : Params ?
14
-
15
- public func giveKeystoreParams( ) -> Params {
16
- keystoreParams!
17
- }
18
-
19
-
20
12
// Protocol
21
- private var address : EthereumAddress ?
22
13
public var isHDKeystore : Bool = false
14
+ private var address : EthereumAddress ?
15
+ public var keystoreParams : KeystoreParamsV3 ?
16
+
23
17
24
18
public var addresses : [ EthereumAddress ] ? {
25
19
get {
@@ -32,7 +26,9 @@ public class EthereumKeystoreV3: AbstractKeystore {
32
26
33
27
public func UNSAFE_getPrivateKeyData( password: String , account: EthereumAddress ) throws -> Data {
34
28
if self . addresses? . count == 1 && account == self . addresses? . last {
35
- guard let privateKey = try ? self . getKeyData ( password) else { throw AbstractKeystoreError . invalidPasswordError}
29
+ guard let privateKey = try ? self . getKeyData ( password) else {
30
+ throw AbstractKeystoreError . invalidPasswordError
31
+ }
36
32
return privateKey
37
33
}
38
34
throw AbstractKeystoreError . invalidAccountError
@@ -48,18 +44,26 @@ public class EthereumKeystoreV3: AbstractKeystore {
48
44
49
45
public convenience init ? ( _ jsonString: String ) {
50
46
let lowercaseJSON = jsonString. lowercased ( )
51
- guard let jsonData = lowercaseJSON. data ( using: . utf8) else { return nil }
47
+ guard let jsonData = lowercaseJSON. data ( using: . utf8) else {
48
+ return nil
49
+ }
52
50
self . init ( jsonData)
53
51
}
54
52
55
53
public convenience init ? ( _ jsonData: Data ) {
56
- guard let keystoreParams = try ? JSONDecoder ( ) . decode ( KeystoreParamsV3 . self, from: jsonData) else { return nil }
54
+ guard let keystoreParams = try ? JSONDecoder ( ) . decode ( KeystoreParamsV3 . self, from: jsonData) else {
55
+ return nil
56
+ }
57
57
self . init ( keystoreParams)
58
58
}
59
59
60
60
public init ? ( _ keystoreParams: KeystoreParamsV3 ) {
61
- if ( keystoreParams. version != 3 ) { return nil }
62
- if ( keystoreParams. crypto. version != nil && keystoreParams. crypto. version != " 1 " ) { return nil }
61
+ if ( keystoreParams. version != 3 ) {
62
+ return nil
63
+ }
64
+ if ( keystoreParams. crypto. version != nil && keystoreParams. crypto. version != " 1 " ) {
65
+ return nil
66
+ }
63
67
self . keystoreParams = keystoreParams
64
68
if keystoreParams. address != nil {
65
69
self . address = EthereumAddress ( keystoreParams. address!. addHexPrefix ( ) )
@@ -68,29 +72,43 @@ public class EthereumKeystoreV3: AbstractKeystore {
68
72
}
69
73
}
70
74
71
- public init ? ( password: String = " web3swift " , aesMode: String = " aes-128-cbc " ) throws {
72
- guard var newPrivateKey = SECP256K1 . generatePrivateKey ( ) else { return nil }
73
- defer { Data . zero ( & newPrivateKey) }
75
+ public init ? ( password: String = " web3swift " , aesMode: String = " aes-128-cbc " ) throws {
76
+ guard var newPrivateKey = SECP256K1 . generatePrivateKey ( ) else {
77
+ return nil
78
+ }
79
+ defer {
80
+ Data . zero ( & newPrivateKey)
81
+ }
74
82
try encryptDataToStorage ( password, keyData: newPrivateKey, aesMode: aesMode)
75
83
}
76
84
77
- public init ? ( privateKey: Data , password: String = " web3swift " , aesMode: String = " aes-128-cbc " ) throws {
78
- guard privateKey. count == 32 else { return nil }
79
- guard SECP256K1 . verifyPrivateKey ( privateKey: privateKey) else { return nil }
85
+ public init ? ( privateKey: Data , password: String = " web3swift " , aesMode: String = " aes-128-cbc " ) throws {
86
+ guard privateKey. count == 32 else {
87
+ return nil
88
+ }
89
+ guard SECP256K1 . verifyPrivateKey ( privateKey: privateKey) else {
90
+ return nil
91
+ }
80
92
try encryptDataToStorage ( password, keyData: privateKey, aesMode: aesMode)
81
93
}
82
94
83
- fileprivate func encryptDataToStorage( _ password: String , keyData: Data ? , dkLen: Int = 32 , N: Int = 4096 , R: Int = 6 , P: Int = 1 , aesMode: String = " aes-128-cbc " ) throws {
95
+ fileprivate func encryptDataToStorage( _ password: String , keyData: Data ? , dkLen: Int = 32 , N: Int = 4096 , R: Int = 6 , P: Int = 1 , aesMode: String = " aes-128-cbc " ) throws {
84
96
if ( keyData == nil ) {
85
97
throw AbstractKeystoreError . encryptionError ( " Encryption without key data " )
86
98
}
87
99
let saltLen = 32 ;
88
- guard let saltData = Data . randomBytes ( length: saltLen) else { throw AbstractKeystoreError . noEntropyError}
89
- guard let derivedKey = scrypt ( password: password, salt: saltData, length: dkLen, N: N, R: R, P: P) else { throw AbstractKeystoreError . keyDerivationError}
90
- let last16bytes = Data ( derivedKey [ ( derivedKey. count - 16 ) ... ( derivedKey. count- 1 ) ] )
100
+ guard let saltData = Data . randomBytes ( length: saltLen) else {
101
+ throw AbstractKeystoreError . noEntropyError
102
+ }
103
+ guard let derivedKey = scrypt ( password: password, salt: saltData, length: dkLen, N: N, R: R, P: P) else {
104
+ throw AbstractKeystoreError . keyDerivationError
105
+ }
106
+ let last16bytes = Data ( derivedKey [ ( derivedKey. count - 16 ) ... ( derivedKey. count - 1 ) ] )
91
107
let encryptionKey = Data ( derivedKey [ 0 ... 15 ] )
92
- guard let IV = Data . randomBytes ( length: 16 ) else { throw AbstractKeystoreError . noEntropyError}
93
- var aesCipher : AES ?
108
+ guard let IV = Data . randomBytes ( length: 16 ) else {
109
+ throw AbstractKeystoreError . noEntropyError
110
+ }
111
+ var aesCipher : AES ?
94
112
switch aesMode {
95
113
case " aes-128-cbc " :
96
114
aesCipher = try ? AES ( key: encryptionKey. bytes, blockMode: CBC ( iv: IV . bytes) , padding: . noPadding)
@@ -102,7 +120,9 @@ public class EthereumKeystoreV3: AbstractKeystore {
102
120
if aesCipher == nil {
103
121
throw AbstractKeystoreError . aesError
104
122
}
105
- guard let encryptedKey = try aesCipher? . encrypt ( keyData!. bytes) else { throw AbstractKeystoreError . aesError}
123
+ guard let encryptedKey = try aesCipher? . encrypt ( keyData!. bytes) else {
124
+ throw AbstractKeystoreError . aesError
125
+ }
106
126
// let encryptedKeyData = Data(bytes:encryptedKey)
107
127
let encryptedKeyData = Data ( encryptedKey)
108
128
var dataForMAC = Data ( )
@@ -112,85 +132,129 @@ public class EthereumKeystoreV3: AbstractKeystore {
112
132
let kdfparams = KdfParamsV3 ( salt: saltData. toHexString ( ) , dklen: dkLen, n: N, p: P, r: R, c: nil , prf: nil )
113
133
let cipherparams = CipherParamsV3 ( iv: IV . toHexString ( ) )
114
134
let crypto = CryptoParamsV3 ( ciphertext: encryptedKeyData. toHexString ( ) , cipher: aesMode, cipherparams: cipherparams, kdf: " scrypt " , kdfparams: kdfparams, mac: mac. toHexString ( ) , version: nil )
115
- guard let pubKey = Web3 . Utils. privateToPublic ( keyData!) else { throw AbstractKeystoreError . keyDerivationError}
116
- guard let addr = Web3 . Utils. publicToAddress ( pubKey) else { throw AbstractKeystoreError . keyDerivationError}
135
+ guard let pubKey = Web3 . Utils. privateToPublic ( keyData!) else {
136
+ throw AbstractKeystoreError . keyDerivationError
137
+ }
138
+ guard let addr = Web3 . Utils. publicToAddress ( pubKey) else {
139
+ throw AbstractKeystoreError . keyDerivationError
140
+ }
117
141
self . address = addr
118
142
let keystoreparams = KeystoreParamsV3 ( address: addr. address. lowercased ( ) , crypto: crypto, id: UUID ( ) . uuidString. lowercased ( ) , version: 3 )
119
143
self . keystoreParams = keystoreparams
120
144
}
121
145
122
- public func regenerate( oldPassword: String , newPassword: String , dkLen: Int = 32 , N: Int = 4096 , R: Int = 6 , P: Int = 1 ) throws {
146
+ public func regenerate( oldPassword: String , newPassword: String , dkLen: Int = 32 , N: Int = 4096 , R: Int = 6 , P: Int = 1 ) throws {
123
147
var keyData = try self . getKeyData ( oldPassword)
124
148
if keyData == nil {
125
149
throw AbstractKeystoreError . encryptionError ( " Failed to decrypt a keystore " )
126
150
}
127
- defer { Data . zero ( & keyData!) }
151
+ defer {
152
+ Data . zero ( & keyData!)
153
+ }
128
154
try self . encryptDataToStorage ( newPassword, keyData: keyData!, aesMode: self . keystoreParams!. crypto. cipher)
129
155
}
130
156
131
157
fileprivate func getKeyData( _ password: String ) throws -> Data ? {
132
- guard let keystoreParams = self . keystoreParams else { return nil }
133
- guard let saltData = Data . fromHex ( keystoreParams. crypto. kdfparams. salt) else { return nil }
158
+ guard let keystoreParams = self . keystoreParams else {
159
+ return nil
160
+ }
161
+ guard let saltData = Data . fromHex ( keystoreParams. crypto. kdfparams. salt) else {
162
+ return nil
163
+ }
134
164
let derivedLen = keystoreParams. crypto. kdfparams. dklen
135
- var passwordDerivedKey : Data ?
165
+ var passwordDerivedKey : Data ?
136
166
switch keystoreParams. crypto. kdf {
137
167
case " scrypt " :
138
- guard let N = keystoreParams. crypto. kdfparams. n else { return nil }
139
- guard let P = keystoreParams. crypto. kdfparams. p else { return nil }
140
- guard let R = keystoreParams. crypto. kdfparams. r else { return nil }
168
+ guard let N = keystoreParams. crypto. kdfparams. n else {
169
+ return nil
170
+ }
171
+ guard let P = keystoreParams. crypto. kdfparams. p else {
172
+ return nil
173
+ }
174
+ guard let R = keystoreParams. crypto. kdfparams. r else {
175
+ return nil
176
+ }
141
177
passwordDerivedKey = scrypt ( password: password, salt: saltData, length: derivedLen, N: N, R: R, P: P)
142
178
case " pbkdf2 " :
143
- guard let algo = keystoreParams. crypto. kdfparams. prf else { return nil }
144
- var hashVariant : HMAC . Variant ? ;
179
+ guard let algo = keystoreParams. crypto. kdfparams. prf else {
180
+ return nil
181
+ }
182
+ var hashVariant : HMAC . Variant ? ;
145
183
switch algo {
146
- case " hmac-sha256 " :
147
- hashVariant = HMAC . Variant. sha256
148
- case " hmac-sha384 " :
149
- hashVariant = HMAC . Variant. sha384
150
- case " hmac-sha512 " :
151
- hashVariant = HMAC . Variant. sha512
152
- default :
153
- hashVariant = nil
184
+ case " hmac-sha256 " :
185
+ hashVariant = HMAC . Variant. sha256
186
+ case " hmac-sha384 " :
187
+ hashVariant = HMAC . Variant. sha384
188
+ case " hmac-sha512 " :
189
+ hashVariant = HMAC . Variant. sha512
190
+ default :
191
+ hashVariant = nil
192
+ }
193
+ guard hashVariant != nil else {
194
+ return nil
195
+ }
196
+ guard let c = keystoreParams. crypto. kdfparams. c else {
197
+ return nil
198
+ }
199
+ guard let passData = password. data ( using: . utf8) else {
200
+ return nil
201
+ }
202
+ guard let derivedArray = try ? PKCS5 . PBKDF2 ( password: passData. bytes, salt: saltData. bytes, iterations: c, keyLength: derivedLen, variant: hashVariant!) . calculate ( ) else {
203
+ return nil
154
204
}
155
- guard hashVariant != nil else { return nil }
156
- guard let c = keystoreParams. crypto. kdfparams. c else { return nil }
157
- guard let passData = password. data ( using: . utf8) else { return nil }
158
- guard let derivedArray = try ? PKCS5 . PBKDF2 ( password: passData. bytes, salt: saltData. bytes, iterations: c, keyLength: derivedLen, variant: hashVariant!) . calculate ( ) else { return nil }
159
205
// passwordDerivedKey = Data(bytes:derivedArray)
160
206
passwordDerivedKey = Data ( derivedArray)
161
207
default :
162
208
return nil
163
209
}
164
- guard let derivedKey = passwordDerivedKey else { return nil }
210
+ guard let derivedKey = passwordDerivedKey else {
211
+ return nil
212
+ }
165
213
var dataForMAC = Data ( )
166
214
let derivedKeyLast16bytes = Data ( derivedKey [ ( derivedKey. count - 16 ) ... ( derivedKey. count - 1 ) ] )
167
215
dataForMAC. append ( derivedKeyLast16bytes)
168
- guard let cipherText = Data . fromHex ( keystoreParams. crypto. ciphertext) else { return nil }
169
- if ( cipherText. count != 32 ) { return nil }
216
+ guard let cipherText = Data . fromHex ( keystoreParams. crypto. ciphertext) else {
217
+ return nil
218
+ }
219
+ if ( cipherText. count != 32 ) {
220
+ return nil
221
+ }
170
222
dataForMAC. append ( cipherText)
171
223
let mac = dataForMAC. sha3 ( . keccak256)
172
- guard let calculatedMac = Data . fromHex ( keystoreParams. crypto. mac) , mac. constantTimeComparisonTo ( calculatedMac) else { return nil }
224
+ guard let calculatedMac = Data . fromHex ( keystoreParams. crypto. mac) , mac. constantTimeComparisonTo ( calculatedMac) else {
225
+ return nil
226
+ }
173
227
let cipher = keystoreParams. crypto. cipher
174
228
let decryptionKey = derivedKey [ 0 ... 15 ]
175
- guard let IV = Data . fromHex ( keystoreParams. crypto. cipherparams. iv) else { return nil }
176
- var decryptedPK : Array < UInt8 > ?
229
+ guard let IV = Data . fromHex ( keystoreParams. crypto. cipherparams. iv) else {
230
+ return nil
231
+ }
232
+ var decryptedPK : Array < UInt8 > ?
177
233
switch cipher {
178
234
case " aes-128-ctr " :
179
- guard let aesCipher = try ? AES ( key: decryptionKey. bytes, blockMode: CTR ( iv: IV . bytes) , padding: . noPadding) else { return nil }
235
+ guard let aesCipher = try ? AES ( key: decryptionKey. bytes, blockMode: CTR ( iv: IV . bytes) , padding: . noPadding) else {
236
+ return nil
237
+ }
180
238
decryptedPK = try aesCipher. decrypt ( cipherText. bytes)
181
239
case " aes-128-cbc " :
182
- guard let aesCipher = try ? AES ( key: decryptionKey. bytes, blockMode: CBC ( iv: IV . bytes) , padding: . noPadding) else { return nil }
240
+ guard let aesCipher = try ? AES ( key: decryptionKey. bytes, blockMode: CBC ( iv: IV . bytes) , padding: . noPadding) else {
241
+ return nil
242
+ }
183
243
decryptedPK = try ? aesCipher. decrypt ( cipherText. bytes)
184
244
default :
185
245
return nil
186
246
}
187
- guard decryptedPK != nil else { return nil }
247
+ guard decryptedPK != nil else {
248
+ return nil
249
+ }
188
250
// return Data(bytes:decryptedPK!)
189
251
return Data ( decryptedPK!)
190
252
}
191
253
192
254
public func serialize( ) throws -> Data ? {
193
- guard let params = self . keystoreParams else { return nil }
255
+ guard let params = self . keystoreParams else {
256
+ return nil
257
+ }
194
258
let data = try JSONEncoder ( ) . encode ( params)
195
259
return data
196
260
}
0 commit comments