@@ -23,13 +23,13 @@ public class EthereumKeystoreV3: AbstractKeystore {
23
23
}
24
24
25
25
public func UNSAFE_getPrivateKeyData( password: String , account: EthereumAddress ) throws -> Data {
26
- if self . addresses ? . count == 1 && account == self . addresses? . last {
27
- guard let privateKey = try ? self . getKeyData ( password) else {
26
+ if account == addresses? . last {
27
+ guard let privateKey = try ? getKeyData ( password) else {
28
28
throw AbstractKeystoreError . invalidPasswordError
29
29
}
30
30
return privateKey
31
31
}
32
- throw AbstractKeystoreError . invalidAccountError
32
+ throw AbstractKeystoreError . invalidAccountError ( " EthereumKeystoreV3. Cannot get private key: keystore doesn't contain information about given address \( account . address ) . " )
33
33
}
34
34
35
35
// Class
@@ -77,7 +77,7 @@ public class EthereumKeystoreV3: AbstractKeystore {
77
77
defer {
78
78
Data . zero ( & newPrivateKey)
79
79
}
80
- try encryptDataToStorage ( password, keyData : newPrivateKey, aesMode: aesMode)
80
+ try encryptDataToStorage ( password, privateKey : newPrivateKey, aesMode: aesMode)
81
81
}
82
82
83
83
public init ? ( privateKey: Data , password: String , aesMode: String = " aes-128-cbc " ) throws {
@@ -87,68 +87,60 @@ public class EthereumKeystoreV3: AbstractKeystore {
87
87
guard SECP256K1 . verifyPrivateKey ( privateKey: privateKey) else {
88
88
return nil
89
89
}
90
- try encryptDataToStorage ( password, keyData : privateKey, aesMode: aesMode)
90
+ try encryptDataToStorage ( password, privateKey : privateKey, aesMode: aesMode)
91
91
}
92
92
93
- 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 {
94
- if keyData == nil {
95
- throw AbstractKeystoreError . encryptionError ( " Encryption without key data " )
93
+ fileprivate func encryptDataToStorage( _ password: String , privateKey : Data , dkLen: Int = 32 , N: Int = 4096 , R: Int = 6 , P: Int = 1 , aesMode: String = " aes-128-cbc " ) throws {
94
+ if privateKey . count != 32 {
95
+ throw AbstractKeystoreError . encryptionError ( " EthereumKeystoreV3. Attempted encryption with private key of length != 32. Given private key length is \( privateKey . count ) . " )
96
96
}
97
97
let saltLen = 32
98
98
guard let saltData = Data . randomBytes ( length: saltLen) else {
99
- throw AbstractKeystoreError . noEntropyError
99
+ throw AbstractKeystoreError . noEntropyError ( " EthereumKeystoreV3. Failed to generate random bytes: `Data.randomBytes(length: \( saltLen ) )`. " )
100
100
}
101
101
guard let derivedKey = scrypt ( password: password, salt: saltData, length: dkLen, N: N, R: R, P: P) else {
102
- throw AbstractKeystoreError . keyDerivationError
102
+ throw AbstractKeystoreError . keyDerivationError ( " EthereumKeystoreV3. Scrypt function failed. " )
103
103
}
104
104
let last16bytes = Data ( derivedKey [ ( derivedKey. count - 16 ) ... ( derivedKey. count - 1 ) ] )
105
105
let encryptionKey = Data ( derivedKey [ 0 ... 15 ] )
106
106
guard let IV = Data . randomBytes ( length: 16 ) else {
107
- throw AbstractKeystoreError . noEntropyError
107
+ throw AbstractKeystoreError . noEntropyError ( " EthereumKeystoreV3. Failed to generate random bytes: `Data.randomBytes(length: 16)`. " )
108
108
}
109
- var aesCipher : AES ?
110
- switch aesMode {
109
+ var aesCipher : AES
110
+ switch aesMode. lowercased ( ) {
111
111
case " aes-128-cbc " :
112
- aesCipher = try ? AES ( key: encryptionKey. bytes, blockMode: CBC ( iv: IV . bytes) , padding: . noPadding)
112
+ aesCipher = try AES ( key: encryptionKey. bytes, blockMode: CBC ( iv: IV . bytes) , padding: . noPadding)
113
113
case " aes-128-ctr " :
114
- aesCipher = try ? AES ( key: encryptionKey. bytes, blockMode: CTR ( iv: IV . bytes) , padding: . noPadding)
114
+ aesCipher = try AES ( key: encryptionKey. bytes, blockMode: CTR ( iv: IV . bytes) , padding: . noPadding)
115
115
default :
116
- aesCipher = nil
116
+ throw AbstractKeystoreError . aesError ( " EthereumKeystoreV3. AES error: given AES mode can be one of 'aes-128-cbc' or 'aes-128-ctr'. Instead ' \( aesMode ) ' was given. " )
117
117
}
118
- if aesCipher == nil {
119
- throw AbstractKeystoreError . aesError
120
- }
121
- guard let encryptedKey = try aesCipher? . encrypt ( keyData!. bytes) else {
122
- throw AbstractKeystoreError . aesError
123
- }
124
- let encryptedKeyData = Data ( encryptedKey)
125
- var dataForMAC = Data ( )
126
- dataForMAC. append ( last16bytes)
127
- dataForMAC. append ( encryptedKeyData)
118
+
119
+ let encryptedKeyData = Data ( try aesCipher. encrypt ( privateKey. bytes) )
120
+ let dataForMAC = last16bytes + encryptedKeyData
128
121
let mac = dataForMAC. sha3 ( . keccak256)
129
122
let kdfparams = KdfParamsV3 ( salt: saltData. toHexString ( ) , dklen: dkLen, n: N, p: P, r: R, c: nil , prf: nil )
130
123
let cipherparams = CipherParamsV3 ( iv: IV . toHexString ( ) )
131
124
let crypto = CryptoParamsV3 ( ciphertext: encryptedKeyData. toHexString ( ) , cipher: aesMode, cipherparams: cipherparams, kdf: " scrypt " , kdfparams: kdfparams, mac: mac. toHexString ( ) , version: nil )
132
- guard let pubKey = Utilities . privateToPublic ( keyData! ) else {
133
- throw AbstractKeystoreError . keyDerivationError
125
+ guard let publicKey = Utilities . privateToPublic ( privateKey ) else {
126
+ throw AbstractKeystoreError . keyDerivationError ( " EthereumKeystoreV3. Failed to derive public key from given private key. `Utilities.privateToPublic(privateKey)` returned `nil`. " )
134
127
}
135
- guard let addr = Utilities . publicToAddress ( pubKey ) else {
136
- throw AbstractKeystoreError . keyDerivationError
128
+ guard let addr = Utilities . publicToAddress ( publicKey ) else {
129
+ throw AbstractKeystoreError . keyDerivationError ( " EthereumKeystoreV3. Failed to derive address from derived public key. `Utilities.publicToAddress(publicKey)` returned `nil`. " )
137
130
}
138
131
self . address = addr
139
132
let keystoreparams = KeystoreParamsV3 ( address: addr. address. lowercased ( ) , crypto: crypto, id: UUID ( ) . uuidString. lowercased ( ) , version: 3 )
140
133
self . keystoreParams = keystoreparams
141
134
}
142
135
143
136
public func regenerate( oldPassword: String , newPassword: String , dkLen: Int = 32 , N: Int = 4096 , R: Int = 6 , P: Int = 1 ) throws {
144
- var keyData = try self . getKeyData ( oldPassword)
145
- if keyData == nil {
146
- throw AbstractKeystoreError . encryptionError ( " Failed to decrypt a keystore " )
137
+ guard var privateKey = try getKeyData ( oldPassword) else {
138
+ throw AbstractKeystoreError . encryptionError ( " EthereumKeystoreV3. Failed to decrypt a keystore " )
147
139
}
148
140
defer {
149
- Data . zero ( & keyData! )
141
+ Data . zero ( & privateKey )
150
142
}
151
- try self . encryptDataToStorage ( newPassword, keyData : keyData! , aesMode: self . keystoreParams!. crypto. cipher)
143
+ try self . encryptDataToStorage ( newPassword, privateKey : privateKey , aesMode: self . keystoreParams!. crypto. cipher)
152
144
}
153
145
154
146
fileprivate func getKeyData( _ password: String ) throws -> Data ? {
0 commit comments