PIVX Core  5.6.99
P2P Digital Currency
crypter.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2013 The Bitcoin developers
2 // Copyright (c) 2017-2021 The PIVX Core developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "crypter.h"
7 
8 #include "crypto/aes.h"
9 #include "crypto/sha512.h"
10 #include "script/script.h"
11 #include "script/standard.h"
12 #include "uint256.h"
13 
14 int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char* key, unsigned char* iv) const
15 {
16  // This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc
17  // cipher and sha512 message digest. Because sha512's output size (64b) is
18  // greater than the aes256 block size (16b) + aes256 key size (32b),
19  // there's no need to process more than once (D_0).
20 
21  if (!count || !key || !iv)
22  return 0;
23 
24  unsigned char buf[CSHA512::OUTPUT_SIZE];
25  CSHA512 di;
26 
27  di.Write((const unsigned char*)strKeyData.c_str(), strKeyData.size());
28  di.Write(chSalt.data(), chSalt.size());
29  di.Finalize(buf);
30 
31  for (int i = 0; i != count - 1; i++)
32  di.Reset().Write(buf, sizeof(buf)).Finalize(buf);
33 
34  memcpy(key, buf, WALLET_CRYPTO_KEY_SIZE);
36  memory_cleanse(buf, sizeof(buf));
38 }
39 
40 bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
41 {
42  if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
43  return false;
44 
45  int i = 0;
46  if (nDerivationMethod == 0)
47  i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data());
48 
49  if (i != (int)WALLET_CRYPTO_KEY_SIZE) {
50  memory_cleanse(vchKey.data(), vchKey.size());
51  memory_cleanse(vchIV.data(), vchIV.size());
52  return false;
53  }
54 
55  fKeySet = true;
56  return true;
57 }
58 
59 bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
60 {
61  if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_IV_SIZE)
62  return false;
63 
64  memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
65  memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());
66 
67  fKeySet = true;
68  return true;
69 }
70 
71 bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char>& vchCiphertext) const
72 {
73  if (!fKeySet)
74  return false;
75 
76  // max ciphertext len for a n bytes of plaintext is
77  // n + AES_BLOCKSIZE bytes
78  vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
79 
80  AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true);
81  size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), vchCiphertext.data());
82  if (nLen < vchPlaintext.size())
83  return false;
84  vchCiphertext.resize(nLen);
85  return true;
86 }
87 
88 bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
89 {
90  if (!fKeySet)
91  return false;
92 
93  // plaintext will always be equal to or lesser than length of ciphertext
94  int nLen = vchCiphertext.size();
95  vchPlaintext.resize(nLen);
96  AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
97  nLen = dec.Decrypt(vchCiphertext.data(), vchCiphertext.size(), &vchPlaintext[0]);
98  if (nLen == 0)
99  return false;
100  vchPlaintext.resize(nLen);
101  return true;
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_IV_SIZE);
108  memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_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_IV_SIZE);
118  memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
119  if (!cKeyCrypter.SetKey(vMasterKey, chIV))
120  return false;
121  return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
122 }
123 
124 bool CCryptoKeyStore::DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
125 {
126  CKeyingMaterial vchSecret;
127  if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
128  return false;
129 
130  if (vchSecret.size() != 32)
131  return false;
132 
133  key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
134  return key.VerifyPubKey(vchPubKey);
135 }
136 
138 {
139  LOCK(cs_KeyStore);
140  if (fUseCrypto)
141  return true;
142  if (!mapKeys.empty() && !mapSaplingSpendingKeys.empty())
143  return false;
144  fUseCrypto = true;
145  return true;
146 }
147 
149 {
150  if (!IsCrypted()) {
151  return false;
152  }
153  return WITH_LOCK(cs_KeyStore, return vMasterKey.empty());
154 }
155 
156 bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey& pubkey)
157 {
158  LOCK(cs_KeyStore);
159  if (!IsCrypted()) {
160  return CBasicKeyStore::AddKeyPubKey(key, pubkey);
161  }
162 
163  if (IsLocked()) {
164  return false;
165  }
166 
167  std::vector<unsigned char> vchCryptedSecret;
168  CKeyingMaterial vchSecret(key.begin(), key.end());
169  if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
170  return false;
171  }
172 
173  if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
174  return false;
175  }
176  return true;
177 }
178 
179 bool CCryptoKeyStore::HaveKey(const CKeyID& address) const
180 {
181  LOCK(cs_KeyStore);
182  if (!IsCrypted()) {
183  return CBasicKeyStore::HaveKey(address);
184  }
185  return mapCryptedKeys.count(address) > 0;
186 }
187 
188 bool CCryptoKeyStore::AddCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret)
189 {
190  LOCK(cs_KeyStore);
191  if (!SetCrypted()) {
192  return false;
193  }
194 
195  mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
196  return true;
197 }
198 
199 bool CCryptoKeyStore::GetKey(const CKeyID& address, CKey& keyOut) const
200 {
201  LOCK(cs_KeyStore);
202  if (!IsCrypted()) {
203  return CBasicKeyStore::GetKey(address, keyOut);
204  }
205 
206  CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
207  if (mi != mapCryptedKeys.end()) {
208  const CPubKey& vchPubKey = (*mi).second.first;
209  const std::vector<unsigned char>& vchCryptedSecret = (*mi).second.second;
210  return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
211  }
212  return false;
213 }
214 
215 bool CCryptoKeyStore::GetPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) const
216 {
217  LOCK(cs_KeyStore);
218  if (!IsCrypted()) {
219  return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
220  }
221 
222  CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
223  if (mi != mapCryptedKeys.end()) {
224  vchPubKeyOut = (*mi).second.first;
225  return true;
226  }
227  // Check for watch-only pubkeys
228  return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
229 }
230 
231 std::set<CKeyID> CCryptoKeyStore::GetKeys() const
232 {
233  LOCK(cs_KeyStore);
234  if (!IsCrypted()) {
235  return CBasicKeyStore::GetKeys();
236  }
237  std::set<CKeyID> set_address;
238  for (const auto& mi : mapCryptedKeys) {
239  set_address.insert(mi.first);
240  }
241  return set_address;
242 }
243 
245 {
246  LOCK(cs_KeyStore);
247  if (!mapCryptedKeys.empty() || IsCrypted())
248  return false;
249 
250  fUseCrypto = true;
251  for (KeyMap::value_type& mKey : mapKeys) {
252  const CKey& key = mKey.second;
253  CPubKey vchPubKey = key.GetPubKey();
254  CKeyingMaterial vchSecret(key.begin(), key.end());
255  std::vector<unsigned char> vchCryptedSecret;
256  if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
257  return false;
258  if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
259  return false;
260  }
261  mapKeys.clear();
262  return true;
263 }
int Decrypt(const unsigned char *data, int size, unsigned char *out) const
Definition: aes.cpp:177
int Encrypt(const unsigned char *data, int size, unsigned char *out) const
Definition: aes.cpp:160
SaplingSpendingKeyMap mapSaplingSpendingKeys
Definition: keystore.h:109
bool GetKey(const CKeyID &address, CKey &keyOut) const
Definition: keystore.cpp:136
KeyMap mapKeys
Definition: keystore.h:101
std::set< CKeyID > GetKeys() const
Definition: keystore.cpp:126
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey)
Add a key to the store.
Definition: keystore.cpp:34
bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
Definition: keystore.cpp:19
bool HaveKey(const CKeyID &address) const
Check whether a key corresponding to a given address is present in the store.
Definition: keystore.cpp:116
Encryption/decryption context with key information.
Definition: crypter.h:84
bool Encrypt(const CKeyingMaterial &vchPlaintext, std::vector< unsigned char > &vchCiphertext) const
Definition: crypter.cpp:71
bool SetKey(const CKeyingMaterial &chNewKey, const std::vector< unsigned char > &chNewIV)
Definition: crypter.cpp:59
bool fKeySet
Definition: crypter.h:89
bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector< unsigned char > &chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
Definition: crypter.cpp:40
bool Decrypt(const std::vector< unsigned char > &vchCiphertext, CKeyingMaterial &vchPlaintext) const
Definition: crypter.cpp:88
int BytesToKeySHA512AES(const std::vector< unsigned char > &chSalt, const SecureString &strKeyData, int count, unsigned char *key, unsigned char *iv) const
Definition: crypter.cpp:14
std::vector< unsigned char, secure_allocator< unsigned char > > vchIV
Definition: crypter.h:88
std::vector< unsigned char, secure_allocator< unsigned char > > vchKey
Definition: crypter.h:87
bool GetKey(const CKeyID &address, CKey &keyOut) const override
Definition: crypter.cpp:199
std::atomic< bool > fUseCrypto
if fUseCrypto is true, mapKeys and mapSaplingSpendingKeys must be empty if fUseCrypto is false,...
Definition: crypter.h:131
static bool DecryptKey(const CKeyingMaterial &vMasterKey, const std::vector< unsigned char > &vchCryptedSecret, const CPubKey &vchPubKey, CKey &key)
Definition: crypter.cpp:124
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override
Add a key to the store.
Definition: crypter.cpp:156
bool IsLocked() const
Definition: crypter.cpp:148
bool HaveKey(const CKeyID &address) const override
Check whether a key corresponding to a given address is present in the store.
Definition: crypter.cpp:179
bool EncryptKeys(CKeyingMaterial &vMasterKeyIn)
will encrypt previously unencrypted keys
Definition: crypter.cpp:244
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret)
Definition: crypter.cpp:188
CKeyingMaterial vMasterKey
Definition: crypter.h:135
bool IsCrypted() const
Definition: crypter.h:154
CryptedKeyMap mapCryptedKeys
Definition: crypter.h:144
std::set< CKeyID > GetKeys() const override
Definition: crypter.cpp:231
bool SetCrypted()
Definition: crypter.cpp:137
bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override
Definition: crypter.cpp:215
An encapsulated private key.
Definition: key.h:30
const unsigned char * end() const
Definition: key.h:92
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:186
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:76
const unsigned char * begin() const
Definition: key.h:91
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:216
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:21
RecursiveMutex cs_KeyStore
Definition: keystore.h:26
An encapsulated public key.
Definition: pubkey.h:44
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:192
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:167
uint256 GetHash() const
Get the 256-bit hash of this public key.
Definition: pubkey.h:173
A hasher class for SHA-512.
Definition: sha512.h:13
static constexpr size_t OUTPUT_SIZE
Definition: sha512.h:20
CSHA512 & Reset()
Definition: sha512.cpp:202
void Finalize(unsigned char hash[OUTPUT_SIZE])
Definition: sha512.cpp:185
CSHA512 & Write(const unsigned char *data, size_t len)
Definition: sha512.cpp:159
256-bit opaque blob.
Definition: uint256.h:138
void memory_cleanse(void *ptr, size_t len)
Definition: cleanse.cpp:27
bool EncryptSecret(const CKeyingMaterial &vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256 &nIV, std::vector< unsigned char > &vchCiphertext)
Definition: crypter.cpp:104
bool DecryptSecret(const CKeyingMaterial &vMasterKey, const std::vector< unsigned char > &vchCiphertext, const uint256 &nIV, CKeyingMaterial &vchPlaintext)
Definition: crypter.cpp:114
const unsigned int WALLET_CRYPTO_IV_SIZE
Definition: crypter.h:20
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
Definition: crypter.h:63
const unsigned int WALLET_CRYPTO_SALT_SIZE
Definition: crypter.h:19
const unsigned int WALLET_CRYPTO_KEY_SIZE
Definition: crypter.h:18
void * memcpy(void *a, const void *b, size_t c)
@ LOCK
Definition: lockunlock.h:16
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: secure.h:61
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:247