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