Update namespaces
[novacoin.git] / src / crypter.cpp
1 // Copyright (c) 2009-2012 The Bitcoin Developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include <openssl/aes.h>
6 #include <openssl/evp.h>
7
8 #include "crypter.h"
9
10 using namespace std;
11
12 //
13 //CMasterKey
14 //
15
16 CMasterKey::CMasterKey()
17 {
18     // 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M
19     // ie slightly lower than the lowest hardware we need bother supporting
20     nDeriveIterations = 25000;
21     nDerivationMethod = 0;
22     vchOtherDerivationParameters = vector<unsigned char>(0);
23 }
24
25 //
26 //CCrypter
27 //
28
29 bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
30 {
31     if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
32         return false;
33
34     int i = 0;
35     if (nDerivationMethod == 0)
36     {
37         i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
38                           (const unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
39     }
40
41     if (i != (int)WALLET_CRYPTO_KEY_SIZE)
42     {
43         OPENSSL_cleanse(&chKey, sizeof chKey);
44         OPENSSL_cleanse(&chIV, sizeof chIV);
45         return false;
46     }
47
48     fKeySet = true;
49     return true;
50 }
51
52 bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const vector<unsigned char>& chNewIV)
53 {
54     if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
55         return false;
56
57     memcpy(&chKey[0], &chNewKey[0], sizeof chKey);
58     memcpy(&chIV[0], &chNewIV[0], sizeof chIV);
59
60     fKeySet = true;
61     return true;
62 }
63
64 bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, vector<unsigned char> &vchCiphertext)
65 {
66     if (!fKeySet)
67         return false;
68
69     // max ciphertext len for a n bytes of plaintext is
70     // n + AES_BLOCK_SIZE - 1 bytes
71     int nLen = vchPlaintext.size();
72     int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
73     vchCiphertext = vector<unsigned char> (nCLen);
74
75     EVP_CIPHER_CTX ctx;
76
77     bool fOk = true;
78
79     EVP_CIPHER_CTX_init(&ctx);
80     if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
81     if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
82     if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
83     EVP_CIPHER_CTX_cleanup(&ctx);
84
85     if (!fOk) return false;
86
87     vchCiphertext.resize(nCLen + nFLen);
88     return true;
89 }
90
91 bool CCrypter::Decrypt(const vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext)
92 {
93     if (!fKeySet)
94         return false;
95
96     // plaintext will always be equal to or lesser than length of ciphertext
97     int nLen = vchCiphertext.size();
98     int nPLen = nLen, nFLen = 0;
99
100     vchPlaintext = CKeyingMaterial(nPLen);
101
102     EVP_CIPHER_CTX ctx;
103
104     bool fOk = true;
105
106     EVP_CIPHER_CTX_init(&ctx);
107     if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
108     if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
109     if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
110     EVP_CIPHER_CTX_cleanup(&ctx);
111
112     if (!fOk) return false;
113
114     vchPlaintext.resize(nPLen + nFLen);
115     return true;
116 }
117
118 void CCrypter::CleanKey()
119 {
120     OPENSSL_cleanse(&chKey, sizeof chKey);
121     OPENSSL_cleanse(&chIV, sizeof chIV);
122     fKeySet = false;
123 }
124
125 CCrypter::CCrypter()
126 {
127     fKeySet = false;
128
129     // 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)
130     // Note that this does nothing about suspend-to-disk (which will put all our key data on disk)
131     // 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.
132     LockedPageManager::instance.LockRange(&chKey[0], sizeof chKey);
133     LockedPageManager::instance.LockRange(&chIV[0], sizeof chIV);
134 }
135
136 CCrypter::~CCrypter()
137 {
138     CleanKey();
139
140     LockedPageManager::instance.UnlockRange(&chKey[0], sizeof chKey);
141     LockedPageManager::instance.UnlockRange(&chIV[0], sizeof chIV);
142 }
143
144 bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, vector<unsigned char> &vchCiphertext)
145 {
146     CCrypter cKeyCrypter;
147     vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
148     memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
149     if(!cKeyCrypter.SetKey(vMasterKey, chIV))
150         return false;
151     return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext);
152 }
153
154 bool DecryptSecret(const CKeyingMaterial& vMasterKey, const vector<unsigned char>& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext)
155 {
156     CCrypter cKeyCrypter;
157     vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
158     memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
159     if(!cKeyCrypter.SetKey(vMasterKey, chIV))
160         return false;
161     return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
162 }