LCOV - code coverage report
Current view: top level - src - crypter.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 125 132 94.7 %
Date: 2025-02-23 09:33:43 Functions: 18 18 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2009-2013 The Bitcoin developers
       2             : // Copyright (c) 2017-2021 The PIVX Core developers
       3             : // Distributed under the MIT/X11 software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include "crypter.h"
       7             : 
       8             : #include "crypto/aes.h"
       9             : #include "crypto/sha512.h"
      10             : #include "script/script.h"
      11             : #include "script/standard.h"
      12             : #include "uint256.h"
      13             : 
      14         122 : int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char* key, unsigned char* iv) const
      15             : {
      16             :     // This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc
      17             :     // cipher and sha512 message digest. Because sha512's output size (64b) is
      18             :     // greater than the aes256 block size (16b) + aes256 key size (32b),
      19             :     // there's no need to process more than once (D_0).
      20             : 
      21         122 :     if (!count || !key || !iv)
      22             :         return 0;
      23             : 
      24         122 :     unsigned char buf[CSHA512::OUTPUT_SIZE];
      25         122 :     CSHA512 di;
      26             : 
      27         122 :     di.Write((const unsigned char*)strKeyData.c_str(), strKeyData.size());
      28         122 :     di.Write(chSalt.data(), chSalt.size());
      29         122 :     di.Finalize(buf);
      30             : 
      31     8326520 :     for (int i = 0; i != count - 1; i++)
      32     8326400 :         di.Reset().Write(buf, sizeof(buf)).Finalize(buf);
      33             : 
      34         122 :     memcpy(key, buf, WALLET_CRYPTO_KEY_SIZE);
      35         122 :     memcpy(iv, buf + WALLET_CRYPTO_KEY_SIZE, WALLET_CRYPTO_IV_SIZE);
      36         122 :     memory_cleanse(buf, sizeof(buf));
      37             :     return WALLET_CRYPTO_KEY_SIZE;
      38             : }
      39             : 
      40         122 : bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
      41             : {
      42         122 :     if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
      43             :         return false;
      44             : 
      45         122 :     int i = 0;
      46         122 :     if (nDerivationMethod == 0)
      47         122 :         i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data());
      48             : 
      49         122 :     if (i != (int)WALLET_CRYPTO_KEY_SIZE) {
      50           0 :         memory_cleanse(vchKey.data(), vchKey.size());
      51           0 :         memory_cleanse(vchIV.data(), vchIV.size());
      52           0 :         return false;
      53             :     }
      54             : 
      55         122 :     fKeySet = true;
      56         122 :     return true;
      57             : }
      58             : 
      59        4997 : bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
      60             : {
      61        4997 :     if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_IV_SIZE)
      62             :         return false;
      63             : 
      64        4995 :     memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
      65        4995 :     memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());
      66             : 
      67        4995 :     fKeySet = true;
      68        4995 :     return true;
      69             : }
      70             : 
      71        5191 : bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char>& vchCiphertext) const
      72             : {
      73        5191 :     if (!fKeySet)
      74             :         return false;
      75             : 
      76             :     // max ciphertext len for a n bytes of plaintext is
      77             :     // n + AES_BLOCKSIZE bytes
      78        5191 :     vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
      79             : 
      80       10382 :     AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true);
      81        5191 :     size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), vchCiphertext.data());
      82        5191 :     if (nLen < vchPlaintext.size())
      83             :         return false;
      84        5191 :     vchCiphertext.resize(nLen);
      85             :     return true;
      86             : }
      87             : 
      88        6610 : bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
      89             : {
      90        6610 :     if (!fKeySet)
      91             :         return false;
      92             : 
      93             :     // plaintext will always be equal to or lesser than length of ciphertext
      94        6610 :     int nLen = vchCiphertext.size();
      95        6610 :     vchPlaintext.resize(nLen);
      96       13220 :     AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
      97        6610 :     nLen = dec.Decrypt(vchCiphertext.data(), vchCiphertext.size(), &vchPlaintext[0]);
      98        6610 :     if (nLen == 0)
      99             :         return false;
     100        6502 :     vchPlaintext.resize(nLen);
     101             :     return true;
     102             : }
     103             : 
     104        1850 : bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial& vchPlaintext, const uint256& nIV, std::vector<unsigned char>& vchCiphertext)
     105             : {
     106        1850 :     CCrypter cKeyCrypter;
     107        3700 :     std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
     108        1850 :     memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
     109        1850 :     if (!cKeyCrypter.SetKey(vMasterKey, chIV))
     110             :         return false;
     111        1850 :     return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
     112             : }
     113             : 
     114        3147 : bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
     115             : {
     116        3147 :     CCrypter cKeyCrypter;
     117        6294 :     std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
     118        3147 :     memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
     119        3147 :     if (!cKeyCrypter.SetKey(vMasterKey, chIV))
     120             :         return false;
     121        3145 :     return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
     122             : }
     123             : 
     124        3035 : bool CCryptoKeyStore::DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
     125             : {
     126        6070 :     CKeyingMaterial vchSecret;
     127        3035 :     if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
     128             :         return false;
     129             : 
     130        3034 :     if (vchSecret.size() != 32)
     131             :         return false;
     132             : 
     133        3034 :     key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
     134        3034 :     return key.VerifyPubKey(vchPubKey);
     135             : }
     136             : 
     137        2501 : bool CCryptoKeyStore::SetCrypted()
     138             : {
     139        2501 :     LOCK(cs_KeyStore);
     140        2501 :     if (fUseCrypto)
     141             :         return true;
     142           1 :     if (!mapKeys.empty() && !mapSaplingSpendingKeys.empty())
     143             :         return false;
     144           1 :     fUseCrypto = true;
     145           1 :     return true;
     146             : }
     147             : 
     148      131709 : bool CCryptoKeyStore::IsLocked() const
     149             : {
     150      131709 :     if (!IsCrypted()) {
     151             :         return false;
     152             :     }
     153        2344 :     return WITH_LOCK(cs_KeyStore, return vMasterKey.empty());
     154             : }
     155             : 
     156       19658 : bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey& pubkey)
     157             : {
     158       39316 :     LOCK(cs_KeyStore);
     159       19658 :     if (!IsCrypted()) {
     160       19651 :         return CBasicKeyStore::AddKeyPubKey(key, pubkey);
     161             :     }
     162             : 
     163           7 :     if (IsLocked()) {
     164             :         return false;
     165             :     }
     166             : 
     167       19665 :     std::vector<unsigned char> vchCryptedSecret;
     168          21 :     CKeyingMaterial vchSecret(key.begin(), key.end());
     169           7 :     if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
     170             :         return false;
     171             :     }
     172             : 
     173           7 :     if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
     174           0 :         return false;
     175             :     }
     176             :     return true;
     177             : }
     178             : 
     179     6969341 : bool CCryptoKeyStore::HaveKey(const CKeyID& address) const
     180             : {
     181    13938662 :     LOCK(cs_KeyStore);
     182     6969341 :     if (!IsCrypted()) {
     183     6966568 :         return CBasicKeyStore::HaveKey(address);
     184             :     }
     185        5548 :     return mapCryptedKeys.count(address) > 0;
     186             : }
     187             : 
     188        2348 : bool CCryptoKeyStore::AddCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret)
     189             : {
     190        4696 :     LOCK(cs_KeyStore);
     191        2348 :     if (!SetCrypted()) {
     192             :         return false;
     193             :     }
     194             : 
     195        4696 :     mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
     196        2348 :     return true;
     197             : }
     198             : 
     199     3757999 : bool CCryptoKeyStore::GetKey(const CKeyID& address, CKey& keyOut) const
     200             : {
     201     7515998 :     LOCK(cs_KeyStore);
     202     3757999 :     if (!IsCrypted()) {
     203     3756357 :         return CBasicKeyStore::GetKey(address, keyOut);
     204             :     }
     205             : 
     206        1639 :     CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
     207        1639 :     if (mi != mapCryptedKeys.end()) {
     208        1639 :         const CPubKey& vchPubKey = (*mi).second.first;
     209        1639 :         const std::vector<unsigned char>& vchCryptedSecret = (*mi).second.second;
     210        1639 :         return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
     211             :     }
     212             :     return false;
     213             : }
     214             : 
     215     3532913 : bool CCryptoKeyStore::GetPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) const
     216             : {
     217     7065826 :     LOCK(cs_KeyStore);
     218     3532913 :     if (!IsCrypted()) {
     219     3532383 :         return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
     220             :     }
     221             : 
     222         532 :     CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
     223         532 :     if (mi != mapCryptedKeys.end()) {
     224         532 :         vchPubKeyOut = (*mi).second.first;
     225         532 :         return true;
     226             :     }
     227             :     // Check for watch-only pubkeys
     228           0 :     return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
     229             : }
     230             : 
     231           8 : std::set<CKeyID> CCryptoKeyStore::GetKeys() const
     232             : {
     233          16 :     LOCK(cs_KeyStore);
     234           8 :     if (!IsCrypted()) {
     235           7 :         return CBasicKeyStore::GetKeys();
     236             :     }
     237           9 :     std::set<CKeyID> set_address;
     238         613 :     for (const auto& mi : mapCryptedKeys) {
     239         612 :         set_address.insert(mi.first);
     240             :     }
     241           2 :     return set_address;
     242             : }
     243             : 
     244           7 : bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
     245             : {
     246          14 :     LOCK(cs_KeyStore);
     247           7 :     if (!mapCryptedKeys.empty() || IsCrypted())
     248           0 :         return false;
     249             : 
     250           7 :     fUseCrypto = true;
     251         785 :     for (KeyMap::value_type& mKey : mapKeys) {
     252         778 :         const CKey& key = mKey.second;
     253         778 :         CPubKey vchPubKey = key.GetPubKey();
     254        2334 :         CKeyingMaterial vchSecret(key.begin(), key.end());
     255        1556 :         std::vector<unsigned char> vchCryptedSecret;
     256         778 :         if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
     257           0 :             return false;
     258         778 :         if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
     259             :             return false;
     260             :     }
     261           7 :     mapKeys.clear();
     262           7 :     return true;
     263             : }

Generated by: LCOV version 1.14