aboutsummaryrefslogtreecommitdiff
path: root/src/crypter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypter.cpp')
-rw-r--r--src/crypter.cpp228
1 files changed, 196 insertions, 32 deletions
diff --git a/src/crypter.cpp b/src/crypter.cpp
index 4f37575a6..00f7f7f1b 100644
--- a/src/crypter.cpp
+++ b/src/crypter.cpp
@@ -1,28 +1,24 @@
-// Copyright (c) 2009-2012 The Bitcoin Developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2009-2013 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "crypter.h"
+
+#include "script/script.h"
+#include "script/standard.h"
+#include "util.h"
+
+#include <string>
+#include <vector>
+#include <boost/foreach.hpp>
#include <openssl/aes.h>
#include <openssl/evp.h>
-#include <vector>
-#include <string>
-#ifdef WIN32
-#include <windows.h>
-#endif
-
-#include "crypter.h"
bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
{
if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
return false;
- // Try to keep the keydata 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.
- mlock(&chKey[0], sizeof chKey);
- mlock(&chIV[0], sizeof chIV);
-
int i = 0;
if (nDerivationMethod == 0)
i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
@@ -30,8 +26,8 @@ bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::v
if (i != (int)WALLET_CRYPTO_KEY_SIZE)
{
- memset(&chKey, 0, sizeof chKey);
- memset(&chIV, 0, sizeof chIV);
+ OPENSSL_cleanse(chKey, sizeof(chKey));
+ OPENSSL_cleanse(chIV, sizeof(chIV));
return false;
}
@@ -44,12 +40,6 @@ bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigne
if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
return false;
- // Try to keep the keydata 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.
- mlock(&chKey[0], sizeof chKey);
- mlock(&chIV[0], sizeof chIV);
-
memcpy(&chKey[0], &chNewKey[0], sizeof chKey);
memcpy(&chIV[0], &chNewIV[0], sizeof chIV);
@@ -73,9 +63,9 @@ bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned
bool fOk = true;
EVP_CIPHER_CTX_init(&ctx);
- if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV);
- if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen);
- if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0])+nCLen, &nFLen);
+ if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
+ if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
+ if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
EVP_CIPHER_CTX_cleanup(&ctx);
if (!fOk) return false;
@@ -100,9 +90,9 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
bool fOk = true;
EVP_CIPHER_CTX_init(&ctx);
- if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV);
- if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen);
- if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0])+nPLen, &nFLen);
+ if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
+ if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
+ if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
EVP_CIPHER_CTX_cleanup(&ctx);
if (!fOk) return false;
@@ -112,17 +102,17 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
}
-bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
+bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false;
- return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext);
+ return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
}
-bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext)
+bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
@@ -131,3 +121,177 @@ bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned
return false;
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
}
+
+bool CCryptoKeyStore::SetCrypted()
+{
+ LOCK(cs_KeyStore);
+ if (fUseCrypto)
+ return true;
+ if (!mapKeys.empty())
+ return false;
+ fUseCrypto = true;
+ return true;
+}
+
+bool CCryptoKeyStore::Lock()
+{
+ if (!SetCrypted())
+ return false;
+
+ {
+ LOCK(cs_KeyStore);
+ vMasterKey.clear();
+ }
+
+ NotifyStatusChanged(this);
+ return true;
+}
+
+bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!SetCrypted())
+ return false;
+
+ bool keyPass = false;
+ bool keyFail = false;
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
+ for (; mi != mapCryptedKeys.end(); ++mi)
+ {
+ const CPubKey &vchPubKey = (*mi).second.first;
+ const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
+ CKeyingMaterial vchSecret;
+ if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
+ {
+ keyFail = true;
+ break;
+ }
+ if (vchSecret.size() != 32)
+ {
+ keyFail = true;
+ break;
+ }
+ CKey key;
+ key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
+ if (key.GetPubKey() != vchPubKey)
+ {
+ keyFail = true;
+ break;
+ }
+ keyPass = true;
+ if (fDecryptionThoroughlyChecked)
+ break;
+ }
+ if (keyPass && keyFail)
+ {
+ LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.");
+ assert(false);
+ }
+ if (keyFail || !keyPass)
+ return false;
+ vMasterKey = vMasterKeyIn;
+ fDecryptionThoroughlyChecked = true;
+ }
+ NotifyStatusChanged(this);
+ return true;
+}
+
+bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!IsCrypted())
+ return CBasicKeyStore::AddKeyPubKey(key, pubkey);
+
+ if (IsLocked())
+ return false;
+
+ std::vector<unsigned char> vchCryptedSecret;
+ CKeyingMaterial vchSecret(key.begin(), key.end());
+ if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
+ return false;
+
+ if (!AddCryptedKey(pubkey, vchCryptedSecret))
+ return false;
+ }
+ return true;
+}
+
+
+bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!SetCrypted())
+ return false;
+
+ mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
+ }
+ return true;
+}
+
+bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!IsCrypted())
+ return CBasicKeyStore::GetKey(address, keyOut);
+
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
+ if (mi != mapCryptedKeys.end())
+ {
+ const CPubKey &vchPubKey = (*mi).second.first;
+ const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
+ CKeyingMaterial vchSecret;
+ if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
+ return false;
+ if (vchSecret.size() != 32)
+ return false;
+ keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!IsCrypted())
+ return CKeyStore::GetPubKey(address, vchPubKeyOut);
+
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
+ if (mi != mapCryptedKeys.end())
+ {
+ vchPubKeyOut = (*mi).second.first;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!mapCryptedKeys.empty() || IsCrypted())
+ return false;
+
+ fUseCrypto = true;
+ BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
+ {
+ const CKey &key = mKey.second;
+ CPubKey vchPubKey = key.GetPubKey();
+ CKeyingMaterial vchSecret(key.begin(), key.end());
+ std::vector<unsigned char> vchCryptedSecret;
+ if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
+ return false;
+ if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
+ return false;
+ }
+ mapKeys.clear();
+ }
+ return true;
+}