Bitcoin Core  29.1.0
P2P Digital Currency
crypter.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2021 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 <common/system.h>
8 #include <crypto/aes.h>
9 #include <crypto/sha512.h>
10 
11 #include <type_traits>
12 #include <vector>
13 
14 namespace wallet {
15 int CCrypter::BytesToKeySHA512AES(const std::span<const unsigned char> salt, const SecureString& key_data, int count, unsigned char* key, unsigned char* iv) const
16 {
17  // This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc
18  // cipher and sha512 message digest. Because sha512's output size (64b) is
19  // greater than the aes256 block size (16b) + aes256 key size (32b),
20  // there's no need to process more than once (D_0).
21 
22  if(!count || !key || !iv)
23  return 0;
24 
25  unsigned char buf[CSHA512::OUTPUT_SIZE];
26  CSHA512 di;
27 
28  di.Write(UCharCast(key_data.data()), key_data.size());
29  di.Write(salt.data(), salt.size());
30  di.Finalize(buf);
31 
32  for(int i = 0; i != count - 1; i++)
33  di.Reset().Write(buf, sizeof(buf)).Finalize(buf);
34 
35  memcpy(key, buf, WALLET_CRYPTO_KEY_SIZE);
37  memory_cleanse(buf, sizeof(buf));
39 }
40 
41 bool CCrypter::SetKeyFromPassphrase(const SecureString& key_data, const std::span<const unsigned char> salt, const unsigned int rounds, const unsigned int derivation_method)
42 {
43  if (rounds < 1 || salt.size() != WALLET_CRYPTO_SALT_SIZE) {
44  return false;
45  }
46 
47  int i = 0;
48  if (derivation_method == 0) {
49  i = BytesToKeySHA512AES(salt, key_data, rounds, vchKey.data(), vchIV.data());
50  }
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& new_key, const std::span<const unsigned char> new_iv)
64 {
65  if (new_key.size() != WALLET_CRYPTO_KEY_SIZE || new_iv.size() != WALLET_CRYPTO_IV_SIZE) {
66  return false;
67  }
68 
69  memcpy(vchKey.data(), new_key.data(), new_key.size());
70  memcpy(vchIV.data(), new_iv.data(), new_iv.size());
71 
72  fKeySet = true;
73  return true;
74 }
75 
76 bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const
77 {
78  if (!fKeySet)
79  return false;
80 
81  // max ciphertext len for a n bytes of plaintext is
82  // n + AES_BLOCKSIZE bytes
83  vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
84 
85  AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true);
86  size_t nLen = enc.Encrypt(vchPlaintext.data(), vchPlaintext.size(), vchCiphertext.data());
87  if(nLen < vchPlaintext.size())
88  return false;
89  vchCiphertext.resize(nLen);
90 
91  return true;
92 }
93 
94 bool CCrypter::Decrypt(const std::span<const unsigned char> ciphertext, CKeyingMaterial& plaintext) const
95 {
96  if (!fKeySet)
97  return false;
98 
99  // plaintext will always be equal to or lesser than length of ciphertext
100  plaintext.resize(ciphertext.size());
101 
102  AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
103  int len = dec.Decrypt(ciphertext.data(), ciphertext.size(), plaintext.data());
104  if (len == 0) {
105  return false;
106  }
107  plaintext.resize(len);
108  return true;
109 }
110 
111 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(vchPlaintext, vchCiphertext);
119 }
120 
121 bool DecryptSecret(const CKeyingMaterial& master_key, const std::span<const unsigned char> ciphertext, const uint256& iv, CKeyingMaterial& plaintext)
122 {
123  CCrypter key_crypter;
124  static_assert(WALLET_CRYPTO_IV_SIZE <= std::remove_reference_t<decltype(iv)>::size());
125  const std::span iv_prefix{iv.data(), WALLET_CRYPTO_IV_SIZE};
126  if (!key_crypter.SetKey(master_key, iv_prefix)) {
127  return false;
128  }
129  return key_crypter.Decrypt(ciphertext, plaintext);
130 }
131 
132 bool DecryptKey(const CKeyingMaterial& master_key, const std::span<const unsigned char> crypted_secret, const CPubKey& pub_key, CKey& key)
133 {
134  CKeyingMaterial secret;
135  if (!DecryptSecret(master_key, crypted_secret, pub_key.GetHash(), secret)) {
136  return false;
137  }
138 
139  if (secret.size() != 32) {
140  return false;
141  }
142 
143  key.Set(secret.begin(), secret.end(), pub_key.IsCompressed());
144  return key.VerifyPubKey(pub_key);
145 }
146 } // namespace wallet
int BytesToKeySHA512AES(std::span< const unsigned char > salt, const SecureString &key_data, int count, unsigned char *key, unsigned char *iv) const
Definition: crypter.cpp:15
bool DecryptSecret(const CKeyingMaterial &master_key, const std::span< const unsigned char > ciphertext, const uint256 &iv, CKeyingMaterial &plaintext)
Definition: crypter.cpp:121
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:236
std::vector< unsigned char, secure_allocator< unsigned char > > vchKey
Definition: crypter.h:74
bool Encrypt(const CKeyingMaterial &vchPlaintext, std::vector< unsigned char > &vchCiphertext) const
Definition: crypter.cpp:76
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: secure.h:58
uint256 GetHash() const
Get the 256-bit hash of this public key.
Definition: pubkey.h:170
int Decrypt(const unsigned char *data, int size, unsigned char *out) const
Definition: aes.cpp:144
memcpy(result.begin(), stream.data(), stream.size())
bool SetKeyFromPassphrase(const SecureString &key_data, std::span< const unsigned char > salt, const unsigned int rounds, const unsigned int derivation_method)
Definition: crypter.cpp:41
void Finalize(unsigned char hash[OUTPUT_SIZE])
Definition: sha512.cpp:185
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
Definition: cleanse.cpp:14
bool DecryptKey(const CKeyingMaterial &master_key, const std::span< const unsigned char > crypted_secret, const CPubKey &pub_key, CKey &key)
Definition: crypter.cpp:132
bool SetKey(const CKeyingMaterial &new_key, std::span< const unsigned char > new_iv)
Definition: crypter.cpp:63
CSHA512 & Reset()
Definition: sha512.cpp:202
An encapsulated public key.
Definition: pubkey.h:33
int Encrypt(const unsigned char *data, int size, unsigned char *out) const
Definition: aes.cpp:127
const unsigned int WALLET_CRYPTO_IV_SIZE
Definition: crypter.h:16
static constexpr size_t OUTPUT_SIZE
Definition: sha512.h:20
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:103
bool Decrypt(std::span< const unsigned char > ciphertext, CKeyingMaterial &plaintext) const
Definition: crypter.cpp:94
std::vector< unsigned char, secure_allocator< unsigned char > > vchIV
Definition: crypter.h:75
256-bit opaque blob.
Definition: uint256.h:201
bool EncryptSecret(const CKeyingMaterial &vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256 &nIV, std::vector< unsigned char > &vchCiphertext)
Definition: crypter.cpp:111
constexpr const unsigned char * data() const
Definition: uint256.h:112
CSHA512 & Write(const unsigned char *data, size_t len)
Definition: sha512.cpp:159
const unsigned int WALLET_CRYPTO_KEY_SIZE
Definition: crypter.h:14
static int count
Encryption/decryption context with key information.
Definition: crypter.h:70
unsigned char * UCharCast(char *c)
Definition: span.h:280
An encapsulated private key.
Definition: key.h:34
A hasher class for SHA-512.
Definition: sha512.h:12
const unsigned int WALLET_CRYPTO_SALT_SIZE
Definition: crypter.h:15
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
Definition: crypter.h:62
static const int AES_BLOCKSIZE
Definition: aes.h:14
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:204