PRCYCoin  2.0.0.7rc1
P2P Digital Currency
crypto_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014 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 "random.h"
6 #include "utilstrencodings.h"
7 #include "test/test_prcycoin.h"
8 #include "crypter.h"
9 
10 #include <vector>
11 
12 #include <boost/test/unit_test.hpp>
13 #include <openssl/aes.h>
14 #include <openssl/evp.h>
15 
16 BOOST_FIXTURE_TEST_SUITE(wallet_crypto, BasicTestingSetup)
17 
18 bool OldSetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod, unsigned char* chKey, unsigned char* chIV)
19 {
20  if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
21  return false;
22 
23  int i = 0;
24  if (nDerivationMethod == 0)
25  i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
26  (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
27 
28  if (i != (int)WALLET_CRYPTO_KEY_SIZE)
29  {
30  memory_cleanse(chKey, sizeof(chKey));
31  memory_cleanse(chIV, sizeof(chIV));
32  return false;
33  }
34  return true;
35 }
36 
37 bool OldEncrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext, const unsigned char chKey[32], const unsigned char chIV[16])
38 {
39  // max ciphertext len for a n bytes of plaintext is
40  // n + AES_BLOCK_SIZE - 1 bytes
41  int nLen = vchPlaintext.size();
42  int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
43  vchCiphertext = std::vector<unsigned char> (nCLen);
44 
45  EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
46 
47  bool fOk = true;
48 
49  EVP_CIPHER_CTX_init(ctx);
50  if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
51  if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
52  if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
53  EVP_CIPHER_CTX_cleanup(ctx);
54 
55  if (!fOk) return false;
56 
57  vchCiphertext.resize(nCLen + nFLen);
58  return true;
59 }
60 
61 bool OldDecrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext, const unsigned char chKey[32], const unsigned char chIV[16])
62 {
63  // plaintext will always be equal to or lesser than length of ciphertext
64  int nLen = vchCiphertext.size();
65  int nPLen = nLen, nFLen = 0;
66 
67  vchPlaintext = CKeyingMaterial(nPLen);
68 
69  EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
70 
71  bool fOk = true;
72 
73  EVP_CIPHER_CTX_init(ctx);
74  if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
75  if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
76  if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
77  EVP_CIPHER_CTX_cleanup(ctx);
78 
79  if (!fOk) return false;
80 
81  vchPlaintext.resize(nPLen + nFLen);
82  return true;
83 }
84 
86 {
87 public:
88 static void TestPassphraseSingle(const std::vector<unsigned char>& vchSalt, const SecureString& passphrase, uint32_t rounds,
89  const std::vector<unsigned char>& correctKey = std::vector<unsigned char>(),
90  const std::vector<unsigned char>& correctIV=std::vector<unsigned char>())
91 {
92  unsigned char chKey[WALLET_CRYPTO_KEY_SIZE];
93  unsigned char chIV[WALLET_CRYPTO_IV_SIZE];
94 
95  CCrypter crypt;
96  crypt.SetKeyFromPassphrase(passphrase, vchSalt, rounds, 0);
97 
98  OldSetKeyFromPassphrase(passphrase, vchSalt, rounds, 0, chKey, chIV);
99 
100  BOOST_CHECK_MESSAGE(memcmp(chKey, crypt.chKey, sizeof(chKey)) == 0, \
101  HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(crypt.chKey, crypt.chKey + (sizeof crypt.chKey)));
102  BOOST_CHECK_MESSAGE(memcmp(chIV, crypt.chIV, sizeof(chIV)) == 0, \
103  HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(crypt.chIV, crypt.chIV + (sizeof crypt.chIV)));
104 
105  if(!correctKey.empty())
106  BOOST_CHECK_MESSAGE(memcmp(chKey, &correctKey[0], sizeof(chKey)) == 0, \
107  HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(correctKey.begin(), correctKey.end()));
108  if(!correctIV.empty())
109  BOOST_CHECK_MESSAGE(memcmp(chIV, &correctIV[0], sizeof(chIV)) == 0,
110  HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(correctIV.begin(), correctIV.end()));
111 }
112 
113 static void TestPassphrase(const std::vector<unsigned char>& vchSalt, const SecureString& passphrase, uint32_t rounds,
114  const std::vector<unsigned char>& correctKey = std::vector<unsigned char>(),
115  const std::vector<unsigned char>& correctIV=std::vector<unsigned char>())
116 {
117  TestPassphraseSingle(vchSalt, passphrase, rounds, correctKey, correctIV);
118  for(SecureString::const_iterator i(passphrase.begin()); i != passphrase.end(); ++i)
119  TestPassphraseSingle(vchSalt, SecureString(i, passphrase.end()), rounds);
120 }
121 
122 
123 static void TestDecrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchCiphertext, \
124  const std::vector<unsigned char>& vchPlaintext = std::vector<unsigned char>())
125 {
126  CKeyingMaterial vchDecrypted1;
127  CKeyingMaterial vchDecrypted2;
128  int result1, result2;
129  result1 = crypt.Decrypt(vchCiphertext, vchDecrypted1);
130  result2 = OldDecrypt(vchCiphertext, vchDecrypted2, crypt.chKey, crypt.chIV);
131  BOOST_CHECK(result1 == result2);
132 
133  // These two should be equal. However, OpenSSL 1.0.1j introduced a change
134  // that would zero all padding except for the last byte for failed decrypts.
135  // This behavior was reverted for 1.0.1k.
136  if (vchDecrypted1 != vchDecrypted2 && vchDecrypted1.size() >= AES_BLOCK_SIZE && SSLeay() == 0x100010afL)
137  {
138  for(CKeyingMaterial::iterator it = vchDecrypted1.end() - AES_BLOCK_SIZE; it != vchDecrypted1.end() - 1; it++)
139  *it = 0;
140  }
141 
142  BOOST_CHECK_MESSAGE(vchDecrypted1 == vchDecrypted2, HexStr(vchDecrypted1.begin(), vchDecrypted1.end()) + " != " + HexStr(vchDecrypted2.begin(), vchDecrypted2.end()));
143 
144  if (vchPlaintext.size())
145  BOOST_CHECK(CKeyingMaterial(vchPlaintext.begin(), vchPlaintext.end()) == vchDecrypted2);
146 }
147 
148 static void TestEncryptSingle(const CCrypter& crypt, const CKeyingMaterial& vchPlaintext,
149  const std::vector<unsigned char>& vchCiphertextCorrect = std::vector<unsigned char>())
150 {
151  std::vector<unsigned char> vchCiphertext1;
152  std::vector<unsigned char> vchCiphertext2;
153  int result1 = crypt.Encrypt(vchPlaintext, vchCiphertext1);
154 
155  int result2 = OldEncrypt(vchPlaintext, vchCiphertext2, crypt.chKey, crypt.chIV);
156  BOOST_CHECK(result1 == result2);
157  BOOST_CHECK(vchCiphertext1 == vchCiphertext2);
158 
159  if (!vchCiphertextCorrect.empty())
160  BOOST_CHECK(vchCiphertext2 == vchCiphertextCorrect);
161 
162  const std::vector<unsigned char> vchPlaintext2(vchPlaintext.begin(), vchPlaintext.end());
163 
164  if(vchCiphertext1 == vchCiphertext2)
165  TestDecrypt(crypt, vchCiphertext1, vchPlaintext2);
166 }
167 
168 static void TestEncrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchPlaintextIn, \
169  const std::vector<unsigned char>& vchCiphertextCorrect = std::vector<unsigned char>())
170 {
171  TestEncryptSingle(crypt, CKeyingMaterial(vchPlaintextIn.begin(), vchPlaintextIn.end()), vchCiphertextCorrect);
172  for(std::vector<unsigned char>::const_iterator i(vchPlaintextIn.begin()); i != vchPlaintextIn.end(); ++i)
173  TestEncryptSingle(crypt, CKeyingMaterial(i, vchPlaintextIn.end()));
174 }
175 
176 };
177 
178 BOOST_AUTO_TEST_CASE(passphrase) {
179  // These are expensive.
180 
181  TestCrypter::TestPassphrase(ParseHex("0000deadbeef0000"), "test", 25000, \
182  ParseHex("fc7aba077ad5f4c3a0988d8daa4810d0d4a0e3bcb53af662998898f33df0556a"), \
183  ParseHex("cf2f2691526dd1aa220896fb8bf7c369"));
184 
185  std::string hash(GetRandHash().ToString());
186  std::vector<unsigned char> vchSalt(8);
187  GetRandBytes(&vchSalt[0], vchSalt.size());
188  uint32_t rounds = GetRandInt(30000);
189  if (rounds > 30000)
190  rounds = 30000;
191  TestCrypter::TestPassphrase(vchSalt, SecureString(hash.begin(), hash.end()), rounds);
192 }
193 
195  std::vector<unsigned char> vchSalt = ParseHex("0000deadbeef0000");
196  BOOST_CHECK(vchSalt.size() == WALLET_CRYPTO_SALT_SIZE);
197  CCrypter crypt;
198  crypt.SetKeyFromPassphrase("passphrase", vchSalt, 25000, 0);
199  TestCrypter::TestEncrypt(crypt, ParseHex("22bcade09ac03ff6386914359cfe885cfeb5f77ff0d670f102f619687453b29d"));
200 
201  for (int i = 0; i != 100; i++)
202  {
203  uint256 hash(GetRandHash());
204  TestCrypter::TestEncrypt(crypt, std::vector<unsigned char>(hash.begin(), hash.end()));
205  }
206 
207 }
208 
210  std::vector<unsigned char> vchSalt = ParseHex("0000deadbeef0000");
211  BOOST_CHECK(vchSalt.size() == WALLET_CRYPTO_SALT_SIZE);
212  CCrypter crypt;
213  crypt.SetKeyFromPassphrase("passphrase", vchSalt, 25000, 0);
214 
215  // Some corner cases the came up while testing
216  TestCrypter::TestDecrypt(crypt,ParseHex("795643ce39d736088367822cdc50535ec6f103715e3e48f4f3b1a60a08ef59ca"));
217  TestCrypter::TestDecrypt(crypt,ParseHex("de096f4a8f9bd97db012aa9d90d74de8cdea779c3ee8bc7633d8b5d6da703486"));
218  TestCrypter::TestDecrypt(crypt,ParseHex("32d0a8974e3afd9c6c3ebf4d66aa4e6419f8c173de25947f98cf8b7ace49449c"));
219  TestCrypter::TestDecrypt(crypt,ParseHex("e7c055cca2faa78cb9ac22c9357a90b4778ded9b2cc220a14cea49f931e596ea"));
220  TestCrypter::TestDecrypt(crypt,ParseHex("b88efddd668a6801d19516d6830da4ae9811988ccbaf40df8fbb72f3f4d335fd"));
221  TestCrypter::TestDecrypt(crypt,ParseHex("8cae76aa6a43694e961ebcb28c8ca8f8540b84153d72865e8561ddd93fa7bfa9"));
222 
223  for (int i = 0; i != 100; i++)
224  {
225  uint256 hash(GetRandHash());
226  TestCrypter::TestDecrypt(crypt, std::vector<unsigned char>(hash.begin(), hash.end()));
227  }
228 }
229 
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(passphrase)
Definition: crypto_tests.cpp:178
crypter.h
WALLET_CRYPTO_KEY_SIZE
const unsigned int WALLET_CRYPTO_KEY_SIZE
Definition: crypter.h:14
GetRandInt
int GetRandInt(int nMax)
Definition: random.cpp:366
TestCrypter::TestDecrypt
static void TestDecrypt(const CCrypter &crypt, const std::vector< unsigned char > &vchCiphertext, const std::vector< unsigned char > &vchPlaintext=std::vector< unsigned char >())
Definition: crypto_tests.cpp:123
base_uint::end
unsigned char * end()
Definition: arith_uint256.h:245
ParseHex
std::vector< unsigned char > ParseHex(const char *psz)
Definition: utilstrencodings.cpp:77
base_uint::begin
unsigned char * begin()
Definition: arith_uint256.h:240
CCrypter::Encrypt
bool Encrypt(const CKeyingMaterial &vchPlaintext, std::vector< unsigned char > &vchCiphertext) const
Definition: crypter.cpp:74
CKeyingMaterial
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
Definition: crypter.h:69
TestCrypter::TestEncrypt
static void TestEncrypt(const CCrypter &crypt, const std::vector< unsigned char > &vchPlaintextIn, const std::vector< unsigned char > &vchCiphertextCorrect=std::vector< unsigned char >())
Definition: crypto_tests.cpp:168
CCrypter::Decrypt
bool Decrypt(const std::vector< unsigned char > &vchCiphertext, CKeyingMaterial &vchPlaintext) const
Definition: crypter.cpp:91
memory_cleanse
void memory_cleanse(void *ptr, size_t len)
Definition: cleanse.cpp:27
BOOST_FIXTURE_TEST_SUITE
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
OldDecrypt
bool OldDecrypt(const std::vector< unsigned char > &vchCiphertext, CKeyingMaterial &vchPlaintext, const unsigned char chKey[32], const unsigned char chIV[16])
Definition: crypto_tests.cpp:61
WALLET_CRYPTO_IV_SIZE
const unsigned int WALLET_CRYPTO_IV_SIZE
Definition: crypter.h:16
CCrypter::chIV
unsigned char chIV[WALLET_CRYPTO_IV_SIZE]
Definition: crypter.h:82
random.h
GetRandBytes
void GetRandBytes(unsigned char *buf, int num)
Functions to gather random data via the OpenSSL PRNG.
Definition: random.cpp:273
SecureString
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: allocators.h:262
HexStr
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
Definition: utilstrencodings.h:85
CCrypter::chKey
unsigned char chKey[WALLET_CRYPTO_KEY_SIZE]
Definition: crypter.h:81
GetRandHash
uint256 GetRandHash()
Definition: random.cpp:371
TestCrypter
Definition: crypto_tests.cpp:85
uint256
256-bit unsigned big integer.
Definition: uint256.h:38
CCrypter
Encryption/decryption context with key information.
Definition: crypter.h:77
std
Definition: adjacency_graphs.hpp:25
TestCrypter::TestPassphraseSingle
static void TestPassphraseSingle(const std::vector< unsigned char > &vchSalt, const SecureString &passphrase, uint32_t rounds, const std::vector< unsigned char > &correctKey=std::vector< unsigned char >(), const std::vector< unsigned char > &correctIV=std::vector< unsigned char >())
Definition: crypto_tests.cpp:88
CCrypter::SetKeyFromPassphrase
bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector< unsigned char > &chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
Definition: crypter.cpp:43
OldSetKeyFromPassphrase
bool OldSetKeyFromPassphrase(const SecureString &strKeyData, const std::vector< unsigned char > &chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod, unsigned char *chKey, unsigned char *chIV)
Definition: crypto_tests.cpp:18
OldEncrypt
bool OldEncrypt(const CKeyingMaterial &vchPlaintext, std::vector< unsigned char > &vchCiphertext, const unsigned char chKey[32], const unsigned char chIV[16])
Definition: crypto_tests.cpp:37
WALLET_CRYPTO_SALT_SIZE
const unsigned int WALLET_CRYPTO_SALT_SIZE
Definition: crypter.h:15
utilstrencodings.h
wallet_crypto
Definition: crypter.h:71
TestCrypter::TestEncryptSingle
static void TestEncryptSingle(const CCrypter &crypt, const CKeyingMaterial &vchPlaintext, const std::vector< unsigned char > &vchCiphertextCorrect=std::vector< unsigned char >())
Definition: crypto_tests.cpp:148
TestCrypter::TestPassphrase
static void TestPassphrase(const std::vector< unsigned char > &vchSalt, const SecureString &passphrase, uint32_t rounds, const std::vector< unsigned char > &correctKey=std::vector< unsigned char >(), const std::vector< unsigned char > &correctIV=std::vector< unsigned char >())
Definition: crypto_tests.cpp:113
BOOST_CHECK
#define BOOST_CHECK(expr)
Definition: object.cpp:17
BOOST_AUTO_TEST_SUITE_END
#define BOOST_AUTO_TEST_SUITE_END()
Definition: object.cpp:16