Branch data Line data Source code
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 : 78 : 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 [ + - + - ]: 78 : if(!count || !key || !iv)
23 : : return 0;
24 : :
25 : 78 : unsigned char buf[CSHA512::OUTPUT_SIZE];
26 : 78 : CSHA512 di;
27 : :
28 : 78 : di.Write(UCharCast(key_data.data()), key_data.size());
29 : 78 : di.Write(salt.data(), salt.size());
30 : 78 : di.Finalize(buf);
31 : :
32 [ + + ]: 2445844 : for(int i = 0; i != count - 1; i++)
33 : 2445766 : di.Reset().Write(buf, sizeof(buf)).Finalize(buf);
34 : :
35 : 78 : memcpy(key, buf, WALLET_CRYPTO_KEY_SIZE);
36 : 78 : memcpy(iv, buf + WALLET_CRYPTO_KEY_SIZE, WALLET_CRYPTO_IV_SIZE);
37 : 78 : memory_cleanse(buf, sizeof(buf));
38 : 78 : return WALLET_CRYPTO_KEY_SIZE;
39 : : }
40 : :
41 : 78 : 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 [ + - + - ]: 78 : if (rounds < 1 || salt.size() != WALLET_CRYPTO_SALT_SIZE) {
44 : : return false;
45 : : }
46 : :
47 : 78 : int i = 0;
48 [ + - ]: 78 : if (derivation_method == 0) {
49 : 78 : i = BytesToKeySHA512AES(salt, key_data, rounds, vchKey.data(), vchIV.data());
50 : : }
51 : :
52 [ - + ]: 78 : if (i != (int)WALLET_CRYPTO_KEY_SIZE)
53 : : {
54 : 0 : memory_cleanse(vchKey.data(), vchKey.size());
55 : 0 : memory_cleanse(vchIV.data(), vchIV.size());
56 : 0 : return false;
57 : : }
58 : :
59 : 78 : fKeySet = true;
60 : 78 : return true;
61 : : }
62 : :
63 : 5006 : bool CCrypter::SetKey(const CKeyingMaterial& new_key, const std::span<const unsigned char> new_iv)
64 : : {
65 [ + - + - ]: 5006 : if (new_key.size() != WALLET_CRYPTO_KEY_SIZE || new_iv.size() != WALLET_CRYPTO_IV_SIZE) {
66 : : return false;
67 : : }
68 : :
69 : 5006 : memcpy(vchKey.data(), new_key.data(), new_key.size());
70 : 5006 : memcpy(vchIV.data(), new_iv.data(), new_iv.size());
71 : :
72 : 5006 : fKeySet = true;
73 : 5006 : return true;
74 : : }
75 : :
76 : 5336 : bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const
77 : : {
78 [ + - ]: 5336 : if (!fKeySet)
79 : : return false;
80 : :
81 : : // max ciphertext len for a n bytes of plaintext is
82 : : // n + AES_BLOCKSIZE bytes
83 : 5336 : vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
84 : :
85 : 5336 : AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true);
86 [ + - ]: 5336 : size_t nLen = enc.Encrypt(vchPlaintext.data(), vchPlaintext.size(), vchCiphertext.data());
87 [ + - ]: 5336 : if(nLen < vchPlaintext.size())
88 : : return false;
89 [ + - ]: 5336 : vchCiphertext.resize(nLen);
90 : :
91 : : return true;
92 : 5336 : }
93 : :
94 : 6446 : bool CCrypter::Decrypt(const std::span<const unsigned char> ciphertext, CKeyingMaterial& plaintext) const
95 : : {
96 [ + - ]: 6446 : if (!fKeySet)
97 : : return false;
98 : :
99 : : // plaintext will always be equal to or lesser than length of ciphertext
100 : 6446 : plaintext.resize(ciphertext.size());
101 : :
102 : 6446 : AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
103 [ + - ]: 6446 : int len = dec.Decrypt(ciphertext.data(), ciphertext.size(), plaintext.data());
104 [ + + ]: 6446 : if (len == 0) {
105 : : return false;
106 : : }
107 [ + - ]: 6340 : plaintext.resize(len);
108 : : return true;
109 : 6446 : }
110 : :
111 : 2002 : bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
112 : : {
113 : 2002 : CCrypter cKeyCrypter;
114 [ + - ]: 2002 : std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
115 [ + - ]: 2002 : memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
116 [ + - + - ]: 2002 : if(!cKeyCrypter.SetKey(vMasterKey, chIV))
117 : : return false;
118 [ + - ]: 2002 : return cKeyCrypter.Encrypt(vchPlaintext, vchCiphertext);
119 : 2002 : }
120 : :
121 : 3004 : bool DecryptSecret(const CKeyingMaterial& master_key, const std::span<const unsigned char> ciphertext, const uint256& iv, CKeyingMaterial& plaintext)
122 : : {
123 : 3004 : CCrypter key_crypter;
124 : 3004 : static_assert(WALLET_CRYPTO_IV_SIZE <= std::remove_reference_t<decltype(iv)>::size());
125 [ + - ]: 3004 : const std::span iv_prefix{iv.data(), WALLET_CRYPTO_IV_SIZE};
126 [ + - + - ]: 3004 : if (!key_crypter.SetKey(master_key, iv_prefix)) {
127 : : return false;
128 : : }
129 [ + - ]: 3004 : return key_crypter.Decrypt(ciphertext, plaintext);
130 : 3004 : }
131 : :
132 : 3004 : bool DecryptKey(const CKeyingMaterial& master_key, const std::span<const unsigned char> crypted_secret, const CPubKey& pub_key, CKey& key)
133 : : {
134 : 3004 : CKeyingMaterial secret;
135 [ + - + - : 3004 : if (!DecryptSecret(master_key, crypted_secret, pub_key.GetHash(), secret)) {
+ - ]
136 : : return false;
137 : : }
138 : :
139 [ + - ]: 3004 : if (secret.size() != 32) {
140 : : return false;
141 : : }
142 : :
143 [ + - ]: 3004 : key.Set(secret.begin(), secret.end(), pub_key.IsCompressed());
144 [ + - ]: 3004 : return key.VerifyPubKey(pub_key);
145 : 3004 : }
146 : : } // namespace wallet
|