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