Use the variable name _ for unused return values
[bitcoinplatinum.git] / src / wallet / crypter.cpp
blobdcce88cedc7e1b628c21ef48de10323ed9d45945
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.
5 #include "crypter.h"
7 #include "crypto/aes.h"
8 #include "crypto/sha512.h"
9 #include "script/script.h"
10 #include "script/standard.h"
11 #include "util.h"
13 #include <string>
14 #include <vector>
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)
24 return 0;
26 unsigned char buf[CSHA512::OUTPUT_SIZE];
27 CSHA512 di;
29 di.Write((const unsigned char*)strKeyData.c_str(), strKeyData.size());
30 if(chSalt.size())
31 di.Write(&chSalt[0], chSalt.size());
32 di.Finalize(buf);
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)
46 return false;
48 int i = 0;
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());
56 return false;
59 fKeySet = true;
60 return true;
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)
66 return false;
68 memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
69 memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());
71 fKeySet = true;
72 return true;
75 bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const
77 if (!fKeySet)
78 return false;
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())
87 return false;
88 vchCiphertext.resize(nLen);
90 return true;
93 bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
95 if (!fKeySet)
96 return false;
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]);
105 if(nLen == 0)
106 return false;
107 vchPlaintext.resize(nLen);
108 return true;
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))
118 return false;
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))
128 return false;
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))
136 return false;
138 if (vchSecret.size() != 32)
139 return false;
141 key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
142 return key.VerifyPubKey(vchPubKey);
145 bool CCryptoKeyStore::SetCrypted()
147 LOCK(cs_KeyStore);
148 if (fUseCrypto)
149 return true;
150 if (!mapKeys.empty())
151 return false;
152 fUseCrypto = true;
153 return true;
156 bool CCryptoKeyStore::Lock()
158 if (!SetCrypted())
159 return false;
162 LOCK(cs_KeyStore);
163 vMasterKey.clear();
166 NotifyStatusChanged(this);
167 return true;
170 bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
173 LOCK(cs_KeyStore);
174 if (!SetCrypted())
175 return false;
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;
184 CKey key;
185 if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
187 keyFail = true;
188 break;
190 keyPass = true;
191 if (fDecryptionThoroughlyChecked)
192 break;
194 if (keyPass && keyFail)
196 LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
197 assert(false);
199 if (keyFail || !keyPass)
200 return false;
201 vMasterKey = vMasterKeyIn;
202 fDecryptionThoroughlyChecked = true;
204 NotifyStatusChanged(this);
205 return true;
208 bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
211 LOCK(cs_KeyStore);
212 if (!IsCrypted())
213 return CBasicKeyStore::AddKeyPubKey(key, pubkey);
215 if (IsLocked())
216 return false;
218 std::vector<unsigned char> vchCryptedSecret;
219 CKeyingMaterial vchSecret(key.begin(), key.end());
220 if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
221 return false;
223 if (!AddCryptedKey(pubkey, vchCryptedSecret))
224 return false;
226 return true;
230 bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
233 LOCK(cs_KeyStore);
234 if (!SetCrypted())
235 return false;
237 mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
239 return true;
242 bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
245 LOCK(cs_KeyStore);
246 if (!IsCrypted())
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);
257 return false;
260 bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
263 LOCK(cs_KeyStore);
264 if (!IsCrypted())
265 return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
267 CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
268 if (mi != mapCryptedKeys.end())
270 vchPubKeyOut = (*mi).second.first;
271 return true;
273 // Check for watch-only pubkeys
274 return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
278 bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
281 LOCK(cs_KeyStore);
282 if (!mapCryptedKeys.empty() || IsCrypted())
283 return false;
285 fUseCrypto = true;
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))
293 return false;
294 if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
295 return false;
297 mapKeys.clear();
299 return true;