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());
31 di
.Write(&chSalt
[0], chSalt
.size());
34 for(int i
= 0; i
!= count
- 1; i
++)
35 di
.Reset().Write(buf
, sizeof(buf
)).Finalize(buf
);
37 memcpy(key
, buf
, WALLET_CRYPTO_KEY_SIZE
);
38 memcpy(iv
, buf
+ WALLET_CRYPTO_KEY_SIZE
, WALLET_CRYPTO_IV_SIZE
);
39 memory_cleanse(buf
, sizeof(buf
));
40 return WALLET_CRYPTO_KEY_SIZE
;
43 bool CCrypter::SetKeyFromPassphrase(const SecureString
& strKeyData
, const std::vector
<unsigned char>& chSalt
, const unsigned int nRounds
, const unsigned int nDerivationMethod
)
45 if (nRounds
< 1 || chSalt
.size() != WALLET_CRYPTO_SALT_SIZE
)
49 if (nDerivationMethod
== 0)
50 i
= BytesToKeySHA512AES(chSalt
, strKeyData
, nRounds
, vchKey
.data(), vchIV
.data());
52 if (i
!= (int)WALLET_CRYPTO_KEY_SIZE
)
54 memory_cleanse(vchKey
.data(), vchKey
.size());
55 memory_cleanse(vchIV
.data(), vchIV
.size());
63 bool CCrypter::SetKey(const CKeyingMaterial
& chNewKey
, const std::vector
<unsigned char>& chNewIV
)
65 if (chNewKey
.size() != WALLET_CRYPTO_KEY_SIZE
|| chNewIV
.size() != WALLET_CRYPTO_IV_SIZE
)
68 memcpy(vchKey
.data(), chNewKey
.data(), chNewKey
.size());
69 memcpy(vchIV
.data(), chNewIV
.data(), chNewIV
.size());
75 bool CCrypter::Encrypt(const CKeyingMaterial
& vchPlaintext
, std::vector
<unsigned char> &vchCiphertext
) const
80 // max ciphertext len for a n bytes of plaintext is
81 // n + AES_BLOCKSIZE bytes
82 vchCiphertext
.resize(vchPlaintext
.size() + AES_BLOCKSIZE
);
84 AES256CBCEncrypt
enc(vchKey
.data(), vchIV
.data(), true);
85 size_t nLen
= enc
.Encrypt(&vchPlaintext
[0], vchPlaintext
.size(), &vchCiphertext
[0]);
86 if(nLen
< vchPlaintext
.size())
88 vchCiphertext
.resize(nLen
);
93 bool CCrypter::Decrypt(const std::vector
<unsigned char>& vchCiphertext
, CKeyingMaterial
& vchPlaintext
) const
98 // plaintext will always be equal to or lesser than length of ciphertext
99 int nLen
= vchCiphertext
.size();
101 vchPlaintext
.resize(nLen
);
103 AES256CBCDecrypt
dec(vchKey
.data(), vchIV
.data(), true);
104 nLen
= dec
.Decrypt(&vchCiphertext
[0], vchCiphertext
.size(), &vchPlaintext
[0]);
107 vchPlaintext
.resize(nLen
);
112 static bool EncryptSecret(const CKeyingMaterial
& vMasterKey
, const CKeyingMaterial
&vchPlaintext
, const uint256
& nIV
, std::vector
<unsigned char> &vchCiphertext
)
114 CCrypter cKeyCrypter
;
115 std::vector
<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE
);
116 memcpy(&chIV
[0], &nIV
, WALLET_CRYPTO_IV_SIZE
);
117 if(!cKeyCrypter
.SetKey(vMasterKey
, chIV
))
119 return cKeyCrypter
.Encrypt(*((const CKeyingMaterial
*)&vchPlaintext
), vchCiphertext
);
122 static bool DecryptSecret(const CKeyingMaterial
& vMasterKey
, const std::vector
<unsigned char>& vchCiphertext
, const uint256
& nIV
, CKeyingMaterial
& vchPlaintext
)
124 CCrypter cKeyCrypter
;
125 std::vector
<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE
);
126 memcpy(&chIV
[0], &nIV
, WALLET_CRYPTO_IV_SIZE
);
127 if(!cKeyCrypter
.SetKey(vMasterKey
, chIV
))
129 return cKeyCrypter
.Decrypt(vchCiphertext
, *((CKeyingMaterial
*)&vchPlaintext
));
132 static bool DecryptKey(const CKeyingMaterial
& vMasterKey
, const std::vector
<unsigned char>& vchCryptedSecret
, const CPubKey
& vchPubKey
, CKey
& key
)
134 CKeyingMaterial vchSecret
;
135 if(!DecryptSecret(vMasterKey
, vchCryptedSecret
, vchPubKey
.GetHash(), vchSecret
))
138 if (vchSecret
.size() != 32)
141 key
.Set(vchSecret
.begin(), vchSecret
.end(), vchPubKey
.IsCompressed());
142 return key
.VerifyPubKey(vchPubKey
);
145 bool CCryptoKeyStore::SetCrypted()
150 if (!mapKeys
.empty())
156 bool CCryptoKeyStore::Lock()
166 NotifyStatusChanged(this);
170 bool CCryptoKeyStore::Unlock(const CKeyingMaterial
& vMasterKeyIn
)
177 bool keyPass
= false;
178 bool keyFail
= false;
179 CryptedKeyMap::const_iterator mi
= mapCryptedKeys
.begin();
180 for (; mi
!= mapCryptedKeys
.end(); ++mi
)
182 const CPubKey
&vchPubKey
= (*mi
).second
.first
;
183 const std::vector
<unsigned char> &vchCryptedSecret
= (*mi
).second
.second
;
185 if (!DecryptKey(vMasterKeyIn
, vchCryptedSecret
, vchPubKey
, key
))
191 if (fDecryptionThoroughlyChecked
)
194 if (keyPass
&& keyFail
)
196 LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
199 if (keyFail
|| !keyPass
)
201 vMasterKey
= vMasterKeyIn
;
202 fDecryptionThoroughlyChecked
= true;
204 NotifyStatusChanged(this);
208 bool CCryptoKeyStore::AddKeyPubKey(const CKey
& key
, const CPubKey
&pubkey
)
213 return CBasicKeyStore::AddKeyPubKey(key
, pubkey
);
218 std::vector
<unsigned char> vchCryptedSecret
;
219 CKeyingMaterial
vchSecret(key
.begin(), key
.end());
220 if (!EncryptSecret(vMasterKey
, vchSecret
, pubkey
.GetHash(), vchCryptedSecret
))
223 if (!AddCryptedKey(pubkey
, vchCryptedSecret
))
230 bool CCryptoKeyStore::AddCryptedKey(const CPubKey
&vchPubKey
, const std::vector
<unsigned char> &vchCryptedSecret
)
237 mapCryptedKeys
[vchPubKey
.GetID()] = make_pair(vchPubKey
, vchCryptedSecret
);
242 bool CCryptoKeyStore::GetKey(const CKeyID
&address
, CKey
& keyOut
) const
247 return CBasicKeyStore::GetKey(address
, keyOut
);
249 CryptedKeyMap::const_iterator mi
= mapCryptedKeys
.find(address
);
250 if (mi
!= mapCryptedKeys
.end())
252 const CPubKey
&vchPubKey
= (*mi
).second
.first
;
253 const std::vector
<unsigned char> &vchCryptedSecret
= (*mi
).second
.second
;
254 return DecryptKey(vMasterKey
, vchCryptedSecret
, vchPubKey
, keyOut
);
260 bool CCryptoKeyStore::GetPubKey(const CKeyID
&address
, CPubKey
& vchPubKeyOut
) const
265 return CBasicKeyStore::GetPubKey(address
, vchPubKeyOut
);
267 CryptedKeyMap::const_iterator mi
= mapCryptedKeys
.find(address
);
268 if (mi
!= mapCryptedKeys
.end())
270 vchPubKeyOut
= (*mi
).second
.first
;
273 // Check for watch-only pubkeys
274 return CBasicKeyStore::GetPubKey(address
, vchPubKeyOut
);
278 bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial
& vMasterKeyIn
)
282 if (!mapCryptedKeys
.empty() || IsCrypted())
286 for (KeyMap::value_type
& mKey
: mapKeys
)
288 const CKey
&key
= mKey
.second
;
289 CPubKey vchPubKey
= key
.GetPubKey();
290 CKeyingMaterial
vchSecret(key
.begin(), key
.end());
291 std::vector
<unsigned char> vchCryptedSecret
;
292 if (!EncryptSecret(vMasterKeyIn
, vchSecret
, vchPubKey
.GetHash(), vchCryptedSecret
))
294 if (!AddCryptedKey(vchPubKey
, vchCryptedSecret
))