Bitcoin Core 28.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
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 <vector>
12
13namespace wallet {
14int 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.data(), 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
40bool 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 {
51 memory_cleanse(vchKey.data(), vchKey.size());
52 memory_cleanse(vchIV.data(), vchIV.size());
53 return false;
54 }
55
56 fKeySet = true;
57 return true;
58}
59
60bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
61{
62 if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_IV_SIZE)
63 return false;
64
65 memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
66 memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());
67
68 fKeySet = true;
69 return true;
70}
71
72bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const
73{
74 if (!fKeySet)
75 return false;
76
77 // max ciphertext len for a n bytes of plaintext is
78 // n + AES_BLOCKSIZE bytes
79 vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
80
81 AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true);
82 size_t nLen = enc.Encrypt(vchPlaintext.data(), vchPlaintext.size(), vchCiphertext.data());
83 if(nLen < vchPlaintext.size())
84 return false;
85 vchCiphertext.resize(nLen);
86
87 return true;
88}
89
90bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
91{
92 if (!fKeySet)
93 return false;
94
95 // plaintext will always be equal to or lesser than length of ciphertext
96 int nLen = vchCiphertext.size();
97
98 vchPlaintext.resize(nLen);
99
100 AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
101 nLen = dec.Decrypt(vchCiphertext.data(), vchCiphertext.size(), vchPlaintext.data());
102 if(nLen == 0)
103 return false;
104 vchPlaintext.resize(nLen);
105 return true;
106}
107
108bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
109{
110 CCrypter cKeyCrypter;
111 std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
112 memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
113 if(!cKeyCrypter.SetKey(vMasterKey, chIV))
114 return false;
115 return cKeyCrypter.Encrypt(vchPlaintext, vchCiphertext);
116}
117
118bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
119{
120 CCrypter cKeyCrypter;
121 std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
122 memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
123 if(!cKeyCrypter.SetKey(vMasterKey, chIV))
124 return false;
125 return cKeyCrypter.Decrypt(vchCiphertext, vchPlaintext);
126}
127
128bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
129{
130 CKeyingMaterial vchSecret;
131 if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
132 return false;
133
134 if (vchSecret.size() != 32)
135 return false;
136
137 key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
138 return key.VerifyPubKey(vchPubKey);
139}
140} // namespace wallet
static const int AES_BLOCKSIZE
Definition aes.h:14
int Decrypt(const unsigned char *data, int size, unsigned char *out) const
Definition aes.cpp:144
int Encrypt(const unsigned char *data, int size, unsigned char *out) const
Definition aes.cpp:127
An encapsulated private key.
Definition key.h:35
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition key.h:103
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition key.cpp:236
An encapsulated public key.
Definition pubkey.h:34
bool IsCompressed() const
Check whether this is a compressed public key.
Definition pubkey.h:204
uint256 GetHash() const
Get the 256-bit hash of this public key.
Definition pubkey.h:170
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:178
Encryption/decryption context with key information.
Definition crypter.h:71
bool Decrypt(const std::vector< unsigned char > &vchCiphertext, CKeyingMaterial &vchPlaintext) const
Definition crypter.cpp:90
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:72
std::vector< unsigned char, secure_allocator< unsigned char > > vchIV
Definition crypter.h:75
bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector< unsigned char > &chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
Definition crypter.cpp:40
bool SetKey(const CKeyingMaterial &chNewKey, const std::vector< unsigned char > &chNewIV)
Definition crypter.cpp:60
int BytesToKeySHA512AES(const std::vector< unsigned char > &chSalt, const SecureString &strKeyData, int count, unsigned char *key, unsigned char *iv) const
Definition crypter.cpp:14
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
Definition cleanse.cpp:14
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
Definition crypter.h:62
bool DecryptSecret(const CKeyingMaterial &vMasterKey, const std::vector< unsigned char > &vchCiphertext, const uint256 &nIV, CKeyingMaterial &vchPlaintext)
Definition crypter.cpp:118
bool DecryptKey(const CKeyingMaterial &vMasterKey, const std::vector< unsigned char > &vchCryptedSecret, const CPubKey &vchPubKey, CKey &key)
Definition crypter.cpp:128
const unsigned int WALLET_CRYPTO_KEY_SIZE
Definition crypter.h:14
const unsigned int WALLET_CRYPTO_IV_SIZE
Definition crypter.h:16
const unsigned int WALLET_CRYPTO_SALT_SIZE
Definition crypter.h:15
bool EncryptSecret(const CKeyingMaterial &vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256 &nIV, std::vector< unsigned char > &vchCiphertext)
Definition crypter.cpp:108
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition secure.h:58
static int count