Encryption.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. // Encryption.cpp: implementation of the CEncryption class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "Encryption.h"
  6. #include "MemUtil.h"
  7. #include "rijndael.h"
  8. #include "sha2.h"
  9. //////////////////////////////////////////////////////////////////////
  10. // Construction/Destruction
  11. //////////////////////////////////////////////////////////////////////
  12. CEncryption::CEncryption()
  13. {
  14. m_dwKeyEncRounds = TD_STD_KEYENCROUNDS;
  15. memset(m_pMasterKey, 0, 32);
  16. m_random.Initialize();
  17. }
  18. CEncryption::~CEncryption()
  19. {
  20. mem_erase(m_pMasterKey, 32);
  21. m_random.Reset();
  22. }
  23. void CEncryption::Release()
  24. {
  25. delete this;
  26. }
  27. bool CEncryption::Encrypt(const unsigned char* pInput, int nLenInput, const char* szPassword,
  28. unsigned char*& pOutput, int& nLenOutput)
  29. {
  30. bool bResult = false;
  31. TD_TLHEADER hdr;
  32. RD_UINT8 uFinalKey[32];
  33. unsigned long uFileSize = 0, uAllocated = 0, pos = 0;
  34. int nEncryptedPartSize = 0;
  35. ASSERT(NULL != pInput); if(NULL == pInput) return FALSE;
  36. ASSERT(0 != nLenInput); if(0 == nLenInput) return FALSE;
  37. ASSERT(NULL != szPassword); if(NULL == szPassword) return FALSE;
  38. uFileSize = nLenInput + sizeof(TD_TLHEADER);
  39. // Allocate enough memory
  40. uAllocated = uFileSize + 16;
  41. pOutput = new unsigned char[uAllocated];
  42. if(NULL != pOutput)
  43. {
  44. unsigned long uKeyLen;
  45. // Build header structure
  46. hdr.dwSignature1 = TD_TLSIG_1;
  47. hdr.dwSignature2 = TD_TLSIG_2;
  48. hdr.dwKeyEncRounds = m_dwKeyEncRounds;
  49. // Make up the master key hash seed and the encryption IV
  50. m_random.GetRandomBuffer(hdr.aMasterSeed, 16);
  51. m_random.GetRandomBuffer((BYTE *)hdr.aEncryptionIV, 16);
  52. m_random.GetRandomBuffer(hdr.aMasterSeed2, 32);
  53. // Create MasterKey by hashing szPassword
  54. uKeyLen = strlen(szPassword);
  55. ASSERT(0 != uKeyLen);
  56. if(0 != uKeyLen)
  57. {
  58. sha256_ctx sha32;
  59. sha256_begin(&sha32);
  60. sha256_hash((unsigned char *)szPassword, uKeyLen, &sha32);
  61. sha256_end(m_pMasterKey, &sha32);
  62. // Generate m_pTransformedMasterKey from m_pMasterKey
  63. if(TRUE == _TransformMasterKey(hdr.aMasterSeed2))
  64. {
  65. // Hash the master password with the generated hash salt
  66. sha256_begin(&sha32);
  67. sha256_hash(hdr.aMasterSeed, 16, &sha32);
  68. sha256_hash(m_pTransformedMasterKey, 32, &sha32);
  69. sha256_end((unsigned char *)uFinalKey, &sha32);
  70. // Hash the tasklist contents
  71. sha256_begin(&sha32);
  72. sha256_hash((unsigned char *)pInput, nLenInput, &sha32);
  73. sha256_end((unsigned char *)hdr.aContentsHash, &sha32);
  74. // Hash the header
  75. sha256_begin(&sha32);
  76. sha256_hash((unsigned char *)&hdr + 32, sizeof(TD_TLHEADER) - 32, &sha32);
  77. sha256_end((unsigned char *)hdr.aHeaderHash, &sha32);
  78. bResult = true;
  79. }
  80. }
  81. }
  82. if (bResult)
  83. {
  84. bResult = false;
  85. // Now we have all to build up the header
  86. memcpy(pOutput, &hdr, sizeof(TD_TLHEADER));
  87. Rijndael aes;
  88. // Initialize Rijndael/AES
  89. if(RIJNDAEL_SUCCESS == aes.init(Rijndael::CBC, Rijndael::Encrypt, uFinalKey,
  90. Rijndael::Key32Bytes, hdr.aEncryptionIV) )
  91. {
  92. nEncryptedPartSize = aes.padEncrypt((RD_UINT8 *)pInput, nLenInput, (RD_UINT8 *)pOutput + sizeof(TD_TLHEADER));
  93. // Check if all went correct
  94. ASSERT(0 <= nEncryptedPartSize);
  95. if(0 <= nEncryptedPartSize)
  96. {
  97. bResult = true; // data encrypted successfully
  98. }
  99. nLenOutput = sizeof(TD_TLHEADER) + nEncryptedPartSize;
  100. }
  101. }
  102. if (!bResult)
  103. {
  104. SAFE_DELETE_ARRAY(pOutput);
  105. }
  106. return (bResult);
  107. }
  108. bool CEncryption::Decrypt(const unsigned char* pInput, int nLenInput, const char* szPassword,
  109. unsigned char*& pOutput, int& nLenOutput)
  110. {
  111. bool bResult = false;
  112. TD_TLHEADER hdr;
  113. RD_UINT8 uFinalKey[32];
  114. sha256_ctx sha32;
  115. ASSERT(NULL != pInput); if(NULL == pInput) return FALSE;
  116. ASSERT(0 != nLenInput); if(0 == nLenInput) return FALSE;
  117. ASSERT(NULL != szPassword); if(NULL == szPassword) return FALSE;
  118. ASSERT(sizeof(TD_TLHEADER) <= nLenInput); if(sizeof(TD_TLHEADER) > nLenInput) return FALSE;
  119. // Extract header structure from memory file
  120. memcpy(&hdr, pInput, sizeof(TD_TLHEADER));
  121. // Hash the header
  122. sha256_begin(&sha32);
  123. sha256_hash((unsigned char *)&hdr + 32, sizeof(TD_TLHEADER) - 32, &sha32);
  124. sha256_end((unsigned char *)uFinalKey, &sha32);
  125. // Check if hash of header is the same as stored hash
  126. // to verify integrity of header
  127. if(0 == memcmp(hdr.aHeaderHash, uFinalKey, 32))
  128. {
  129. // Check if we can open this
  130. if((hdr.dwSignature1 == TD_TLSIG_1) && (hdr.dwSignature2 == TD_TLSIG_2))
  131. {
  132. // Allocate enough memory
  133. pOutput = new unsigned char[nLenInput];
  134. if(NULL != pOutput)
  135. {
  136. memset(pOutput, 0, nLenInput);
  137. unsigned long uKeyLen = strlen(szPassword);
  138. // Create MasterKey by hashing szPassword
  139. ASSERT(0 != uKeyLen);
  140. if(0 != uKeyLen)
  141. {
  142. sha256_begin(&sha32);
  143. sha256_hash((unsigned char *)szPassword, uKeyLen, &sha32);
  144. sha256_end(m_pMasterKey, &sha32);
  145. m_dwKeyEncRounds = hdr.dwKeyEncRounds;
  146. // Generate m_pTransformedMasterKey from m_pMasterKey
  147. if(TRUE == _TransformMasterKey(hdr.aMasterSeed2))
  148. {
  149. // Hash the master password with the generated hash salt
  150. sha256_begin(&sha32);
  151. sha256_hash(hdr.aMasterSeed, 16, &sha32);
  152. sha256_hash(m_pTransformedMasterKey, 32, &sha32);
  153. sha256_end((unsigned char *)uFinalKey, &sha32);
  154. bResult = true;
  155. }
  156. }
  157. }
  158. }
  159. }
  160. if (bResult)
  161. {
  162. bResult = false;
  163. Rijndael aes;
  164. // Initialize Rijndael/AES
  165. if(RIJNDAEL_SUCCESS == aes.init(Rijndael::CBC, Rijndael::Decrypt, uFinalKey,
  166. Rijndael::Key32Bytes, hdr.aEncryptionIV) )
  167. {
  168. nLenOutput = aes.padDecrypt((RD_UINT8 *)pInput + sizeof(TD_TLHEADER), nLenInput - sizeof(TD_TLHEADER), (RD_UINT8 *)pOutput);
  169. // Check if all went correct
  170. ASSERT(0 <= nLenOutput);
  171. if(0 <= nLenOutput)
  172. {
  173. // Check contents correct (with high probability)
  174. sha256_begin(&sha32);
  175. sha256_hash((unsigned char *)pOutput, nLenOutput, &sha32);
  176. sha256_end((unsigned char *)uFinalKey, &sha32);
  177. if(0 == memcmp(hdr.aContentsHash, uFinalKey, 32))
  178. {
  179. bResult = true; // data decrypted successfully
  180. }
  181. }
  182. }
  183. }
  184. if (!bResult)
  185. {
  186. SAFE_DELETE_ARRAY(pOutput);
  187. }
  188. return (bResult);
  189. }
  190. void CEncryption::FreeBuffer(unsigned char*& pBuffer)
  191. {
  192. SAFE_DELETE_ARRAY(pBuffer);
  193. }
  194. /*
  195. Copyright (c) 2003/2004, Dominik Reichl <[email protected]>
  196. All rights reserved.
  197. Redistribution and use in source and binary forms, with or without
  198. modification, are permitted provided that the following conditions are met:
  199. - Redistributions of source code must retain the above copyright notice,
  200. this list of conditions and the following disclaimer.
  201. - Redistributions in binary form must reproduce the above copyright notice,
  202. this list of conditions and the following disclaimer in the documentation
  203. and/or other materials provided with the distribution.
  204. - Neither the name of ReichlSoft nor the names of its contributors may be
  205. used to endorse or promote products derived from this software without
  206. specific prior written permission.
  207. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  208. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  209. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  210. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  211. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  212. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  213. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  214. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  215. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  216. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  217. POSSIBILITY OF SUCH DAMAGE.
  218. */
  219. // Encrypt the master key a few times to make brute-force key-search harder
  220. BOOL CEncryption::_TransformMasterKey(BYTE *pKeySeed)
  221. {
  222. Rijndael rijndael;
  223. RD_UINT8 aKey[32];
  224. RD_UINT8 aTest[16];
  225. RD_UINT8 aRef[16] = { // The Rijndael class will be tested, that's the expected ciphertext
  226. 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf,
  227. 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89
  228. };
  229. DWORD i;
  230. sha256_ctx sha2;
  231. ASSERT(pKeySeed != NULL); if(pKeySeed == NULL) return FALSE;
  232. if(rijndael.init(Rijndael::ECB, Rijndael::Encrypt, (const RD_UINT8 *)pKeySeed,
  233. Rijndael::Key32Bytes, 0) != RIJNDAEL_SUCCESS)
  234. {
  235. return FALSE;
  236. }
  237. memcpy(m_pTransformedMasterKey, m_pMasterKey, 32);
  238. for(i = 0; i < m_dwKeyEncRounds; i++)
  239. {
  240. rijndael.blockEncrypt((const RD_UINT8 *)m_pTransformedMasterKey, 256, (RD_UINT8 *)m_pTransformedMasterKey);
  241. }
  242. // Do a quick test if the Rijndael class worked correctly
  243. for(i = 0; i < 32; i++) aKey[i] = (RD_UINT8)i;
  244. for(i = 0; i < 16; i++) aTest[i] = ((RD_UINT8)i << 4) | (RD_UINT8)i;
  245. if(rijndael.init(Rijndael::ECB, Rijndael::Encrypt, aKey, Rijndael::Key32Bytes, NULL) != RIJNDAEL_SUCCESS)
  246. { ASSERT(FALSE); return FALSE; }
  247. if(rijndael.blockEncrypt(aTest, 128, aTest) != 128) { ASSERT(FALSE); }
  248. if(memcmp(aTest, aRef, 16) != 0) { ASSERT(FALSE); return FALSE; }
  249. // Hash once with SHA-256
  250. sha256_begin(&sha2);
  251. sha256_hash(m_pTransformedMasterKey, 32, &sha2);
  252. sha256_end(m_pTransformedMasterKey, &sha2);
  253. return TRUE;
  254. }