Bitcoin Core 22.99.0
P2P Digital Currency
crypter.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2019 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/sha512.h>
9#include <util/system.h>
10
11#include <vector>
12
13int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const
14{
15 // This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc
16 // cipher and sha512 message digest. Because sha512's output size (64b) is
17 // greater than the aes256 block size (16b) + aes256 key size (32b),
18 // there's no need to process more than once (D_0).
19
20 if(!count || !key || !iv)
21 return 0;
22
23 unsigned char buf[CSHA512::OUTPUT_SIZE];
24 CSHA512 di;
25
26 di.Write((const unsigned char*)strKeyData.data(), strKeyData.size());
27 di.Write(chSalt.data(), chSalt.size());
28 di.Finalize(buf);
29
30 for(int i = 0; i != count - 1; i++)
31 di.Reset().Write(buf, sizeof(buf)).Finalize(buf);
32
33 memcpy(key, buf, WALLET_CRYPTO_KEY_SIZE);
35 memory_cleanse(buf, sizeof(buf));
37}
38
39bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
40{
41 if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
42 return false;
43
44 int i = 0;
45 if (nDerivationMethod == 0)
46 i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data());
47
48 if (i != (int)WALLET_CRYPTO_KEY_SIZE)
49 {
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
59bool 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
71bool 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.data(), vchPlaintext.size(), vchCiphertext.data());
82 if(nLen < vchPlaintext.size())
83 return false;
84 vchCiphertext.resize(nLen);
85
86 return true;
87}
88
89bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
90{
91 if (!fKeySet)
92 return false;
93
94 // plaintext will always be equal to or lesser than length of ciphertext
95 int nLen = vchCiphertext.size();
96
97 vchPlaintext.resize(nLen);
98
99 AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
100 nLen = dec.Decrypt(vchCiphertext.data(), vchCiphertext.size(), vchPlaintext.data());
101 if(nLen == 0)
102 return false;
103 vchPlaintext.resize(nLen);
104 return true;
105}
106
107bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
108{
109 CCrypter cKeyCrypter;
110 std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
111 memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
112 if(!cKeyCrypter.SetKey(vMasterKey, chIV))
113 return false;
114 return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
115}
116
117bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
118{
119 CCrypter cKeyCrypter;
120 std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
121 memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
122 if(!cKeyCrypter.SetKey(vMasterKey, chIV))
123 return false;
124 return cKeyCrypter.Decrypt(vchCiphertext, vchPlaintext);
125}
126
127bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
128{
129 CKeyingMaterial vchSecret;
130 if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
131 return false;
132
133 if (vchSecret.size() != 32)
134 return false;
135
136 key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
137 return key.VerifyPubKey(vchPubKey);
138}
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
Encryption/decryption context with key information.
Definition: crypter.h:70
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:75
bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector< unsigned char > &chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
Definition: crypter.cpp:39
bool Decrypt(const std::vector< unsigned char > &vchCiphertext, CKeyingMaterial &vchPlaintext) const
Definition: crypter.cpp:89
int BytesToKeySHA512AES(const std::vector< unsigned char > &chSalt, const SecureString &strKeyData, int count, unsigned char *key, unsigned char *iv) const
Definition: crypter.cpp:13
std::vector< unsigned char, secure_allocator< unsigned char > > vchIV
Definition: crypter.h:74
std::vector< unsigned char, secure_allocator< unsigned char > > vchKey
Definition: crypter.h:73
An encapsulated private key.
Definition: key.h:27
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:73
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:235
An encapsulated public key.
Definition: pubkey.h:33
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:194
uint256 GetHash() const
Get the 256-bit hash of this public key.
Definition: pubkey.h:166
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:124
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 &vMasterKey, const std::vector< unsigned char > &vchCryptedSecret, const CPubKey &vchPubKey, CKey &key)
Definition: crypter.cpp:127
bool EncryptSecret(const CKeyingMaterial &vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256 &nIV, std::vector< unsigned char > &vchCiphertext)
Definition: crypter.cpp:107
bool DecryptSecret(const CKeyingMaterial &vMasterKey, const std::vector< unsigned char > &vchCiphertext, const uint256 &nIV, CKeyingMaterial &vchPlaintext)
Definition: crypter.cpp:117
const unsigned int WALLET_CRYPTO_IV_SIZE
Definition: crypter.h:15
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
Definition: crypter.h:61
const unsigned int WALLET_CRYPTO_SALT_SIZE
Definition: crypter.h:14
const unsigned int WALLET_CRYPTO_KEY_SIZE
Definition: crypter.h:13
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: secure.h:59
static int count
Definition: tests.c:41