crypter.h raw

   1  // Copyright (c) 2009-present 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  #ifndef BITCOIN_WALLET_CRYPTER_H
   6  #define BITCOIN_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_IV_SIZE = 16;
  17  
  18  /**
  19   * Private key encryption is done based on a CMasterKey,
  20   * which holds a salt and random encryption key.
  21   *
  22   * CMasterKeys are encrypted using AES-256-CBC using a key
  23   * derived using derivation method nDerivationMethod
  24   * (0 == EVP_sha512()) and derivation iterations nDeriveIterations.
  25   * vchOtherDerivationParameters is provided for alternative algorithms
  26   * which may require more parameters.
  27   *
  28   * Wallet Private Keys are then encrypted using AES-256-CBC
  29   * with the double-sha256 of the public key as the IV, and the
  30   * master key's key as the encryption key (see keystore.[ch]).
  31   */
  32  
  33  /** Master key for wallet encryption */
  34  class CMasterKey
  35  {
  36  public:
  37      std::vector<unsigned char> vchCryptedKey;
  38      std::vector<unsigned char> vchSalt;
  39      //! 0 = EVP_sha512()
  40      unsigned int nDerivationMethod;
  41      unsigned int nDeriveIterations;
  42      //! Use this for more parameters to key derivation (currently unused)
  43      std::vector<unsigned char> vchOtherDerivationParameters;
  44  
  45      //! Default/minimum number of key derivation rounds
  46      // 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M
  47      // ie slightly lower than the lowest hardware we need bother supporting
  48      static constexpr unsigned int DEFAULT_DERIVE_ITERATIONS = 25000;
  49  
  50      SERIALIZE_METHODS(CMasterKey, obj)
  51      {
  52          READWRITE(obj.vchCryptedKey, obj.vchSalt, obj.nDerivationMethod, obj.nDeriveIterations, obj.vchOtherDerivationParameters);
  53      }
  54  
  55      CMasterKey()
  56      {
  57          nDeriveIterations = DEFAULT_DERIVE_ITERATIONS;
  58          nDerivationMethod = 0;
  59          vchOtherDerivationParameters = std::vector<unsigned char>(0);
  60      }
  61  };
  62  
  63  typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
  64  
  65  namespace wallet_crypto_tests
  66  {
  67      class TestCrypter;
  68  }
  69  
  70  /** Encryption/decryption context with key information */
  71  class CCrypter
  72  {
  73  friend class wallet_crypto_tests::TestCrypter; // for test access to chKey/chIV
  74  private:
  75      std::vector<unsigned char, secure_allocator<unsigned char>> vchKey;
  76      std::vector<unsigned char, secure_allocator<unsigned char>> vchIV;
  77      bool fKeySet;
  78  
  79      int BytesToKeySHA512AES(std::span<const unsigned char> salt, const SecureString& key_data, int count, unsigned char* key, unsigned char* iv) const;
  80  
  81  public:
  82      bool SetKeyFromPassphrase(const SecureString& key_data, std::span<const unsigned char> salt, unsigned int rounds, unsigned int derivation_method);
  83      bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const;
  84      bool Decrypt(std::span<const unsigned char> ciphertext, CKeyingMaterial& plaintext) const;
  85      bool SetKey(const CKeyingMaterial& new_key, std::span<const unsigned char> new_iv);
  86  
  87      void CleanKey()
  88      {
  89          memory_cleanse(vchKey.data(), vchKey.size());
  90          memory_cleanse(vchIV.data(), vchIV.size());
  91          fKeySet = false;
  92      }
  93  
  94      CCrypter()
  95      {
  96          fKeySet = false;
  97          vchKey.resize(WALLET_CRYPTO_KEY_SIZE);
  98          vchIV.resize(WALLET_CRYPTO_IV_SIZE);
  99      }
 100  
 101      ~CCrypter()
 102      {
 103          CleanKey();
 104      }
 105  };
 106  
 107  bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
 108  bool DecryptSecret(const CKeyingMaterial& master_key, std::span<const unsigned char> ciphertext, const uint256& iv, CKeyingMaterial& plaintext);
 109  bool DecryptKey(const CKeyingMaterial& master_key, std::span<const unsigned char> crypted_secret, const CPubKey& pub_key, CKey& key);
 110  } // namespace wallet
 111  
 112  #endif // BITCOIN_WALLET_CRYPTER_H
 113