crypter.h raw
1 // Copyright (c) 2009-2021 The Limenka 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 #ifndef LIMENKA_WALLET_CRYPTER_H
6 #define LIMENKA_WALLET_CRYPTER_H
7
8 #include <serialize.h>
9 #include <support/allocators/secure.h>
10 #include <script/signingprovider.h>
11
12
13 namespace wallet {
14 const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
15 const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
16 const unsigned int WALLET_CRYPTO_SALT_SIZE_V2 = 32;
17 const unsigned int WALLET_CRYPTO_IV_SIZE = 16;
18 const unsigned int WALLET_CRYPTO_HMAC_SIZE = 32;
19
20 /** Master key for wallet encryption */
21 class CMasterKey
22 {
23 public:
24 std::vector<unsigned char> vchCryptedKey;
25 std::vector<unsigned char> vchSalt;
26 //! 0 = EVP_sha512() (legacy, no HMAC)
27 //! 1 = scrypt() (reserved, never implemented)
28 //! 2 = PBKDF2-HMAC-SHA512 (with HMAC-SHA256 authenticated encryption)
29 unsigned int nDerivationMethod;
30 unsigned int nDeriveIterations;
31 //! Use this for more parameters to key derivation,
32 //! such as the various parameters to scrypt
33 std::vector<unsigned char> vchOtherDerivationParameters;
34
35 SERIALIZE_METHODS(CMasterKey, obj)
36 {
37 READWRITE(obj.vchCryptedKey, obj.vchSalt, obj.nDerivationMethod, obj.nDeriveIterations, obj.vchOtherDerivationParameters);
38 }
39
40 CMasterKey() : nDerivationMethod(2)
41 {
42 // New wallets use PBKDF2-HMAC-SHA512 with calibrated iterations
43 nDeriveIterations = 600000;
44 vchOtherDerivationParameters = std::vector<unsigned char>(0);
45 }
46
47 bool UsesAEAD() const { return nDerivationMethod >= 2; }
48 };
49
50 typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
51
52 namespace wallet_crypto_tests
53 {
54 class TestCrypter;
55 }
56
57 /** Encryption/decryption context with key information */
58 class CCrypter
59 {
60 friend class wallet_crypto_tests::TestCrypter; // for test access to chKey/chIV
61 private:
62 std::vector<unsigned char, secure_allocator<unsigned char>> vchKey;
63 std::vector<unsigned char, secure_allocator<unsigned char>> vchIV;
64 std::vector<unsigned char, secure_allocator<unsigned char>> vchHmacKey;
65 bool fKeySet;
66 bool fUseAEAD{false};
67
68 int BytesToKeySHA512AES(std::span<const unsigned char> salt, const SecureString& key_data, int count, unsigned char* key, unsigned char* iv) const;
69 int PBKDF2_SHA512_AES(std::span<const unsigned char> salt, const SecureString& key_data, int count, unsigned char* key, unsigned char* iv, unsigned char* hmac_key) const;
70
71 public:
72 bool SetKeyFromPassphrase(const SecureString& key_data, std::span<const unsigned char> salt, const unsigned int rounds, const unsigned int derivation_method);
73 bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const;
74 bool Decrypt(std::span<const unsigned char> ciphertext, CKeyingMaterial& plaintext) const;
75 bool SetKey(const CKeyingMaterial& new_key, std::span<const unsigned char> new_iv);
76
77 void CleanKey()
78 {
79 memory_cleanse(vchKey.data(), vchKey.size());
80 memory_cleanse(vchIV.data(), vchIV.size());
81 memory_cleanse(vchHmacKey.data(), vchHmacKey.size());
82 fKeySet = false;
83 fUseAEAD = false;
84 }
85
86 CCrypter()
87 {
88 fKeySet = false;
89 vchKey.resize(WALLET_CRYPTO_KEY_SIZE);
90 vchIV.resize(WALLET_CRYPTO_IV_SIZE);
91 vchHmacKey.resize(WALLET_CRYPTO_HMAC_SIZE);
92 }
93
94 ~CCrypter()
95 {
96 CleanKey();
97 }
98 };
99
100 bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
101 bool DecryptSecret(const CKeyingMaterial& master_key, std::span<const unsigned char> ciphertext, const uint256& iv, CKeyingMaterial& plaintext);
102 bool DecryptKey(const CKeyingMaterial& master_key, std::span<const unsigned char> crypted_secret, const CPubKey& pub_key, CKey& key);
103
104 // V2: AEAD-aware key encryption/decryption with random IV
105 bool EncryptSecretV2(const CKeyingMaterial& master_key, const CKeyingMaterial& plaintext, std::vector<unsigned char>& ciphertext);
106 bool DecryptSecretV2(const CKeyingMaterial& master_key, std::span<const unsigned char> ciphertext, uint256& iv_out, CKeyingMaterial& plaintext);
107 } // namespace wallet
108
109 #endif // LIMENKA_WALLET_CRYPTER_H
110