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