Fix travis failing to fetch keys from the sks keyserver pool
[bitcoinplatinum.git] / src / wallet / crypter.cpp
blobfc318c161250d797212c8fdd9992752d0ca9f5df
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>
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)
25 return 0;
27 unsigned char buf[CSHA512::OUTPUT_SIZE];
28 CSHA512 di;
30 di.Write((const unsigned char*)strKeyData.c_str(), strKeyData.size());
31 if(chSalt.size())
32 di.Write(&chSalt[0], chSalt.size());
33 di.Finalize(buf);
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)
47 return false;
49 int i = 0;
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());
57 return false;
60 fKeySet = true;
61 return true;
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)
67 return false;
69 memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
70 memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());
72 fKeySet = true;
73 return true;
76 bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const
78 if (!fKeySet)
79 return false;
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())
88 return false;
89 vchCiphertext.resize(nLen);
91 return true;
94 bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
96 if (!fKeySet)
97 return false;
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]);
106 if(nLen == 0)
107 return false;
108 vchPlaintext.resize(nLen);
109 return true;
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))
119 return false;
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))
129 return false;
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))
137 return false;
139 if (vchSecret.size() != 32)
140 return false;
142 key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
143 return key.VerifyPubKey(vchPubKey);
146 bool CCryptoKeyStore::SetCrypted()
148 LOCK(cs_KeyStore);
149 if (fUseCrypto)
150 return true;
151 if (!mapKeys.empty())
152 return false;
153 fUseCrypto = true;
154 return true;
157 bool CCryptoKeyStore::Lock()
159 if (!SetCrypted())
160 return false;
163 LOCK(cs_KeyStore);
164 vMasterKey.clear();
167 NotifyStatusChanged(this);
168 return true;
171 bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
174 LOCK(cs_KeyStore);
175 if (!SetCrypted())
176 return false;
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;
185 CKey key;
186 if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
188 keyFail = true;
189 break;
191 keyPass = true;
192 if (fDecryptionThoroughlyChecked)
193 break;
195 if (keyPass && keyFail)
197 LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
198 assert(false);
200 if (keyFail || !keyPass)
201 return false;
202 vMasterKey = vMasterKeyIn;
203 fDecryptionThoroughlyChecked = true;
205 NotifyStatusChanged(this);
206 return true;
209 bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
212 LOCK(cs_KeyStore);
213 if (!IsCrypted())
214 return CBasicKeyStore::AddKeyPubKey(key, pubkey);
216 if (IsLocked())
217 return false;
219 std::vector<unsigned char> vchCryptedSecret;
220 CKeyingMaterial vchSecret(key.begin(), key.end());
221 if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
222 return false;
224 if (!AddCryptedKey(pubkey, vchCryptedSecret))
225 return false;
227 return true;
231 bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
234 LOCK(cs_KeyStore);
235 if (!SetCrypted())
236 return false;
238 mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
240 return true;
243 bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
246 LOCK(cs_KeyStore);
247 if (!IsCrypted())
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);
258 return false;
261 bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
264 LOCK(cs_KeyStore);
265 if (!IsCrypted())
266 return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
268 CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
269 if (mi != mapCryptedKeys.end())
271 vchPubKeyOut = (*mi).second.first;
272 return true;
274 // Check for watch-only pubkeys
275 return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
277 return false;
280 bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
283 LOCK(cs_KeyStore);
284 if (!mapCryptedKeys.empty() || IsCrypted())
285 return false;
287 fUseCrypto = true;
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))
295 return false;
296 if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
297 return false;
299 mapKeys.clear();
301 return true;