Fabcoin Core  0.16.2
P2P Digital Currency
crypter.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2017 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 <wallet/crypter.h>
6 
7 #include <crypto/aes.h>
8 #include <crypto/sha512.h>
9 #include <script/script.h>
10 #include <script/standard.h>
11 #include <util.h>
12 
13 #include <string>
14 #include <vector>
15 
16 int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const
17 {
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).
22 
23  if(!count || !key || !iv)
24  return 0;
25 
26  unsigned char buf[CSHA512::OUTPUT_SIZE];
27  CSHA512 di;
28 
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);
33 
34  for(int i = 0; i != count - 1; i++)
35  di.Reset().Write(buf, sizeof(buf)).Finalize(buf);
36 
37  memcpy(key, buf, WALLET_CRYPTO_KEY_SIZE);
39  memory_cleanse(buf, sizeof(buf));
41 }
42 
43 bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
44 {
45  if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
46  return false;
47 
48  int i = 0;
49  if (nDerivationMethod == 0)
50  i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data());
51 
52  if (i != (int)WALLET_CRYPTO_KEY_SIZE)
53  {
54  memory_cleanse(vchKey.data(), vchKey.size());
55  memory_cleanse(vchIV.data(), vchIV.size());
56  return false;
57  }
58 
59  fKeySet = true;
60  return true;
61 }
62 
63 bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
64 {
65  if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_IV_SIZE)
66  return false;
67 
68  memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
69  memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());
70 
71  fKeySet = true;
72  return true;
73 }
74 
75 bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const
76 {
77  if (!fKeySet)
78  return false;
79 
80  // max ciphertext len for a n bytes of plaintext is
81  // n + AES_BLOCKSIZE bytes
82  vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
83 
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);
89 
90  return true;
91 }
92 
93 bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
94 {
95  if (!fKeySet)
96  return false;
97 
98  // plaintext will always be equal to or lesser than length of ciphertext
99  int nLen = vchCiphertext.size();
100 
101  vchPlaintext.resize(nLen);
102 
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;
109 }
110 
111 
112 static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
113 {
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);
120 }
121 
122 static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
123 {
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));
130 }
131 
132 static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
133 {
134  CKeyingMaterial vchSecret;
135  if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
136  return false;
137 
138  if (vchSecret.size() != 32)
139  return false;
140 
141  key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
142  return key.VerifyPubKey(vchPubKey);
143 }
144 
146 {
147  LOCK(cs_KeyStore);
148  if (fUseCrypto)
149  return true;
150  if (!mapKeys.empty())
151  return false;
152  fUseCrypto = true;
153  return true;
154 }
155 
157 {
158  if (!SetCrypted())
159  return false;
160 
161  {
162  LOCK(cs_KeyStore);
163  vMasterKey.clear();
164  }
165 
166  NotifyStatusChanged(this);
167  return true;
168 }
169 
170 bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
171 {
172  {
173  LOCK(cs_KeyStore);
174  if (!SetCrypted())
175  return false;
176 
177  bool keyPass = false;
178  bool keyFail = false;
179  CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
180  for (; mi != mapCryptedKeys.end(); ++mi)
181  {
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))
186  {
187  keyFail = true;
188  break;
189  }
190  keyPass = true;
191  if (fDecryptionThoroughlyChecked)
192  break;
193  }
194  if (keyPass && keyFail)
195  {
196  LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
197  assert(false);
198  }
199  if (keyFail || !keyPass)
200  return false;
201  vMasterKey = vMasterKeyIn;
202  fDecryptionThoroughlyChecked = true;
203  }
204  NotifyStatusChanged(this);
205  return true;
206 }
207 
208 bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
209 {
210  {
211  LOCK(cs_KeyStore);
212  if (!IsCrypted())
213  return CBasicKeyStore::AddKeyPubKey(key, pubkey);
214 
215  if (IsLocked())
216  return false;
217 
218  std::vector<unsigned char> vchCryptedSecret;
219  CKeyingMaterial vchSecret(key.begin(), key.end());
220  if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
221  return false;
222 
223  if (!AddCryptedKey(pubkey, vchCryptedSecret))
224  return false;
225  }
226  return true;
227 }
228 
229 
230 bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
231 {
232  {
233  LOCK(cs_KeyStore);
234  if (!SetCrypted())
235  return false;
236 
237  mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
238  }
239  return true;
240 }
241 
242 bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
243 {
244  {
245  LOCK(cs_KeyStore);
246  if (!IsCrypted())
247  return CBasicKeyStore::GetKey(address, keyOut);
248 
249  CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
250  if (mi != mapCryptedKeys.end())
251  {
252  const CPubKey &vchPubKey = (*mi).second.first;
253  const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
254  return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
255  }
256  }
257  return false;
258 }
259 
260 bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
261 {
262  {
263  LOCK(cs_KeyStore);
264  if (!IsCrypted())
265  return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
266 
267  CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
268  if (mi != mapCryptedKeys.end())
269  {
270  vchPubKeyOut = (*mi).second.first;
271  return true;
272  }
273  // Check for watch-only pubkeys
274  return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
275  }
276 }
277 
279 {
280  {
281  LOCK(cs_KeyStore);
282  if (!mapCryptedKeys.empty() || IsCrypted())
283  return false;
284 
285  fUseCrypto = true;
286  for (KeyMap::value_type& mKey : mapKeys)
287  {
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;
296  }
297  mapKeys.clear();
298  }
299  return true;
300 }
bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector< unsigned char > &chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
Definition: crypter.cpp:43
const unsigned char * begin() const
Definition: key.h:88
const unsigned int WALLET_CRYPTO_KEY_SIZE
Definition: crypter.h:12
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:175
bool SetKey(const CKeyingMaterial &chNewKey, const std::vector< unsigned char > &chNewIV)
Definition: crypter.cpp:63
Encryption/decryption context with key information.
Definition: crypter.h:74
int Encrypt(const unsigned char *data, int size, unsigned char *out) const
Definition: aes.cpp:159
bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override
Definition: keystore.cpp:16
const unsigned char * end() const
Definition: key.h:89
size_t count
Definition: ExecStats.cpp:37
bool SetCrypted()
Definition: crypter.cpp:145
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: secure.h:56
bool Decrypt(const std::vector< unsigned char > &vchCiphertext, CKeyingMaterial &vchPlaintext) const
Definition: crypter.cpp:93
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
Definition: keystore.h:110
bool EncryptKeys(CKeyingMaterial &vMasterKeyIn)
will encrypt previously unencrypted keys
Definition: crypter.cpp:278
assert(len-trim+(2 *lenIndices)<=WIDTH)
const unsigned int WALLET_CRYPTO_IV_SIZE
Definition: crypter.h:14
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret)
Definition: crypter.cpp:230
bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override
Definition: crypter.cpp:260
void Finalize(unsigned char hash[OUTPUT_SIZE])
Definition: sha512.cpp:185
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override
Add a key to the store.
Definition: crypter.cpp:208
void memory_cleanse(void *ptr, size_t len)
Definition: cleanse.cpp:10
static const size_t OUTPUT_SIZE
Definition: sha512.h:20
#define LogPrintf(...)
Definition: util.h:153
std::vector< unsigned char, secure_allocator< unsigned char > > vchKey
Definition: crypter.h:78
std::vector< unsigned char, secure_allocator< unsigned char > > vchIV
Definition: crypter.h:79
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:147
#define LOCK(cs)
Definition: sync.h:175
bool fKeySet
Definition: crypter.h:80
CSHA512 & Reset()
Definition: sha512.cpp:202
An encapsulated public key.
Definition: pubkey.h:39
bool Unlock(const CKeyingMaterial &vMasterKeyIn)
Definition: crypter.cpp:170
int Decrypt(const unsigned char *data, int size, unsigned char *out) const
Definition: aes.cpp:176
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override
Add a key to the store.
Definition: keystore.cpp:32
uint256 GetHash() const
Get the 256-bit hash of this public key.
Definition: pubkey.h:152
bool GetKey(const CKeyID &address, CKey &keyOut) const override
Definition: crypter.cpp:242
bool GetKey(const CKeyID &address, CKey &keyOut) const override
Definition: keystore.h:87
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:73
int BytesToKeySHA512AES(const std::vector< unsigned char > &chSalt, const SecureString &strKeyData, int count, unsigned char *key, unsigned char *iv) const
Definition: crypter.cpp:16
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:171
256-bit opaque blob.
Definition: uint256.h:132
const unsigned int WALLET_CRYPTO_SALT_SIZE
Definition: crypter.h:13
bool Encrypt(const CKeyingMaterial &vchPlaintext, std::vector< unsigned char > &vchCiphertext) const
Definition: crypter.cpp:75
void * memcpy(void *a, const void *b, size_t c)
CSHA512 & Write(const unsigned char *data, size_t len)
Definition: sha512.cpp:159
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:29
struct evm_uint160be address(struct evm_env *env)
Definition: capi.c:13
An encapsulated private key.
Definition: key.h:35
A hasher class for SHA-512.
Definition: sha512.h:12
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:146