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