1 // Copyright (c) 2009-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
7 #include "crypto/aes.h"
8 #include "crypto/sha512.h"
9 #include "script/script.h"
10 #include "script/standard.h"
16 int CCrypter::BytesToKeySHA512AES(const std::vector
<unsigned char>& chSalt
, const SecureString
& strKeyData
, int count
, unsigned char *key
,unsigned char *iv
) const
18 // This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc
19 // cipher and sha512 message digest. Because sha512's output size (64b) is
20 // greater than the aes256 block size (16b) + aes256 key size (32b),
21 // there's no need to process more than once (D_0).
23 if(!count
|| !key
|| !iv
)
26 unsigned char buf
[CSHA512::OUTPUT_SIZE
];
29 di
.Write((const unsigned char*)strKeyData
.c_str(), strKeyData
.size());
30 di
.Write(chSalt
.data(), chSalt
.size());
33 for(int i
= 0; i
!= count
- 1; i
++)
34 di
.Reset().Write(buf
, sizeof(buf
)).Finalize(buf
);
36 memcpy(key
, buf
, WALLET_CRYPTO_KEY_SIZE
);
37 memcpy(iv
, buf
+ WALLET_CRYPTO_KEY_SIZE
, WALLET_CRYPTO_IV_SIZE
);
38 memory_cleanse(buf
, sizeof(buf
));
39 return WALLET_CRYPTO_KEY_SIZE
;
42 bool CCrypter::SetKeyFromPassphrase(const SecureString
& strKeyData
, const std::vector
<unsigned char>& chSalt
, const unsigned int nRounds
, const unsigned int nDerivationMethod
)
44 if (nRounds
< 1 || chSalt
.size() != WALLET_CRYPTO_SALT_SIZE
)
48 if (nDerivationMethod
== 0)
49 i
= BytesToKeySHA512AES(chSalt
, strKeyData
, nRounds
, vchKey
.data(), vchIV
.data());
51 if (i
!= (int)WALLET_CRYPTO_KEY_SIZE
)
53 memory_cleanse(vchKey
.data(), vchKey
.size());
54 memory_cleanse(vchIV
.data(), vchIV
.size());
62 bool CCrypter::SetKey(const CKeyingMaterial
& chNewKey
, const std::vector
<unsigned char>& chNewIV
)
64 if (chNewKey
.size() != WALLET_CRYPTO_KEY_SIZE
|| chNewIV
.size() != WALLET_CRYPTO_IV_SIZE
)
67 memcpy(vchKey
.data(), chNewKey
.data(), chNewKey
.size());
68 memcpy(vchIV
.data(), chNewIV
.data(), chNewIV
.size());
74 bool CCrypter::Encrypt(const CKeyingMaterial
& vchPlaintext
, std::vector
<unsigned char> &vchCiphertext
) const
79 // max ciphertext len for a n bytes of plaintext is
80 // n + AES_BLOCKSIZE bytes
81 vchCiphertext
.resize(vchPlaintext
.size() + AES_BLOCKSIZE
);
83 AES256CBCEncrypt
enc(vchKey
.data(), vchIV
.data(), true);
84 size_t nLen
= enc
.Encrypt(&vchPlaintext
[0], vchPlaintext
.size(), vchCiphertext
.data());
85 if(nLen
< vchPlaintext
.size())
87 vchCiphertext
.resize(nLen
);
92 bool CCrypter::Decrypt(const std::vector
<unsigned char>& vchCiphertext
, CKeyingMaterial
& vchPlaintext
) const
97 // plaintext will always be equal to or lesser than length of ciphertext
98 int nLen
= vchCiphertext
.size();
100 vchPlaintext
.resize(nLen
);
102 AES256CBCDecrypt
dec(vchKey
.data(), vchIV
.data(), true);
103 nLen
= dec
.Decrypt(vchCiphertext
.data(), vchCiphertext
.size(), &vchPlaintext
[0]);
106 vchPlaintext
.resize(nLen
);
111 static bool EncryptSecret(const CKeyingMaterial
& vMasterKey
, const CKeyingMaterial
&vchPlaintext
, const uint256
& nIV
, std::vector
<unsigned char> &vchCiphertext
)
113 CCrypter cKeyCrypter
;
114 std::vector
<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE
);
115 memcpy(chIV
.data(), &nIV
, WALLET_CRYPTO_IV_SIZE
);
116 if(!cKeyCrypter
.SetKey(vMasterKey
, chIV
))
118 return cKeyCrypter
.Encrypt(*((const CKeyingMaterial
*)&vchPlaintext
), vchCiphertext
);
121 static bool DecryptSecret(const CKeyingMaterial
& vMasterKey
, const std::vector
<unsigned char>& vchCiphertext
, const uint256
& nIV
, CKeyingMaterial
& vchPlaintext
)
123 CCrypter cKeyCrypter
;
124 std::vector
<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE
);
125 memcpy(chIV
.data(), &nIV
, WALLET_CRYPTO_IV_SIZE
);
126 if(!cKeyCrypter
.SetKey(vMasterKey
, chIV
))
128 return cKeyCrypter
.Decrypt(vchCiphertext
, *((CKeyingMaterial
*)&vchPlaintext
));
131 static bool DecryptKey(const CKeyingMaterial
& vMasterKey
, const std::vector
<unsigned char>& vchCryptedSecret
, const CPubKey
& vchPubKey
, CKey
& key
)
133 CKeyingMaterial vchSecret
;
134 if(!DecryptSecret(vMasterKey
, vchCryptedSecret
, vchPubKey
.GetHash(), vchSecret
))
137 if (vchSecret
.size() != 32)
140 key
.Set(vchSecret
.begin(), vchSecret
.end(), vchPubKey
.IsCompressed());
141 return key
.VerifyPubKey(vchPubKey
);
144 bool CCryptoKeyStore::SetCrypted()
149 if (!mapKeys
.empty())
155 bool CCryptoKeyStore::Lock()
165 NotifyStatusChanged(this);
169 bool CCryptoKeyStore::Unlock(const CKeyingMaterial
& vMasterKeyIn
)
176 bool keyPass
= false;
177 bool keyFail
= false;
178 CryptedKeyMap::const_iterator mi
= mapCryptedKeys
.begin();
179 for (; mi
!= mapCryptedKeys
.end(); ++mi
)
181 const CPubKey
&vchPubKey
= (*mi
).second
.first
;
182 const std::vector
<unsigned char> &vchCryptedSecret
= (*mi
).second
.second
;
184 if (!DecryptKey(vMasterKeyIn
, vchCryptedSecret
, vchPubKey
, key
))
190 if (fDecryptionThoroughlyChecked
)
193 if (keyPass
&& keyFail
)
195 LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
198 if (keyFail
|| !keyPass
)
200 vMasterKey
= vMasterKeyIn
;
201 fDecryptionThoroughlyChecked
= true;
203 NotifyStatusChanged(this);
207 bool CCryptoKeyStore::AddKeyPubKey(const CKey
& key
, const CPubKey
&pubkey
)
212 return CBasicKeyStore::AddKeyPubKey(key
, pubkey
);
217 std::vector
<unsigned char> vchCryptedSecret
;
218 CKeyingMaterial
vchSecret(key
.begin(), key
.end());
219 if (!EncryptSecret(vMasterKey
, vchSecret
, pubkey
.GetHash(), vchCryptedSecret
))
222 if (!AddCryptedKey(pubkey
, vchCryptedSecret
))
229 bool CCryptoKeyStore::AddCryptedKey(const CPubKey
&vchPubKey
, const std::vector
<unsigned char> &vchCryptedSecret
)
236 mapCryptedKeys
[vchPubKey
.GetID()] = make_pair(vchPubKey
, vchCryptedSecret
);
241 bool CCryptoKeyStore::GetKey(const CKeyID
&address
, CKey
& keyOut
) const
246 return CBasicKeyStore::GetKey(address
, keyOut
);
248 CryptedKeyMap::const_iterator mi
= mapCryptedKeys
.find(address
);
249 if (mi
!= mapCryptedKeys
.end())
251 const CPubKey
&vchPubKey
= (*mi
).second
.first
;
252 const std::vector
<unsigned char> &vchCryptedSecret
= (*mi
).second
.second
;
253 return DecryptKey(vMasterKey
, vchCryptedSecret
, vchPubKey
, keyOut
);
259 bool CCryptoKeyStore::GetPubKey(const CKeyID
&address
, CPubKey
& vchPubKeyOut
) const
264 return CBasicKeyStore::GetPubKey(address
, vchPubKeyOut
);
266 CryptedKeyMap::const_iterator mi
= mapCryptedKeys
.find(address
);
267 if (mi
!= mapCryptedKeys
.end())
269 vchPubKeyOut
= (*mi
).second
.first
;
272 // Check for watch-only pubkeys
273 return CBasicKeyStore::GetPubKey(address
, vchPubKeyOut
);
277 bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial
& vMasterKeyIn
)
281 if (!mapCryptedKeys
.empty() || IsCrypted())
285 for (KeyMap::value_type
& mKey
: mapKeys
)
287 const CKey
&key
= mKey
.second
;
288 CPubKey vchPubKey
= key
.GetPubKey();
289 CKeyingMaterial
vchSecret(key
.begin(), key
.end());
290 std::vector
<unsigned char> vchCryptedSecret
;
291 if (!EncryptSecret(vMasterKeyIn
, vchSecret
, vchPubKey
.GetHash(), vchCryptedSecret
))
293 if (!AddCryptedKey(vchPubKey
, vchCryptedSecret
))