]> Git Repo - VerusCoin.git/blob - src/crypter.cpp
Merge pull request #5360
[VerusCoin.git] / src / crypter.cpp
1 // Copyright (c) 2009-2013 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.
4
5 #include "crypter.h"
6
7 #include "script/script.h"
8 #include "script/standard.h"
9 #include "util.h"
10
11 #include <string>
12 #include <vector>
13 #include <boost/foreach.hpp>
14 #include <openssl/aes.h>
15 #include <openssl/evp.h>
16
17 bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
18 {
19     if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
20         return false;
21
22     int i = 0;
23     if (nDerivationMethod == 0)
24         i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
25                           (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
26
27     if (i != (int)WALLET_CRYPTO_KEY_SIZE)
28     {
29         memory_cleanse(chKey, sizeof(chKey));
30         memory_cleanse(chIV, sizeof(chIV));
31         return false;
32     }
33
34     fKeySet = true;
35     return true;
36 }
37
38 bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
39 {
40     if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
41         return false;
42
43     memcpy(&chKey[0], &chNewKey[0], sizeof chKey);
44     memcpy(&chIV[0], &chNewIV[0], sizeof chIV);
45
46     fKeySet = true;
47     return true;
48 }
49
50 bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext)
51 {
52     if (!fKeySet)
53         return false;
54
55     // max ciphertext len for a n bytes of plaintext is
56     // n + AES_BLOCK_SIZE - 1 bytes
57     int nLen = vchPlaintext.size();
58     int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
59     vchCiphertext = std::vector<unsigned char> (nCLen);
60
61     EVP_CIPHER_CTX ctx;
62
63     bool fOk = true;
64
65     EVP_CIPHER_CTX_init(&ctx);
66     if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
67     if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
68     if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
69     EVP_CIPHER_CTX_cleanup(&ctx);
70
71     if (!fOk) return false;
72
73     vchCiphertext.resize(nCLen + nFLen);
74     return true;
75 }
76
77 bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext)
78 {
79     if (!fKeySet)
80         return false;
81
82     // plaintext will always be equal to or lesser than length of ciphertext
83     int nLen = vchCiphertext.size();
84     int nPLen = nLen, nFLen = 0;
85
86     vchPlaintext = CKeyingMaterial(nPLen);
87
88     EVP_CIPHER_CTX ctx;
89
90     bool fOk = true;
91
92     EVP_CIPHER_CTX_init(&ctx);
93     if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
94     if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
95     if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
96     EVP_CIPHER_CTX_cleanup(&ctx);
97
98     if (!fOk) return false;
99
100     vchPlaintext.resize(nPLen + nFLen);
101     return true;
102 }
103
104
105 static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
106 {
107     CCrypter cKeyCrypter;
108     std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
109     memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
110     if(!cKeyCrypter.SetKey(vMasterKey, chIV))
111         return false;
112     return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
113 }
114
115 static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
116 {
117     CCrypter cKeyCrypter;
118     std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
119     memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
120     if(!cKeyCrypter.SetKey(vMasterKey, chIV))
121         return false;
122     return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
123 }
124
125 static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
126 {
127     CKeyingMaterial vchSecret;
128     if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
129         return false;
130
131     if (vchSecret.size() != 32)
132         return false;
133
134     key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
135     return key.VerifyPubKey(vchPubKey);
136 }
137
138 bool CCryptoKeyStore::SetCrypted()
139 {
140     LOCK(cs_KeyStore);
141     if (fUseCrypto)
142         return true;
143     if (!mapKeys.empty())
144         return false;
145     fUseCrypto = true;
146     return true;
147 }
148
149 bool CCryptoKeyStore::Lock()
150 {
151     if (!SetCrypted())
152         return false;
153
154     {
155         LOCK(cs_KeyStore);
156         vMasterKey.clear();
157     }
158
159     NotifyStatusChanged(this);
160     return true;
161 }
162
163 bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
164 {
165     {
166         LOCK(cs_KeyStore);
167         if (!SetCrypted())
168             return false;
169
170         bool keyPass = false;
171         bool keyFail = false;
172         CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
173         for (; mi != mapCryptedKeys.end(); ++mi)
174         {
175             const CPubKey &vchPubKey = (*mi).second.first;
176             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
177             CKey key;
178             if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
179             {
180                 keyFail = true;
181                 break;
182             }
183             keyPass = true;
184             if (fDecryptionThoroughlyChecked)
185                 break;
186         }
187         if (keyPass && keyFail)
188         {
189             LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.");
190             assert(false);
191         }
192         if (keyFail || !keyPass)
193             return false;
194         vMasterKey = vMasterKeyIn;
195         fDecryptionThoroughlyChecked = true;
196     }
197     NotifyStatusChanged(this);
198     return true;
199 }
200
201 bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
202 {
203     {
204         LOCK(cs_KeyStore);
205         if (!IsCrypted())
206             return CBasicKeyStore::AddKeyPubKey(key, pubkey);
207
208         if (IsLocked())
209             return false;
210
211         std::vector<unsigned char> vchCryptedSecret;
212         CKeyingMaterial vchSecret(key.begin(), key.end());
213         if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
214             return false;
215
216         if (!AddCryptedKey(pubkey, vchCryptedSecret))
217             return false;
218     }
219     return true;
220 }
221
222
223 bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
224 {
225     {
226         LOCK(cs_KeyStore);
227         if (!SetCrypted())
228             return false;
229
230         mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
231     }
232     return true;
233 }
234
235 bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
236 {
237     {
238         LOCK(cs_KeyStore);
239         if (!IsCrypted())
240             return CBasicKeyStore::GetKey(address, keyOut);
241
242         CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
243         if (mi != mapCryptedKeys.end())
244         {
245             const CPubKey &vchPubKey = (*mi).second.first;
246             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
247             return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
248         }
249     }
250     return false;
251 }
252
253 bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
254 {
255     {
256         LOCK(cs_KeyStore);
257         if (!IsCrypted())
258             return CKeyStore::GetPubKey(address, vchPubKeyOut);
259
260         CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
261         if (mi != mapCryptedKeys.end())
262         {
263             vchPubKeyOut = (*mi).second.first;
264             return true;
265         }
266     }
267     return false;
268 }
269
270 bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
271 {
272     {
273         LOCK(cs_KeyStore);
274         if (!mapCryptedKeys.empty() || IsCrypted())
275             return false;
276
277         fUseCrypto = true;
278         BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
279         {
280             const CKey &key = mKey.second;
281             CPubKey vchPubKey = key.GetPubKey();
282             CKeyingMaterial vchSecret(key.begin(), key.end());
283             std::vector<unsigned char> vchCryptedSecret;
284             if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
285                 return false;
286             if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
287                 return false;
288         }
289         mapKeys.clear();
290     }
291     return true;
292 }
This page took 0.064432 seconds and 4 git commands to generate.