LCOV - code coverage report
Current view: top level - src/wallet - crypter.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 132 140 94.3 %
Date: 2015-10-12 22:39:14 Functions: 17 17 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2009-2013 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             : #include "crypter.h"
       6             : 
       7             : #include "script/script.h"
       8             : #include "script/standard.h"
       9             : #include "util.h"
      10             : 
      11             : #include <string>
      12             : #include <vector>
      13             : #include <boost/foreach.hpp>
      14             : #include <openssl/aes.h>
      15             : #include <openssl/evp.h>
      16             : 
      17           5 : bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
      18             : {
      19          10 :     if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
      20             :         return false;
      21             : 
      22           5 :     int i = 0;
      23           5 :     if (nDerivationMethod == 0)
      24           5 :         i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
      25          15 :                           (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
      26             : 
      27           5 :     if (i != (int)WALLET_CRYPTO_KEY_SIZE)
      28             :     {
      29           0 :         memory_cleanse(chKey, sizeof(chKey));
      30           0 :         memory_cleanse(chIV, sizeof(chIV));
      31           0 :         return false;
      32             :     }
      33             : 
      34           5 :     fKeySet = true;
      35           5 :     return true;
      36             : }
      37             : 
      38         258 : bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
      39             : {
      40         774 :     if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
      41             :         return false;
      42             : 
      43         258 :     memcpy(&chKey[0], &chNewKey[0], sizeof chKey);
      44         258 :     memcpy(&chIV[0], &chNewIV[0], sizeof chIV);
      45             : 
      46         258 :     fKeySet = true;
      47         258 :     return true;
      48             : }
      49             : 
      50          66 : bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext)
      51             : {
      52          66 :     if (!fKeySet)
      53             :         return false;
      54             : 
      55             :     // max ciphertext len for a n bytes of plaintext is
      56             :     // n + AES_BLOCK_SIZE - 1 bytes
      57         132 :     int nLen = vchPlaintext.size();
      58          66 :     int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
      59         198 :     vchCiphertext = std::vector<unsigned char> (nCLen);
      60             : 
      61             :     EVP_CIPHER_CTX ctx;
      62             : 
      63          66 :     bool fOk = true;
      64             : 
      65          66 :     EVP_CIPHER_CTX_init(&ctx);
      66          66 :     if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
      67          66 :     if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
      68          66 :     if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
      69          66 :     EVP_CIPHER_CTX_cleanup(&ctx);
      70             : 
      71          66 :     if (!fOk) return false;
      72             : 
      73          66 :     vchCiphertext.resize(nCLen + nFLen);
      74             :     return true;
      75             : }
      76             : 
      77         195 : bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext)
      78             : {
      79         195 :     if (!fKeySet)
      80             :         return false;
      81             : 
      82             :     // plaintext will always be equal to or lesser than length of ciphertext
      83         390 :     int nLen = vchCiphertext.size();
      84         195 :     int nPLen = nLen, nFLen = 0;
      85             : 
      86         585 :     vchPlaintext = CKeyingMaterial(nPLen);
      87             : 
      88             :     EVP_CIPHER_CTX ctx;
      89             : 
      90         195 :     bool fOk = true;
      91             : 
      92         195 :     EVP_CIPHER_CTX_init(&ctx);
      93         195 :     if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
      94         195 :     if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
      95         195 :     if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
      96         195 :     EVP_CIPHER_CTX_cleanup(&ctx);
      97             : 
      98         195 :     if (!fOk) return false;
      99             : 
     100         195 :     vchPlaintext.resize(nPLen + nFLen);
     101             :     return true;
     102             : }
     103             : 
     104             : 
     105          65 : static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
     106             : {
     107          65 :     CCrypter cKeyCrypter;
     108         130 :     std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
     109          65 :     memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
     110          65 :     if(!cKeyCrypter.SetKey(vMasterKey, chIV))
     111             :         return false;
     112         130 :     return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
     113             : }
     114             : 
     115         193 : static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
     116             : {
     117         193 :     CCrypter cKeyCrypter;
     118         386 :     std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
     119         193 :     memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
     120         193 :     if(!cKeyCrypter.SetKey(vMasterKey, chIV))
     121             :         return false;
     122         386 :     return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
     123             : }
     124             : 
     125         193 : static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
     126             : {
     127             :     CKeyingMaterial vchSecret;
     128         193 :     if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
     129             :         return false;
     130             : 
     131         386 :     if (vchSecret.size() != 32)
     132             :         return false;
     133             : 
     134         386 :     key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
     135         193 :     return key.VerifyPubKey(vchPubKey);
     136             : }
     137             : 
     138          91 : bool CCryptoKeyStore::SetCrypted()
     139             : {
     140          91 :     LOCK(cs_KeyStore);
     141          91 :     if (fUseCrypto)
     142             :         return true;
     143           2 :     if (!mapKeys.empty())
     144             :         return false;
     145           1 :     fUseCrypto = true;
     146           1 :     return true;
     147             : }
     148             : 
     149           2 : bool CCryptoKeyStore::Lock()
     150             : {
     151           2 :     if (!SetCrypted())
     152             :         return false;
     153             : 
     154             :     {
     155           2 :         LOCK(cs_KeyStore);
     156           2 :         vMasterKey.clear();
     157             :     }
     158             : 
     159           2 :     NotifyStatusChanged(this);
     160           2 :     return true;
     161             : }
     162             : 
     163           2 : bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
     164             : {
     165             :     {
     166           2 :         LOCK(cs_KeyStore);
     167           2 :         if (!SetCrypted())
     168             :             return false;
     169             : 
     170           2 :         bool keyPass = false;
     171           2 :         bool keyFail = false;
     172           4 :         CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
     173          92 :         for (; mi != mapCryptedKeys.end(); ++mi)
     174             :         {
     175          43 :             const CPubKey &vchPubKey = (*mi).second.first;
     176          43 :             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
     177             :             CKey key;
     178          43 :             if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
     179             :             {
     180             :                 keyFail = true;
     181             :                 break;
     182             :             }
     183          43 :             keyPass = true;
     184          43 :             if (fDecryptionThoroughlyChecked)
     185             :                 break;
     186             :         }
     187           2 :         if (keyPass && keyFail)
     188             :         {
     189           0 :             LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
     190           0 :             assert(false);
     191             :         }
     192           2 :         if (keyFail || !keyPass)
     193             :             return false;
     194           2 :         vMasterKey = vMasterKeyIn;
     195           2 :         fDecryptionThoroughlyChecked = true;
     196             :     }
     197           2 :     NotifyStatusChanged(this);
     198           2 :     return true;
     199             : }
     200             : 
     201        3991 : bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
     202             : {
     203             :     {
     204        3991 :         LOCK(cs_KeyStore);
     205        3991 :         if (!IsCrypted())
     206        3947 :             return CBasicKeyStore::AddKeyPubKey(key, pubkey);
     207             : 
     208          44 :         if (IsLocked())
     209             :             return false;
     210             : 
     211             :         std::vector<unsigned char> vchCryptedSecret;
     212         132 :         CKeyingMaterial vchSecret(key.begin(), key.end());
     213          44 :         if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
     214             :             return false;
     215             : 
     216          44 :         if (!AddCryptedKey(pubkey, vchCryptedSecret))
     217             :             return false;
     218             :     }
     219          44 :     return true;
     220             : }
     221             : 
     222             : 
     223          87 : bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
     224             : {
     225             :     {
     226          87 :         LOCK(cs_KeyStore);
     227          87 :         if (!SetCrypted())
     228           0 :             return false;
     229             : 
     230         348 :         mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
     231             :     }
     232          87 :     return true;
     233             : }
     234             : 
     235        1278 : bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
     236             : {
     237             :     {
     238        1278 :         LOCK(cs_KeyStore);
     239        1278 :         if (!IsCrypted())
     240        1128 :             return CBasicKeyStore::GetKey(address, keyOut);
     241             : 
     242         300 :         CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
     243         300 :         if (mi != mapCryptedKeys.end())
     244             :         {
     245         150 :             const CPubKey &vchPubKey = (*mi).second.first;
     246         150 :             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
     247         150 :             return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
     248             :         }
     249             :     }
     250           0 :     return false;
     251             : }
     252             : 
     253         543 : bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
     254             : {
     255             :     {
     256         543 :         LOCK(cs_KeyStore);
     257         543 :         if (!IsCrypted())
     258         284 :             return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
     259             : 
     260         518 :         CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
     261         518 :         if (mi != mapCryptedKeys.end())
     262             :         {
     263         259 :             vchPubKeyOut = (*mi).second.first;
     264         259 :             return true;
     265             :         }
     266             :         // Check for watch-only pubkeys
     267           0 :         return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
     268             :     }
     269             :     return false;
     270             : }
     271             : 
     272           1 : bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
     273             : {
     274             :     {
     275           1 :         LOCK(cs_KeyStore);
     276           2 :         if (!mapCryptedKeys.empty() || IsCrypted())
     277             :             return false;
     278             : 
     279           1 :         fUseCrypto = true;
     280         111 :         BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
     281             :         {
     282          21 :             const CKey &key = mKey.second;
     283          21 :             CPubKey vchPubKey = key.GetPubKey();
     284          63 :             CKeyingMaterial vchSecret(key.begin(), key.end());
     285             :             std::vector<unsigned char> vchCryptedSecret;
     286          21 :             if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
     287             :                 return false;
     288          21 :             if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
     289             :                 return false;
     290             :         }
     291           1 :         mapKeys.clear();
     292             :     }
     293           1 :     return true;
     294         288 : }

Generated by: LCOV version 1.11