1 // Copyright (c) 2009-2013 The Bitcoin developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
11 #include <boost/foreach.hpp>
12 #include <openssl/aes.h>
13 #include <openssl/evp.h>
15 bool CCrypter::SetKeyFromPassphrase(const SecureString
& strKeyData
, const std::vector
<unsigned char>& chSalt
, const unsigned int nRounds
, const unsigned int nDerivationMethod
)
17 if (nRounds
< 1 || chSalt
.size() != WALLET_CRYPTO_SALT_SIZE
)
21 if (nDerivationMethod
== 0)
22 i
= EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt
[0],
23 (unsigned char *)&strKeyData
[0], strKeyData
.size(), nRounds
, chKey
, chIV
);
25 if (i
!= (int)WALLET_CRYPTO_KEY_SIZE
)
27 OPENSSL_cleanse(chKey
, sizeof(chKey
));
28 OPENSSL_cleanse(chIV
, sizeof(chIV
));
36 bool CCrypter::SetKey(const CKeyingMaterial
& chNewKey
, const std::vector
<unsigned char>& chNewIV
)
38 if (chNewKey
.size() != WALLET_CRYPTO_KEY_SIZE
|| chNewIV
.size() != WALLET_CRYPTO_KEY_SIZE
)
41 memcpy(&chKey
[0], &chNewKey
[0], sizeof chKey
);
42 memcpy(&chIV
[0], &chNewIV
[0], sizeof chIV
);
48 bool CCrypter::Encrypt(const CKeyingMaterial
& vchPlaintext
, std::vector
<unsigned char> &vchCiphertext
)
53 // max ciphertext len for a n bytes of plaintext is
54 // n + AES_BLOCK_SIZE - 1 bytes
55 int nLen
= vchPlaintext
.size();
56 int nCLen
= nLen
+ AES_BLOCK_SIZE
, nFLen
= 0;
57 vchCiphertext
= std::vector
<unsigned char> (nCLen
);
63 EVP_CIPHER_CTX_init(&ctx
);
64 if (fOk
) fOk
= EVP_EncryptInit_ex(&ctx
, EVP_aes_256_cbc(), NULL
, chKey
, chIV
);
65 if (fOk
) fOk
= EVP_EncryptUpdate(&ctx
, &vchCiphertext
[0], &nCLen
, &vchPlaintext
[0], nLen
);
66 if (fOk
) fOk
= EVP_EncryptFinal_ex(&ctx
, (&vchCiphertext
[0])+nCLen
, &nFLen
);
67 EVP_CIPHER_CTX_cleanup(&ctx
);
69 if (!fOk
) return false;
71 vchCiphertext
.resize(nCLen
+ nFLen
);
75 bool CCrypter::Decrypt(const std::vector
<unsigned char>& vchCiphertext
, CKeyingMaterial
& vchPlaintext
)
80 // plaintext will always be equal to or lesser than length of ciphertext
81 int nLen
= vchCiphertext
.size();
82 int nPLen
= nLen
, nFLen
= 0;
84 vchPlaintext
= CKeyingMaterial(nPLen
);
90 EVP_CIPHER_CTX_init(&ctx
);
91 if (fOk
) fOk
= EVP_DecryptInit_ex(&ctx
, EVP_aes_256_cbc(), NULL
, chKey
, chIV
);
92 if (fOk
) fOk
= EVP_DecryptUpdate(&ctx
, &vchPlaintext
[0], &nPLen
, &vchCiphertext
[0], nLen
);
93 if (fOk
) fOk
= EVP_DecryptFinal_ex(&ctx
, (&vchPlaintext
[0])+nPLen
, &nFLen
);
94 EVP_CIPHER_CTX_cleanup(&ctx
);
96 if (!fOk
) return false;
98 vchPlaintext
.resize(nPLen
+ nFLen
);
103 bool EncryptSecret(const CKeyingMaterial
& vMasterKey
, const CKeyingMaterial
&vchPlaintext
, const uint256
& nIV
, std::vector
<unsigned char> &vchCiphertext
)
105 CCrypter cKeyCrypter
;
106 std::vector
<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE
);
107 memcpy(&chIV
[0], &nIV
, WALLET_CRYPTO_KEY_SIZE
);
108 if(!cKeyCrypter
.SetKey(vMasterKey
, chIV
))
110 return cKeyCrypter
.Encrypt(*((const CKeyingMaterial
*)&vchPlaintext
), vchCiphertext
);
113 bool DecryptSecret(const CKeyingMaterial
& vMasterKey
, const std::vector
<unsigned char>& vchCiphertext
, const uint256
& nIV
, CKeyingMaterial
& vchPlaintext
)
115 CCrypter cKeyCrypter
;
116 std::vector
<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE
);
117 memcpy(&chIV
[0], &nIV
, WALLET_CRYPTO_KEY_SIZE
);
118 if(!cKeyCrypter
.SetKey(vMasterKey
, chIV
))
120 return cKeyCrypter
.Decrypt(vchCiphertext
, *((CKeyingMaterial
*)&vchPlaintext
));
123 bool CCryptoKeyStore::SetCrypted()
128 if (!mapKeys
.empty())
134 bool CCryptoKeyStore::Lock()
144 NotifyStatusChanged(this);
148 bool CCryptoKeyStore::Unlock(const CKeyingMaterial
& vMasterKeyIn
)
155 bool keyPass
= false;
156 bool keyFail
= false;
157 CryptedKeyMap::const_iterator mi
= mapCryptedKeys
.begin();
158 for (; mi
!= mapCryptedKeys
.end(); ++mi
)
160 const CPubKey
&vchPubKey
= (*mi
).second
.first
;
161 const std::vector
<unsigned char> &vchCryptedSecret
= (*mi
).second
.second
;
162 CKeyingMaterial vchSecret
;
163 if(!DecryptSecret(vMasterKeyIn
, vchCryptedSecret
, vchPubKey
.GetHash(), vchSecret
))
168 if (vchSecret
.size() != 32)
174 key
.Set(vchSecret
.begin(), vchSecret
.end(), vchPubKey
.IsCompressed());
175 if (key
.GetPubKey() != vchPubKey
)
181 if (fDecryptionThoroughlyChecked
)
184 if (keyPass
&& keyFail
)
186 LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.");
189 if (keyFail
|| !keyPass
)
191 vMasterKey
= vMasterKeyIn
;
192 fDecryptionThoroughlyChecked
= true;
194 NotifyStatusChanged(this);
198 bool CCryptoKeyStore::AddKeyPubKey(const CKey
& key
, const CPubKey
&pubkey
)
203 return CBasicKeyStore::AddKeyPubKey(key
, pubkey
);
208 std::vector
<unsigned char> vchCryptedSecret
;
209 CKeyingMaterial
vchSecret(key
.begin(), key
.end());
210 if (!EncryptSecret(vMasterKey
, vchSecret
, pubkey
.GetHash(), vchCryptedSecret
))
213 if (!AddCryptedKey(pubkey
, vchCryptedSecret
))
220 bool CCryptoKeyStore::AddCryptedKey(const CPubKey
&vchPubKey
, const std::vector
<unsigned char> &vchCryptedSecret
)
227 mapCryptedKeys
[vchPubKey
.GetID()] = make_pair(vchPubKey
, vchCryptedSecret
);
232 bool CCryptoKeyStore::GetKey(const CKeyID
&address
, CKey
& keyOut
) const
237 return CBasicKeyStore::GetKey(address
, keyOut
);
239 CryptedKeyMap::const_iterator mi
= mapCryptedKeys
.find(address
);
240 if (mi
!= mapCryptedKeys
.end())
242 const CPubKey
&vchPubKey
= (*mi
).second
.first
;
243 const std::vector
<unsigned char> &vchCryptedSecret
= (*mi
).second
.second
;
244 CKeyingMaterial vchSecret
;
245 if (!DecryptSecret(vMasterKey
, vchCryptedSecret
, vchPubKey
.GetHash(), vchSecret
))
247 if (vchSecret
.size() != 32)
249 keyOut
.Set(vchSecret
.begin(), vchSecret
.end(), vchPubKey
.IsCompressed());
256 bool CCryptoKeyStore::GetPubKey(const CKeyID
&address
, CPubKey
& vchPubKeyOut
) const
261 return CKeyStore::GetPubKey(address
, vchPubKeyOut
);
263 CryptedKeyMap::const_iterator mi
= mapCryptedKeys
.find(address
);
264 if (mi
!= mapCryptedKeys
.end())
266 vchPubKeyOut
= (*mi
).second
.first
;
273 bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial
& vMasterKeyIn
)
277 if (!mapCryptedKeys
.empty() || IsCrypted())
281 BOOST_FOREACH(KeyMap::value_type
& mKey
, mapKeys
)
283 const CKey
&key
= mKey
.second
;
284 CPubKey vchPubKey
= key
.GetPubKey();
285 CKeyingMaterial
vchSecret(key
.begin(), key
.end());
286 std::vector
<unsigned char> vchCryptedSecret
;
287 if (!EncryptSecret(vMasterKeyIn
, vchSecret
, vchPubKey
.GetHash(), vchCryptedSecret
))
289 if (!AddCryptedKey(vchPubKey
, vchCryptedSecret
))