PageRenderTime 44ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/crypter.cpp

https://gitlab.com/ppanula/nevacoin
C++ | 291 lines | 234 code | 50 blank | 7 comment | 54 complexity | e14d61d96111fd7f9e7c98cb81aa1c77 MD5 | raw file
  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. #include "crypter.h"
  5. #include "script.h"
  6. #include "scrypt.h"
  7. #include <string>
  8. #include <vector>
  9. #include <boost/foreach.hpp>
  10. #include <openssl/aes.h>
  11. #include <openssl/evp.h>
  12. #ifdef WIN32
  13. #include <windows.h>
  14. #endif
  15. bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
  16. {
  17. if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
  18. return false;
  19. int i = 0;
  20. if (nDerivationMethod == 0)
  21. {
  22. i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
  23. (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
  24. }
  25. if (nDerivationMethod == 1)
  26. {
  27. // Passphrase conversion
  28. uint256 scryptHash = scrypt_salted_multiround_hash((const void*)strKeyData.c_str(), strKeyData.size(), &chSalt[0], 8, nRounds);
  29. i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
  30. (unsigned char *)&scryptHash, sizeof scryptHash, nRounds, chKey, chIV);
  31. OPENSSL_cleanse(&scryptHash, sizeof scryptHash);
  32. }
  33. if (i != (int)WALLET_CRYPTO_KEY_SIZE)
  34. {
  35. OPENSSL_cleanse(chKey, sizeof(chKey));
  36. OPENSSL_cleanse(chIV, sizeof(chIV));
  37. return false;
  38. }
  39. fKeySet = true;
  40. return true;
  41. }
  42. bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
  43. {
  44. if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
  45. return false;
  46. memcpy(&chKey[0], &chNewKey[0], sizeof chKey);
  47. memcpy(&chIV[0], &chNewIV[0], sizeof chIV);
  48. fKeySet = true;
  49. return true;
  50. }
  51. bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext)
  52. {
  53. if (!fKeySet)
  54. return false;
  55. // max ciphertext len for a n bytes of plaintext is
  56. // n + AES_BLOCK_SIZE - 1 bytes
  57. int nLen = vchPlaintext.size();
  58. int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
  59. vchCiphertext = std::vector<unsigned char> (nCLen);
  60. EVP_CIPHER_CTX ctx;
  61. bool fOk = true;
  62. EVP_CIPHER_CTX_init(&ctx);
  63. if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV);
  64. if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen);
  65. if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0])+nCLen, &nFLen);
  66. EVP_CIPHER_CTX_cleanup(&ctx);
  67. if (!fOk) return false;
  68. vchCiphertext.resize(nCLen + nFLen);
  69. return true;
  70. }
  71. bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext)
  72. {
  73. if (!fKeySet)
  74. return false;
  75. // plaintext will always be equal to or lesser than length of ciphertext
  76. int nLen = vchCiphertext.size();
  77. int nPLen = nLen, nFLen = 0;
  78. vchPlaintext = CKeyingMaterial(nPLen);
  79. EVP_CIPHER_CTX ctx;
  80. bool fOk = true;
  81. EVP_CIPHER_CTX_init(&ctx);
  82. if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV);
  83. if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen);
  84. if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0])+nPLen, &nFLen);
  85. EVP_CIPHER_CTX_cleanup(&ctx);
  86. if (!fOk) return false;
  87. vchPlaintext.resize(nPLen + nFLen);
  88. return true;
  89. }
  90. bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
  91. {
  92. CCrypter cKeyCrypter;
  93. std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
  94. memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
  95. if(!cKeyCrypter.SetKey(vMasterKey, chIV))
  96. return false;
  97. return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
  98. }
  99. bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
  100. {
  101. CCrypter cKeyCrypter;
  102. std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
  103. memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
  104. if(!cKeyCrypter.SetKey(vMasterKey, chIV))
  105. return false;
  106. return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
  107. }
  108. bool CCryptoKeyStore::SetCrypted()
  109. {
  110. LOCK(cs_KeyStore);
  111. if (fUseCrypto)
  112. return true;
  113. if (!mapKeys.empty())
  114. return false;
  115. fUseCrypto = true;
  116. return true;
  117. }
  118. bool CCryptoKeyStore::Lock()
  119. {
  120. if (!SetCrypted())
  121. return false;
  122. {
  123. LOCK(cs_KeyStore);
  124. vMasterKey.clear();
  125. }
  126. NotifyStatusChanged(this);
  127. return true;
  128. }
  129. bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
  130. {
  131. {
  132. LOCK(cs_KeyStore);
  133. if (!SetCrypted())
  134. return false;
  135. CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
  136. for (; mi != mapCryptedKeys.end(); ++mi)
  137. {
  138. const CPubKey &vchPubKey = (*mi).second.first;
  139. const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
  140. CKeyingMaterial vchSecret;
  141. if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
  142. return false;
  143. if (vchSecret.size() != 32)
  144. return false;
  145. CKey key;
  146. key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
  147. if (key.GetPubKey() == vchPubKey)
  148. break;
  149. return false;
  150. }
  151. vMasterKey = vMasterKeyIn;
  152. }
  153. NotifyStatusChanged(this);
  154. return true;
  155. }
  156. bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
  157. {
  158. {
  159. LOCK(cs_KeyStore);
  160. if (!IsCrypted())
  161. return CBasicKeyStore::AddKeyPubKey(key, pubkey);
  162. if (IsLocked())
  163. return false;
  164. std::vector<unsigned char> vchCryptedSecret;
  165. CKeyingMaterial vchSecret(key.begin(), key.end());
  166. if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
  167. return false;
  168. if (!AddCryptedKey(pubkey, vchCryptedSecret))
  169. return false;
  170. }
  171. return true;
  172. }
  173. bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
  174. {
  175. {
  176. LOCK(cs_KeyStore);
  177. if (!SetCrypted())
  178. return false;
  179. mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
  180. }
  181. return true;
  182. }
  183. bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
  184. {
  185. {
  186. LOCK(cs_KeyStore);
  187. if (!IsCrypted())
  188. return CBasicKeyStore::GetKey(address, keyOut);
  189. CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
  190. if (mi != mapCryptedKeys.end())
  191. {
  192. const CPubKey &vchPubKey = (*mi).second.first;
  193. const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
  194. CKeyingMaterial vchSecret;
  195. if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
  196. return false;
  197. if (vchSecret.size() != 32)
  198. return false;
  199. keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
  200. return true;
  201. }
  202. }
  203. return false;
  204. }
  205. bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
  206. {
  207. {
  208. LOCK(cs_KeyStore);
  209. if (!IsCrypted())
  210. return CKeyStore::GetPubKey(address, vchPubKeyOut);
  211. CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
  212. if (mi != mapCryptedKeys.end())
  213. {
  214. vchPubKeyOut = (*mi).second.first;
  215. return true;
  216. }
  217. }
  218. return false;
  219. }
  220. bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
  221. {
  222. {
  223. LOCK(cs_KeyStore);
  224. if (!mapCryptedKeys.empty() || IsCrypted())
  225. return false;
  226. fUseCrypto = true;
  227. BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
  228. {
  229. const CKey &key = mKey.second;
  230. CPubKey vchPubKey = key.GetPubKey();
  231. CKeyingMaterial vchSecret(key.begin(), key.end());
  232. std::vector<unsigned char> vchCryptedSecret;
  233. if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
  234. return false;
  235. if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
  236. return false;
  237. }
  238. mapKeys.clear();
  239. }
  240. return true;
  241. }