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"
15 #include <boost/foreach.hpp>
17 int CCrypter::BytesToKeySHA512AES(const std::vector
<unsigned char>& chSalt
, const SecureString
& strKeyData
, int count
, unsigned char *key
,unsigned char *iv
) const
19 // This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc
20 // cipher and sha512 message digest. Because sha512's output size (64b) is
21 // greater than the aes256 block size (16b) + aes256 key size (32b),
22 // there's no need to process more than once (D_0).
24 if(!count
|| !key
|| !iv
)
27 unsigned char buf
[CSHA512::OUTPUT_SIZE
];
30 di
.Write((const unsigned char*)strKeyData
.c_str(), strKeyData
.size());
32 di
.Write(&chSalt
[0], chSalt
.size());
35 for(int i
= 0; i
!= count
- 1; i
++)
36 di
.Reset().Write(buf
, sizeof(buf
)).Finalize(buf
);
38 memcpy(key
, buf
, WALLET_CRYPTO_KEY_SIZE
);
39 memcpy(iv
, buf
+ WALLET_CRYPTO_KEY_SIZE
, WALLET_CRYPTO_IV_SIZE
);
40 memory_cleanse(buf
, sizeof(buf
));
41 return WALLET_CRYPTO_KEY_SIZE
;
44 bool CCrypter::SetKeyFromPassphrase(const SecureString
& strKeyData
, const std::vector
<unsigned char>& chSalt
, const unsigned int nRounds
, const unsigned int nDerivationMethod
)
46 if (nRounds
< 1 || chSalt
.size() != WALLET_CRYPTO_SALT_SIZE
)
50 if (nDerivationMethod
== 0)
51 i
= BytesToKeySHA512AES(chSalt
, strKeyData
, nRounds
, vchKey
.data(), vchIV
.data());
53 if (i
!= (int)WALLET_CRYPTO_KEY_SIZE
)
55 memory_cleanse(vchKey
.data(), vchKey
.size());
56 memory_cleanse(vchIV
.data(), vchIV
.size());
64 bool CCrypter::SetKey(const CKeyingMaterial
& chNewKey
, const std::vector
<unsigned char>& chNewIV
)
66 if (chNewKey
.size() != WALLET_CRYPTO_KEY_SIZE
|| chNewIV
.size() != WALLET_CRYPTO_IV_SIZE
)
69 memcpy(vchKey
.data(), chNewKey
.data(), chNewKey
.size());
70 memcpy(vchIV
.data(), chNewIV
.data(), chNewIV
.size());
76 bool CCrypter::Encrypt(const CKeyingMaterial
& vchPlaintext
, std::vector
<unsigned char> &vchCiphertext
) const
81 // max ciphertext len for a n bytes of plaintext is
82 // n + AES_BLOCKSIZE bytes
83 vchCiphertext
.resize(vchPlaintext
.size() + AES_BLOCKSIZE
);
85 AES256CBCEncrypt
enc(vchKey
.data(), vchIV
.data(), true);
86 size_t nLen
= enc
.Encrypt(&vchPlaintext
[0], vchPlaintext
.size(), &vchCiphertext
[0]);
87 if(nLen
< vchPlaintext
.size())
89 vchCiphertext
.resize(nLen
);
94 bool CCrypter::Decrypt(const std::vector
<unsigned char>& vchCiphertext
, CKeyingMaterial
& vchPlaintext
) const
99 // plaintext will always be equal to or lesser than length of ciphertext
100 int nLen
= vchCiphertext
.size();
102 vchPlaintext
.resize(nLen
);
104 AES256CBCDecrypt
dec(vchKey
.data(), vchIV
.data(), true);
105 nLen
= dec
.Decrypt(&vchCiphertext
[0], vchCiphertext
.size(), &vchPlaintext
[0]);
108 vchPlaintext
.resize(nLen
);
113 static bool EncryptSecret(const CKeyingMaterial
& vMasterKey
, const CKeyingMaterial
&vchPlaintext
, const uint256
& nIV
, std::vector
<unsigned char> &vchCiphertext
)
115 CCrypter cKeyCrypter
;
116 std::vector
<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE
);
117 memcpy(&chIV
[0], &nIV
, WALLET_CRYPTO_IV_SIZE
);
118 if(!cKeyCrypter
.SetKey(vMasterKey
, chIV
))
120 return cKeyCrypter
.Encrypt(*((const CKeyingMaterial
*)&vchPlaintext
), vchCiphertext
);
123 static bool DecryptSecret(const CKeyingMaterial
& vMasterKey
, const std::vector
<unsigned char>& vchCiphertext
, const uint256
& nIV
, CKeyingMaterial
& vchPlaintext
)
125 CCrypter cKeyCrypter
;
126 std::vector
<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE
);
127 memcpy(&chIV
[0], &nIV
, WALLET_CRYPTO_IV_SIZE
);
128 if(!cKeyCrypter
.SetKey(vMasterKey
, chIV
))
130 return cKeyCrypter
.Decrypt(vchCiphertext
, *((CKeyingMaterial
*)&vchPlaintext
));
133 static bool DecryptKey(const CKeyingMaterial
& vMasterKey
, const std::vector
<unsigned char>& vchCryptedSecret
, const CPubKey
& vchPubKey
, CKey
& key
)
135 CKeyingMaterial vchSecret
;
136 if(!DecryptSecret(vMasterKey
, vchCryptedSecret
, vchPubKey
.GetHash(), vchSecret
))
139 if (vchSecret
.size() != 32)
142 key
.Set(vchSecret
.begin(), vchSecret
.end(), vchPubKey
.IsCompressed());
143 return key
.VerifyPubKey(vchPubKey
);
146 bool CCryptoKeyStore::SetCrypted()
151 if (!mapKeys
.empty())
157 bool CCryptoKeyStore::Lock()
167 NotifyStatusChanged(this);
171 bool CCryptoKeyStore::Unlock(const CKeyingMaterial
& vMasterKeyIn
)
178 bool keyPass
= false;
179 bool keyFail
= false;
180 CryptedKeyMap::const_iterator mi
= mapCryptedKeys
.begin();
181 for (; mi
!= mapCryptedKeys
.end(); ++mi
)
183 const CPubKey
&vchPubKey
= (*mi
).second
.first
;
184 const std::vector
<unsigned char> &vchCryptedSecret
= (*mi
).second
.second
;
186 if (!DecryptKey(vMasterKeyIn
, vchCryptedSecret
, vchPubKey
, key
))
192 if (fDecryptionThoroughlyChecked
)
195 if (keyPass
&& keyFail
)
197 LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
200 if (keyFail
|| !keyPass
)
202 vMasterKey
= vMasterKeyIn
;
203 fDecryptionThoroughlyChecked
= true;
205 NotifyStatusChanged(this);
209 bool CCryptoKeyStore::AddKeyPubKey(const CKey
& key
, const CPubKey
&pubkey
)
214 return CBasicKeyStore::AddKeyPubKey(key
, pubkey
);
219 std::vector
<unsigned char> vchCryptedSecret
;
220 CKeyingMaterial
vchSecret(key
.begin(), key
.end());
221 if (!EncryptSecret(vMasterKey
, vchSecret
, pubkey
.GetHash(), vchCryptedSecret
))
224 if (!AddCryptedKey(pubkey
, vchCryptedSecret
))
231 bool CCryptoKeyStore::AddCryptedKey(const CPubKey
&vchPubKey
, const std::vector
<unsigned char> &vchCryptedSecret
)
238 mapCryptedKeys
[vchPubKey
.GetID()] = make_pair(vchPubKey
, vchCryptedSecret
);
243 bool CCryptoKeyStore::GetKey(const CKeyID
&address
, CKey
& keyOut
) const
248 return CBasicKeyStore::GetKey(address
, keyOut
);
250 CryptedKeyMap::const_iterator mi
= mapCryptedKeys
.find(address
);
251 if (mi
!= mapCryptedKeys
.end())
253 const CPubKey
&vchPubKey
= (*mi
).second
.first
;
254 const std::vector
<unsigned char> &vchCryptedSecret
= (*mi
).second
.second
;
255 return DecryptKey(vMasterKey
, vchCryptedSecret
, vchPubKey
, keyOut
);
261 bool CCryptoKeyStore::GetPubKey(const CKeyID
&address
, CPubKey
& vchPubKeyOut
) const
266 return CBasicKeyStore::GetPubKey(address
, vchPubKeyOut
);
268 CryptedKeyMap::const_iterator mi
= mapCryptedKeys
.find(address
);
269 if (mi
!= mapCryptedKeys
.end())
271 vchPubKeyOut
= (*mi
).second
.first
;
274 // Check for watch-only pubkeys
275 return CBasicKeyStore::GetPubKey(address
, vchPubKeyOut
);
280 bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial
& vMasterKeyIn
)
284 if (!mapCryptedKeys
.empty() || IsCrypted())
288 BOOST_FOREACH(KeyMap::value_type
& mKey
, mapKeys
)
290 const CKey
&key
= mKey
.second
;
291 CPubKey vchPubKey
= key
.GetPubKey();
292 CKeyingMaterial
vchSecret(key
.begin(), key
.end());
293 std::vector
<unsigned char> vchCryptedSecret
;
294 if (!EncryptSecret(vMasterKeyIn
, vchSecret
, vchPubKey
.GetHash(), vchCryptedSecret
))
296 if (!AddCryptedKey(vchPubKey
, vchCryptedSecret
))