BSHA3  0.17.99
P2P Blockchain, based on Bitcoin
crypter.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2018 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/sha3512.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 sha3-512 message digest. Because sha3-512'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[CSHA3512::OUTPUT_SIZE];
27  CSHA3512 di;
28 
29  di.Write((const unsigned char*)strKeyData.c_str(), strKeyData.size());
30  di.Write(chSalt.data(), chSalt.size());
31  di.Finalize(buf);
32 
33  for(int i = 0; i != count - 1; i++)
34  di.Reset().Write(buf, sizeof(buf)).Finalize(buf);
35 
36  memcpy(key, buf, WALLET_CRYPTO_KEY_SIZE);
38  memory_cleanse(buf, sizeof(buf));
40 }
41 
42 bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
43 {
44  if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
45  return false;
46 
47  int i = 0;
48  if (nDerivationMethod == 0)
49  i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data());
50 
51  if (i != (int)WALLET_CRYPTO_KEY_SIZE)
52  {
53  memory_cleanse(vchKey.data(), vchKey.size());
54  memory_cleanse(vchIV.data(), vchIV.size());
55  return false;
56  }
57 
58  fKeySet = true;
59  return true;
60 }
61 
62 bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
63 {
64  if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_IV_SIZE)
65  return false;
66 
67  memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
68  memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());
69 
70  fKeySet = true;
71  return true;
72 }
73 
74 bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const
75 {
76  if (!fKeySet)
77  return false;
78 
79  // max ciphertext len for a n bytes of plaintext is
80  // n + AES_BLOCKSIZE bytes
81  vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
82 
83  AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true);
84  size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), vchCiphertext.data());
85  if(nLen < vchPlaintext.size())
86  return false;
87  vchCiphertext.resize(nLen);
88 
89  return true;
90 }
91 
92 bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
93 {
94  if (!fKeySet)
95  return false;
96 
97  // plaintext will always be equal to or lesser than length of ciphertext
98  int nLen = vchCiphertext.size();
99 
100  vchPlaintext.resize(nLen);
101 
102  AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
103  nLen = dec.Decrypt(vchCiphertext.data(), vchCiphertext.size(), &vchPlaintext[0]);
104  if(nLen == 0)
105  return false;
106  vchPlaintext.resize(nLen);
107  return true;
108 }
109 
110 
111 static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
112 {
113  CCrypter cKeyCrypter;
114  std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
115  memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
116  if(!cKeyCrypter.SetKey(vMasterKey, chIV))
117  return false;
118  return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
119 }
120 
121 static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
122 {
123  CCrypter cKeyCrypter;
124  std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
125  memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
126  if(!cKeyCrypter.SetKey(vMasterKey, chIV))
127  return false;
128  return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
129 }
130 
131 static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
132 {
133  CKeyingMaterial vchSecret;
134  if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
135  return false;
136 
137  if (vchSecret.size() != 32)
138  return false;
139 
140  key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
141  return key.VerifyPubKey(vchPubKey);
142 }
143 
145 {
146  LOCK(cs_KeyStore);
147  if (fUseCrypto)
148  return true;
149  if (!mapKeys.empty())
150  return false;
151  fUseCrypto = true;
152  return true;
153 }
154 
156 {
157  if (!IsCrypted()) {
158  return false;
159  }
160  LOCK(cs_KeyStore);
161  return vMasterKey.empty();
162 }
163 
165 {
166  if (!SetCrypted())
167  return false;
168 
169  {
170  LOCK(cs_KeyStore);
171  vMasterKey.clear();
172  }
173 
174  NotifyStatusChanged(this);
175  return true;
176 }
177 
178 bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
179 {
180  {
181  LOCK(cs_KeyStore);
182  if (!SetCrypted())
183  return false;
184 
185  bool keyPass = false;
186  bool keyFail = false;
187  CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
188  for (; mi != mapCryptedKeys.end(); ++mi)
189  {
190  const CPubKey &vchPubKey = (*mi).second.first;
191  const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
192  CKey key;
193  if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
194  {
195  keyFail = true;
196  break;
197  }
198  keyPass = true;
200  break;
201  }
202  if (keyPass && keyFail)
203  {
204  LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
205  assert(false);
206  }
207  if (keyFail || !keyPass)
208  return false;
209  vMasterKey = vMasterKeyIn;
211  }
212  NotifyStatusChanged(this);
213  return true;
214 }
215 
216 bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
217 {
218  LOCK(cs_KeyStore);
219  if (!IsCrypted()) {
220  return CBasicKeyStore::AddKeyPubKey(key, pubkey);
221  }
222 
223  if (IsLocked()) {
224  return false;
225  }
226 
227  std::vector<unsigned char> vchCryptedSecret;
228  CKeyingMaterial vchSecret(key.begin(), key.end());
229  if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
230  return false;
231  }
232 
233  if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
234  return false;
235  }
236  return true;
237 }
238 
239 
240 bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
241 {
242  LOCK(cs_KeyStore);
243  if (!SetCrypted()) {
244  return false;
245  }
246 
247  mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
249  return true;
250 }
251 
252 bool CCryptoKeyStore::HaveKey(const CKeyID &address) const
253 {
254  LOCK(cs_KeyStore);
255  if (!IsCrypted()) {
256  return CBasicKeyStore::HaveKey(address);
257  }
258  return mapCryptedKeys.count(address) > 0;
259 }
260 
261 bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
262 {
263  LOCK(cs_KeyStore);
264  if (!IsCrypted()) {
265  return CBasicKeyStore::GetKey(address, keyOut);
266  }
267 
268  CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
269  if (mi != mapCryptedKeys.end())
270  {
271  const CPubKey &vchPubKey = (*mi).second.first;
272  const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
273  return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
274  }
275  return false;
276 }
277 
278 bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
279 {
280  LOCK(cs_KeyStore);
281  if (!IsCrypted())
282  return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
283 
284  CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
285  if (mi != mapCryptedKeys.end())
286  {
287  vchPubKeyOut = (*mi).second.first;
288  return true;
289  }
290  // Check for watch-only pubkeys
291  return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
292 }
293 
294 std::set<CKeyID> CCryptoKeyStore::GetKeys() const
295 {
296  LOCK(cs_KeyStore);
297  if (!IsCrypted()) {
298  return CBasicKeyStore::GetKeys();
299  }
300  std::set<CKeyID> set_address;
301  for (const auto& mi : mapCryptedKeys) {
302  set_address.insert(mi.first);
303  }
304  return set_address;
305 }
306 
308 {
309  LOCK(cs_KeyStore);
310  if (!mapCryptedKeys.empty() || IsCrypted())
311  return false;
312 
313  fUseCrypto = true;
314  for (const KeyMap::value_type& mKey : mapKeys)
315  {
316  const CKey &key = mKey.second;
317  CPubKey vchPubKey = key.GetPubKey();
318  CKeyingMaterial vchSecret(key.begin(), key.end());
319  std::vector<unsigned char> vchCryptedSecret;
320  if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
321  return false;
322  if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
323  return false;
324  }
325  mapKeys.clear();
326  return true;
327 }
bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector< unsigned char > &chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
Definition: crypter.cpp:42
CSHA3512 & Write(const unsigned char *data, size_t len)
Definition: sha3512.cpp:30
bool HaveKey(const CKeyID &address) const override
Check whether a key corresponding to a given address is present in the store.
Definition: crypter.cpp:252
const unsigned int WALLET_CRYPTO_KEY_SIZE
Definition: crypter.h:14
bool Encrypt(const CKeyingMaterial &vchPlaintext, std::vector< unsigned char > &vchCiphertext) const
Definition: crypter.cpp:74
static const size_t OUTPUT_SIZE
Definition: sha3512.h:23
bool SetKey(const CKeyingMaterial &chNewKey, const std::vector< unsigned char > &chNewIV)
Definition: crypter.cpp:62
Encryption/decryption context with key information.
Definition: crypter.h:76
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:227
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:179
bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override
Definition: keystore.cpp:35
bool IsCrypted() const
Definition: crypter.h:144
CCriticalSection cs_KeyStore
Definition: keystore.h:45
bool SetCrypted()
Definition: crypter.cpp:144
void ImplicitlyLearnRelatedKeyScripts(const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore)
Definition: keystore.cpp:10
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: secure.h:56
std::set< CKeyID > GetKeys() const override
Definition: keystore.cpp:65
uint256 GetHash() const
Get the 256-bit hash of this public key.
Definition: pubkey.h:161
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
Definition: crypter.h:68
bool EncryptKeys(CKeyingMaterial &vMasterKeyIn)
will encrypt previously unencrypted keys
Definition: crypter.cpp:307
int BytesToKeySHA512AES(const std::vector< unsigned char > &chSalt, const SecureString &strKeyData, int count, unsigned char *key, unsigned char *iv) const
Definition: crypter.cpp:16
int Decrypt(const unsigned char *data, int size, unsigned char *out) const
Definition: aes.cpp:176
std::atomic< bool > fUseCrypto
if fUseCrypto is true, mapKeys must be empty if fUseCrypto is false, vMasterKey must be empty ...
Definition: crypter.h:123
bool Decrypt(const std::vector< unsigned char > &vchCiphertext, CKeyingMaterial &vchPlaintext) const
Definition: crypter.cpp:92
const unsigned int WALLET_CRYPTO_IV_SIZE
Definition: crypter.h:16
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret)
Definition: crypter.cpp:240
const unsigned char * begin() const
Definition: key.h:89
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:155
bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override
Definition: crypter.cpp:278
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override
Add a key to the store.
Definition: crypter.cpp:216
boost::signals2::signal< void(CCryptoKeyStore *wallet)> NotifyStatusChanged
Wallet status (encrypted, locked) changed.
Definition: crypter.h:159
void memory_cleanse(void *ptr, size_t len)
Definition: cleanse.cpp:31
void Finalize(unsigned char hash[OUTPUT_SIZE])
Definition: sha3512.cpp:36
std::vector< unsigned char, secure_allocator< unsigned char > > vchKey
Definition: crypter.h:80
std::vector< unsigned char, secure_allocator< unsigned char > > vchIV
Definition: crypter.h:81
#define LOCK(cs)
Definition: sync.h:181
bool IsLocked() const
Definition: crypter.cpp:155
bool fKeySet
Definition: crypter.h:82
An encapsulated public key.
Definition: pubkey.h:30
bool Unlock(const CKeyingMaterial &vMasterKeyIn)
Definition: crypter.cpp:178
int Encrypt(const unsigned char *data, int size, unsigned char *out) const
Definition: aes.cpp:159
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override
Add a key to the store.
Definition: keystore.cpp:51
A hasher class for SHA3-512.
Definition: sha3512.h:14
bool GetKey(const CKeyID &address, CKey &keyOut) const override
Definition: crypter.cpp:261
bool GetKey(const CKeyID &address, CKey &keyOut) const override
Definition: keystore.cpp:75
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:74
256-bit opaque blob.
Definition: uint256.h:122
const unsigned int WALLET_CRYPTO_SALT_SIZE
Definition: crypter.h:15
CSHA3512 & Reset()
Definition: sha3512.cpp:41
void * memcpy(void *a, const void *b, size_t c)
const unsigned char * end() const
Definition: key.h:90
A reference to a CKey: the Hash360 of its serialized public key.
Definition: pubkey.h:20
An encapsulated private key.
Definition: key.h:27
std::set< CKeyID > GetKeys() const override
Definition: crypter.cpp:294
bool HaveKey(const CKeyID &address) const override
Check whether a key corresponding to a given address is present in the store.
Definition: keystore.cpp:59
bool fDecryptionThoroughlyChecked
keeps track of whether Unlock has run a thorough check before
Definition: crypter.h:126
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:180