// Copyright (c) 2009-2012 The Bitcoin Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef __CRYPTER_H__ #define __CRYPTER_H__ #include "allocators.h" /* for SecureString */ #include "key.h" #include "serialize.h" const unsigned int WALLET_CRYPTO_KEY_SIZE = 32; const unsigned int WALLET_CRYPTO_SALT_SIZE = 8; /* Private key encryption is done based on a CMasterKey, which holds a salt and random encryption key. CMasterKeys are encrypted using AES-256-CBC using a key derived using derivation method nDerivationMethod (0 == EVP_sha512()) and derivation iterations nDeriveIterations. vchOtherDerivationParameters is provided for alternative algorithms which may require more parameters (such as scrypt). Wallet Private Keys are then encrypted using AES-256-CBC with the double-sha256 of the public key as the IV, and the master key's key as the encryption key (see keystore.[ch]). */ /** Master key for wallet encryption */ class CMasterKey { public: std::vector vchCryptedKey; std::vector vchSalt; // 0 = EVP_sha512() // 1 = scrypt() unsigned int nDerivationMethod; unsigned int nDeriveIterations; // Use this for more parameters to key derivation, // such as the various parameters to scrypt std::vector vchOtherDerivationParameters; IMPLEMENT_SERIALIZE ( READWRITE(vchCryptedKey); READWRITE(vchSalt); READWRITE(nDerivationMethod); READWRITE(nDeriveIterations); READWRITE(vchOtherDerivationParameters); ) CMasterKey() { // 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M // ie slightly lower than the lowest hardware we need bother supporting nDeriveIterations = 25000; nDerivationMethod = 0; vchOtherDerivationParameters = std::vector(0); } }; typedef std::vector > CKeyingMaterial; /** Encryption/decryption context with key information */ class CCrypter { private: unsigned char chKey[WALLET_CRYPTO_KEY_SIZE]; unsigned char chIV[WALLET_CRYPTO_KEY_SIZE]; bool fKeySet; public: bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod); bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector &vchCiphertext); bool Decrypt(const std::vector& vchCiphertext, CKeyingMaterial& vchPlaintext); bool SetKey(const CKeyingMaterial& chNewKey, const std::vector& chNewIV); void CleanKey() { OPENSSL_cleanse(&chKey, sizeof chKey); OPENSSL_cleanse(&chIV, sizeof chIV); fKeySet = false; } CCrypter() { fKeySet = false; // Try to keep the key data out of swap (and be a bit over-careful to keep the IV that we don't even use out of swap) // Note that this does nothing about suspend-to-disk (which will put all our key data on disk) // Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process. LockedPageManager::instance.LockRange(&chKey[0], sizeof chKey); LockedPageManager::instance.LockRange(&chIV[0], sizeof chIV); } ~CCrypter() { CleanKey(); LockedPageManager::instance.UnlockRange(&chKey[0], sizeof chKey); LockedPageManager::instance.UnlockRange(&chIV[0], sizeof chIV); } }; bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext); bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector &vchCiphertext, const uint256& nIV, CSecret &vchPlaintext); #endif