Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2219 lines
82 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. // Note: not using precompiled headers. The crypto++ headers create gunk that anyone including them
  8. // has to link to, so they can't be included in the global project file. They also contain
  9. // string functions which are deprecated by the global project file so they can't be included after, either.
  10. // So we can't use the global precompiled header, need to manually include the things we need.
  11. #include "winlite.h"
  12. #ifdef POSIX
  13. #include <sys/types.h>
  14. #include <sys/socket.h>
  15. #endif
  16. /* this stuff needs to be before the crypto headers, as it relies on memdbg, which doesn't
  17. do the right thing in the face of xdebug getting included below */
  18. // tier0
  19. //#include "tier0/tier0.h"
  20. #include "tier0/basetypes.h"
  21. #include "tier0/vprof.h"
  22. //#include "constants.h"
  23. #include "vstdlib/vstdlib.h"
  24. #include "strtools.h"
  25. //#include "version.h"
  26. //#include "globals.h"
  27. //#include "ivalidate.h"
  28. #include "tier1/utlvector.h"
  29. #include "simplebitstring.h"
  30. #include "tier1/checksum_sha1.h"
  31. #include "tier0/memdbgon.h"
  32. #include "tier0/tslist.h"
  33. #include "tier0/memdbgoff.h"
  34. #ifdef ENABLE_OPENSSLCONNECTION
  35. #define USE_OPENSSL_AES_DECRYPT 1
  36. #endif
  37. #ifdef USE_OPENSSL_AES_DECRYPT
  38. // openssl optimized AES routines
  39. #include "openssl/aes.h"
  40. #if defined(_M_IX86) || defined (_M_X64) || defined(__i386__) || defined(__x86_64__)
  41. #include <emmintrin.h>
  42. #endif
  43. #endif
  44. // crypto ++
  45. #include "tier0/valve_off.h"
  46. #include "../external/crypto++-5.6.3/cryptopushdisablewarnings.h"
  47. #if _MSC_VER < 1400 // doesn't work with vc8, things below need xdebug
  48. #define _XDEBUG_ // keep crypto++-5.2 from including xdebug
  49. // these are defined in xdebug and used in some subsequent headers, define them to be our version
  50. #define _NEW_CRT new
  51. #define _DELETE_CRT(_P) delete (_P)
  52. #define _DELETE_CRT_VEC(_P) delete[] (_P)
  53. #define _STRING_CRT string
  54. #endif
  55. #define CRYPTOPP_DLL
  56. #undef min
  57. #undef max
  58. #undef Verify
  59. #define VPROF_BUDGETGROUP_ENCRYPTION _T("Encryption")
  60. #define SPEW_CRYPTO "crypto"
  61. const int k_cMedBuff = 1024; // medium buffer
  62. #if defined(GNUC)
  63. #pragma GCC diagnostic ignored "-Wshadow"
  64. #endif
  65. #include "../external/crypto++-5.6.3/cryptlib.h"
  66. #include "../external/crypto++-5.6.3/osrng.h"
  67. #include "../external/crypto++-5.6.3/crc.h"
  68. #include "../external/crypto++-5.6.3/modes.h"
  69. #include "../external/crypto++-5.6.3/files.h"
  70. #include "../external/crypto++-5.6.3/hex.h"
  71. #include "../external/crypto++-5.6.3/base64.h"
  72. #include "../external/crypto++-5.6.3/base32.h"
  73. #include "../external/crypto++-5.6.3/words.h"
  74. #include "../external/crypto++-5.6.3/rsa.h"
  75. #include "../external/crypto++-5.6.3/aes.h"
  76. #include "../external/crypto++-5.6.3/hmac.h"
  77. #include "../external/crypto++-5.6.3/zlib.h"
  78. #include "../external/crypto++-5.6.3/gzip.h"
  79. #include "../external/crypto++-5.6.3/pwdbased.h"
  80. using namespace CryptoPP;
  81. typedef AutoSeededX917RNG<AES> CAutoSeededRNG;
  82. #include "../external/crypto++-5.6.3/cryptopopdisablewarnings.h"
  83. #if defined(GNUC)
  84. #pragma GCC diagnostic warning "-Wshadow"
  85. #endif
  86. #include "tier0/memdbgon.h"
  87. #include "tier0/valve_on.h"
  88. #include "crypto.h"
  89. #define max(a,b) (((a) > (b)) ? (a) : (b))
  90. #define min(a,b) (((a) < (b)) ? (a) : (b))
  91. // list of auto-seeded RNG pointers
  92. // these are very expensive to construct, so it makes sense to cache them
  93. CTSList<CAutoSeededRNG> g_tslistPAutoSeededRNG;
  94. // to avoid deconstructor order issuses we allow to manually free the list
  95. void FreeListRNG()
  96. {
  97. g_tslistPAutoSeededRNG.Purge();
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Purpose: thread-safe access to a pool of cryptoPP random number generators
  101. //-----------------------------------------------------------------------------
  102. class CPoolAllocatedRNG
  103. {
  104. public:
  105. CPoolAllocatedRNG()
  106. {
  107. m_pRNGNode = g_tslistPAutoSeededRNG.Pop();
  108. if ( !m_pRNGNode )
  109. {
  110. m_pRNGNode = new CTSList<CAutoSeededRNG>::Node_t;
  111. }
  112. }
  113. ~CPoolAllocatedRNG()
  114. {
  115. g_tslistPAutoSeededRNG.Push( m_pRNGNode );
  116. }
  117. CAutoSeededRNG &GetRNG()
  118. {
  119. return m_pRNGNode->elem;
  120. }
  121. private:
  122. CTSList<CAutoSeededRNG>::Node_t *m_pRNGNode;
  123. };
  124. // force run this static construction code
  125. class CGlobalInitConstructor
  126. {
  127. public:
  128. CGlobalInitConstructor()
  129. {
  130. // we have to use this function once since the underlying static constructor
  131. // is not thread safe. See use of MicrosoftCryptoProvider in Crypto++
  132. CAutoSeededRNG rng;
  133. rng.GenerateByte();
  134. }
  135. };
  136. volatile static CGlobalInitConstructor s_StaticCryptoConstructor;
  137. //-----------------------------------------------------------------------------
  138. // Purpose: Encrypts the specified data with the specified key. Uses AES (Rijndael) symmetric
  139. // encryption. The encrypted data may then be decrypted by calling SymmetricDecrypt
  140. // with the same key.
  141. // Input: pubPlaintextData - Data to be encrypted
  142. // cubPlaintextData - Size of data to be encrypted
  143. // pIV - Pointer to initialization vector
  144. // cubIV - Size of initialization vector
  145. // pubEncryptedData - Pointer to buffer to receive encrypted data
  146. // pcubEncryptedData - Pointer to a variable that at time of call contains the size of
  147. // the receive buffer for encrypted data. When the method returns, this will contain
  148. // the actual size of the encrypted data.
  149. // pubKey - the key to encrypt the data with
  150. // cubKey - Size of the key (must be k_nSymmetricKeyLen)
  151. // Output: true if successful, false if encryption failed
  152. //-----------------------------------------------------------------------------
  153. bool CCrypto::SymmetricEncryptWithIV( const uint8 *pubPlaintextData, const uint32 cubPlaintextData,
  154. const uint8 *pIV, const uint32 cubIV,
  155. uint8 *pubEncryptedData, uint32 *pcubEncryptedData,
  156. const uint8 *pubKey, const uint32 cubKey )
  157. {
  158. VPROF_BUDGET( "CCrypto::SymmetricEncrypt", VPROF_BUDGETGROUP_ENCRYPTION );
  159. Assert( pubPlaintextData );
  160. Assert( cubPlaintextData );
  161. Assert( pubEncryptedData );
  162. Assert( pcubEncryptedData );
  163. Assert( *pcubEncryptedData );
  164. Assert( pubKey );
  165. Assert( k_nSymmetricKeyLen == cubKey ); // the only key length supported is k_nSymmetricKeyLen
  166. bool bRet = false;
  167. uint32 cubEncryptedData = *pcubEncryptedData; // remember how big the caller's buffer is
  168. bool bUseTempBuffer = false;
  169. uint8 *pTemp = pubEncryptedData;
  170. //
  171. // Crypto++ does not play well with overlapping buffers. If the buffers are
  172. // overlapping, then allocate some temp space to use for the encryption.
  173. //
  174. // It does work fine with _identical_ buffers.
  175. //
  176. if ( ( pubEncryptedData + cubEncryptedData >= pubPlaintextData ) &&
  177. ( pubPlaintextData + cubPlaintextData >= pubEncryptedData ) )
  178. {
  179. pTemp = new uint8[cubEncryptedData];
  180. bUseTempBuffer = true;
  181. }
  182. try // handle any exceptions crypto++ may throw
  183. {
  184. if ( pTemp != NULL )
  185. {
  186. AESEncryption aesEncrypt( pubKey, cubKey );
  187. byte rgubIVEncrypted[k_cMedBuff];
  188. Assert( Q_ARRAYSIZE( rgubIVEncrypted ) >= aesEncrypt.BlockSize() );
  189. Assert( pIV != NULL && cubIV >= aesEncrypt.BlockSize() );
  190. ArraySink * pOutputSink = new ArraySink( pTemp, *pcubEncryptedData );
  191. // encrypt the initial vector with the key
  192. aesEncrypt.ProcessBlock( pIV, rgubIVEncrypted );
  193. // store the encrypted IV in the output - the recipient will need it
  194. pOutputSink->Put( rgubIVEncrypted, aesEncrypt.BlockSize() );
  195. // encrypt the message, given the key & IV
  196. CBC_Mode_ExternalCipher::Encryption cipher( aesEncrypt, pIV );
  197. // Note: StreamTransformationFilter now owns the pointer to pOutputSink and will
  198. // free it when the filter goes out of scope and destructs
  199. StreamTransformationFilter filter( cipher, pOutputSink );
  200. filter.Put( (byte *) pubPlaintextData, cubPlaintextData );
  201. filter.MessageEnd();
  202. // return length of encrypted data to caller
  203. *pcubEncryptedData = pOutputSink->TotalPutLength();
  204. // CryptoPP may leave garbage hanging around in the caller's buffer past the stated output length.
  205. // Just to be safe, zero out caller's buffer from end out output to end of max buffer
  206. if ( bUseTempBuffer )
  207. {
  208. Q_memcpy( pubEncryptedData, pTemp, *pcubEncryptedData );
  209. }
  210. Q_memset( pubEncryptedData + *pcubEncryptedData, 0, (cubEncryptedData - *pcubEncryptedData ) );
  211. bRet = true;
  212. }
  213. }
  214. catch ( Exception e )
  215. {
  216. DMsg( SPEW_CRYPTO, 2, "CCrypto::SymmetricEncrypt: crypto++ threw exception %s (%d)\n",
  217. e.what(), e.GetErrorType() );
  218. }
  219. if ( bUseTempBuffer )
  220. {
  221. delete[] pTemp;
  222. }
  223. return bRet;
  224. }
  225. //-----------------------------------------------------------------------------
  226. // Purpose: Encrypts the specified data with the specified key. Uses AES (Rijndael) symmetric
  227. // encryption. The encrypted data may then be decrypted by calling SymmetricDecrypt
  228. // with the same key. Generates a random initialization vector of the
  229. // appropriate size.
  230. // Input: pubPlaintextData - Data to be encrypted
  231. // cubPlaintextData - Size of data to be encrypted
  232. // pubEncryptedData - Pointer to buffer to receive encrypted data
  233. // pcubEncryptedData - Pointer to a variable that at time of call contains the size of
  234. // the receive buffer for encrypted data. When the method returns, this will contain
  235. // the actual size of the encrypted data.
  236. // pubKey - the key to encrypt the data with
  237. // cubKey - Size of the key (must be k_nSymmetricKeyLen)
  238. // Output: true if successful, false if encryption failed
  239. //-----------------------------------------------------------------------------
  240. bool CCrypto::SymmetricEncrypt( const uint8 *pubPlaintextData, const uint32 cubPlaintextData,
  241. uint8 *pubEncryptedData, uint32 *pcubEncryptedData,
  242. const uint8 *pubKey, const uint32 cubKey )
  243. {
  244. bool bRet = false;
  245. //
  246. // Generate a random IV
  247. //
  248. AESEncryption aesEncrypt( pubKey, cubKey );
  249. byte rgubIV[k_cMedBuff];
  250. CPoolAllocatedRNG rng;
  251. rng.GetRNG().GenerateBlock( rgubIV, aesEncrypt.BlockSize() );
  252. bRet = SymmetricEncryptWithIV( pubPlaintextData, cubPlaintextData, rgubIV, aesEncrypt.BlockSize(), pubEncryptedData, pcubEncryptedData, pubKey, cubKey );
  253. return bRet;
  254. }
  255. #ifdef USE_OPENSSL_AES_DECRYPT
  256. // Local helper to perform AES+CBC decryption using optimized OpenSSL AES routines
  257. static bool BDecryptAESUsingOpenSSL( const uint8 *pubEncryptedData, uint32 cubEncryptedData, uint8 *pubPlaintextData, uint32 *pcubPlaintextData, AES_KEY *key, const uint8 *pIV )
  258. {
  259. COMPILE_TIME_ASSERT( k_nSymmetricBlockSize == 16 );
  260. // Block cipher encrypted text must be a multiple of the block size
  261. if ( cubEncryptedData % k_nSymmetricBlockSize != 0 )
  262. return false;
  263. // Enough input? Requirement is one padded final block
  264. if ( cubEncryptedData < k_nSymmetricBlockSize )
  265. return false;
  266. // Enough output space for all the full non-final blocks?
  267. if ( *pcubPlaintextData < cubEncryptedData - k_nSymmetricBlockSize )
  268. return false;
  269. uint8 rgubWorking[k_nSymmetricBlockSize];
  270. uint32 nDecrypted = 0;
  271. // Process non-final blocks
  272. #if defined(_M_IX86) || defined (_M_X64) || defined(__i386__) || defined(__x86_64__)
  273. // ... believe it or not, Steam client on Windows supports Athlon XP without SSE2
  274. if ( !IsWindows() || GetCPUInformation().m_bSSE2 )
  275. {
  276. while ( nDecrypted < cubEncryptedData - k_nSymmetricBlockSize )
  277. {
  278. AES_decrypt( pubEncryptedData + nDecrypted, rgubWorking, key );
  279. __m128i m128Temp = _mm_xor_si128( _mm_loadu_si128( (__m128i*)pIV ), _mm_loadu_si128( (__m128i*)rgubWorking ) );
  280. pIV = pubEncryptedData + nDecrypted;
  281. nDecrypted += k_nSymmetricBlockSize;
  282. _mm_storeu_si128( (__m128i* RESTRICT)( pubPlaintextData + nDecrypted - k_nSymmetricBlockSize ), m128Temp );
  283. }
  284. }
  285. else
  286. #endif
  287. {
  288. while ( nDecrypted < cubEncryptedData - k_nSymmetricBlockSize )
  289. {
  290. AES_decrypt( pubEncryptedData + nDecrypted, rgubWorking, key );
  291. for ( int i = 0; i < k_nSymmetricBlockSize; ++i )
  292. pubPlaintextData[nDecrypted + i] = rgubWorking[i] ^ pIV[i];
  293. pIV = pubEncryptedData + nDecrypted;
  294. nDecrypted += k_nSymmetricBlockSize;
  295. }
  296. }
  297. // Process final block into rgubWorking for padding inspection
  298. Assert( nDecrypted == cubEncryptedData - k_nSymmetricBlockSize );
  299. AES_decrypt( pubEncryptedData + nDecrypted, rgubWorking, key );
  300. for ( int i = 0; i < k_nSymmetricBlockSize; ++i )
  301. rgubWorking[i] ^= pIV[i];
  302. // Get final block padding length and make sure it is backfilled properly (PKCS#5)
  303. uint8 pad = rgubWorking[ k_nSymmetricBlockSize - 1 ];
  304. if ( pad < 1 || pad > k_nSymmetricBlockSize )
  305. return false;
  306. for ( int i = k_nSymmetricBlockSize - pad; i < k_nSymmetricBlockSize; ++i )
  307. if ( rgubWorking[i] != pad )
  308. return false;
  309. // Check that we have enough space for final bytes
  310. if ( *pcubPlaintextData < nDecrypted + k_nSymmetricBlockSize - pad )
  311. return false;
  312. // Write any non-pad bytes from rgubWorking to pubPlaintextData
  313. for ( int i = 0; i < k_nSymmetricBlockSize - pad; ++i )
  314. pubPlaintextData[nDecrypted++] = rgubWorking[i];
  315. // The old CryptoPP path zeros out the entire destination buffer, but that
  316. // behavior isn't documented or even expected. We'll just zero out one byte
  317. // in case anyone relies on string termination, but that zero isn't counted.
  318. if ( *pcubPlaintextData > nDecrypted )
  319. pubPlaintextData[nDecrypted] = 0;
  320. *pcubPlaintextData = nDecrypted;
  321. return true;
  322. }
  323. #else
  324. /* function, not method */
  325. static bool SymmetricDecryptWorker( const uint8 *pubEncryptedData, uint32 cubEncryptedData,
  326. const uint8 * pIV, uint32 cubIV,
  327. uint8 *pubPlaintextData, uint32 *pcubPlaintextData,
  328. AESDecryption &aesDecrypt )
  329. {
  330. VPROF_BUDGET( "CCrypto::SymmetricDecrypt", VPROF_BUDGETGROUP_ENCRYPTION );
  331. Assert( pubEncryptedData );
  332. Assert( cubEncryptedData);
  333. Assert( pIV );
  334. Assert( cubIV );
  335. Assert( pubPlaintextData );
  336. Assert( pcubPlaintextData );
  337. Assert( *pcubPlaintextData );
  338. bool bRet = false;
  339. uint32 cubPlaintextData = *pcubPlaintextData; // remember how big the caller's buffer is
  340. bool bUseTempBuffer = false;
  341. uint8* pTemp = pubPlaintextData;
  342. //
  343. // Crypto++ does not play nice with decrypting in place. If the buffers are
  344. // overlapping, then allocate some temp space to use for the decryption.
  345. //
  346. // It does work fine with _identical_ buffers, but due to the way we store
  347. // the IV in the returned encrypted data we never actually hit that case.
  348. //
  349. if ( ( pubEncryptedData + cubEncryptedData >= pubPlaintextData ) &&
  350. ( pubPlaintextData + cubPlaintextData >= pubEncryptedData ) )
  351. {
  352. pTemp = new uint8[cubPlaintextData];
  353. bUseTempBuffer = true;
  354. }
  355. try // handle any exceptions crypto++ may throw
  356. {
  357. if ( pTemp != NULL )
  358. {
  359. CryptoPP::ArraySink* pOutputSink = new CryptoPP::ArraySink( pTemp, *pcubPlaintextData );
  360. CryptoPP::CBC_Mode_ExternalCipher::Decryption cbc( aesDecrypt, pIV );
  361. // Note: StreamTransformationFilter now owns the pointer to pOutputSink and will
  362. // free it when the filter goes out of scope and destructs
  363. CryptoPP::StreamTransformationFilter padding( cbc, pOutputSink );
  364. padding.Put( pubEncryptedData, cubEncryptedData );
  365. padding.MessageEnd();
  366. // return length of decrypted data to caller
  367. *pcubPlaintextData = pOutputSink->TotalPutLength();
  368. // CryptoPP may leave garbage hanging around in the caller's buffer past the stated output length.
  369. // Just to be safe, zero out caller's buffer from end out output to end of max buffer
  370. if ( bUseTempBuffer )
  371. {
  372. Q_memcpy( pubPlaintextData, pTemp, *pcubPlaintextData );
  373. }
  374. Q_memset( pubPlaintextData + *pcubPlaintextData, 0, (cubPlaintextData - *pcubPlaintextData ) );
  375. bRet = true;
  376. }
  377. }
  378. catch ( Exception e )
  379. {
  380. DMsg( SPEW_CRYPTO, 4, "CCrypto::SymmetricDecrypt: crypto++ threw exception %s (%d)\n",
  381. e.what(), e.GetErrorType() );
  382. }
  383. if ( bUseTempBuffer )
  384. {
  385. delete[] pTemp;
  386. }
  387. return bRet;
  388. }
  389. #endif
  390. //-----------------------------------------------------------------------------
  391. // Purpose: Decrypts the specified data with the specified key. Uses AES (Rijndael) symmetric
  392. // decryption.
  393. // Input: pubEncryptedData - Data to be decrypted
  394. // cubEncryptedData - Size of data to be decrypted
  395. // pubPlaintextData - Pointer to buffer to receive decrypted data
  396. // pcubPlaintextData - Pointer to a variable that at time of call contains the size of
  397. // the receive buffer for decrypted data. When the method returns, this will contain
  398. // the actual size of the decrypted data.
  399. // pubKey - the key to decrypt the data with
  400. // cubKey - Size of the key (must be k_nSymmetricKeyLen)
  401. // Output: true if successful, false if decryption failed
  402. //-----------------------------------------------------------------------------
  403. bool CCrypto::SymmetricDecrypt( const uint8 *pubEncryptedData, uint32 cubEncryptedData,
  404. uint8 *pubPlaintextData, uint32 *pcubPlaintextData,
  405. const uint8 *pubKey, const uint32 cubKey )
  406. {
  407. Assert( pubEncryptedData );
  408. Assert( cubEncryptedData);
  409. Assert( pubPlaintextData );
  410. Assert( pcubPlaintextData );
  411. Assert( *pcubPlaintextData );
  412. Assert( pubKey );
  413. Assert( k_nSymmetricKeyLen == cubKey ); // the only key length supported is k_nSymmetricKeyLen
  414. // the initialization vector (IV) must be stored in the first block of bytes.
  415. // If the size of encrypted data is not at least the block size, it is not valid
  416. if ( cubEncryptedData < k_nSymmetricBlockSize )
  417. return false;
  418. #ifdef USE_OPENSSL_AES_DECRYPT
  419. AES_KEY key;
  420. if ( AES_set_decrypt_key( pubKey, cubKey * 8, &key ) < 0 )
  421. return false;
  422. // Our first block is straight AES block encryption of IV with user key, no XOR.
  423. uint8 rgubIV[ k_nSymmetricBlockSize ];
  424. AES_decrypt( pubEncryptedData, rgubIV, &key );
  425. pubEncryptedData += k_nSymmetricBlockSize;
  426. cubEncryptedData -= k_nSymmetricBlockSize;
  427. return BDecryptAESUsingOpenSSL( pubEncryptedData, cubEncryptedData, pubPlaintextData, pcubPlaintextData, &key, rgubIV );
  428. #else
  429. AESDecryption aesDecrypt( pubKey, cubKey );
  430. Assert( k_nSymmetricBlockSize == aesDecrypt.BlockSize() );
  431. // Decrypt the IV
  432. byte rgubIV[k_cMedBuff];
  433. Assert( Q_ARRAYSIZE( rgubIV ) >= aesDecrypt.BlockSize() );
  434. aesDecrypt.ProcessBlock( pubEncryptedData, rgubIV );
  435. // We have now consumed the IV, so remove it from the front of the message
  436. pubEncryptedData += k_nSymmetricBlockSize;
  437. cubEncryptedData -= k_nSymmetricBlockSize;
  438. // given the IV stored in the message, and the key, decrypt the message
  439. return SymmetricDecryptWorker( pubEncryptedData, cubEncryptedData,
  440. rgubIV, aesDecrypt.BlockSize(),
  441. pubPlaintextData, pcubPlaintextData,
  442. aesDecrypt );
  443. #endif
  444. }
  445. //-----------------------------------------------------------------------------
  446. // Purpose: Decrypts the specified data with the specified key. Uses AES (Rijndael) symmetric
  447. // decryption.
  448. // Input: pubEncryptedData - Data to be decrypted
  449. // cubEncryptedData - Size of data to be decrypted
  450. // pIV - Initialization vector. Byte array one block in size.
  451. // cubIV - size of IV. This should be 16 (one block, 128 bits)
  452. // pubPlaintextData - Pointer to buffer to receive decrypted data
  453. // pcubPlaintextData - Pointer to a variable that at time of call contains the size of
  454. // the receive buffer for decrypted data. When the method returns, this will contain
  455. // the actual size of the decrypted data.
  456. // pubKey - the key to decrypt the data with
  457. // cubKey - Size of the key (must be k_nSymmetricKeyLen)
  458. // Output: true if successful, false if decryption failed
  459. //-----------------------------------------------------------------------------
  460. bool CCrypto::SymmetricDecryptWithIV( const uint8 *pubEncryptedData, uint32 cubEncryptedData,
  461. const uint8 * pIV, uint32 cubIV,
  462. uint8 *pubPlaintextData, uint32 *pcubPlaintextData,
  463. const uint8 *pubKey, const uint32 cubKey )
  464. {
  465. Assert( pubEncryptedData );
  466. Assert( cubEncryptedData);
  467. Assert( pIV );
  468. Assert( cubIV );
  469. Assert( pubPlaintextData );
  470. Assert( pcubPlaintextData );
  471. Assert( *pcubPlaintextData );
  472. Assert( pubKey );
  473. Assert( k_nSymmetricKeyLen == cubKey ); // the only key length supported is k_nSymmetricKeyLen
  474. // IV input into CBC must be exactly one block size
  475. if ( cubIV != k_nSymmetricBlockSize )
  476. return false;
  477. #ifdef USE_OPENSSL_AES_DECRYPT
  478. AES_KEY key;
  479. if ( AES_set_decrypt_key( pubKey, cubKey * 8, &key ) < 0 )
  480. return false;
  481. return BDecryptAESUsingOpenSSL( pubEncryptedData, cubEncryptedData, pubPlaintextData, pcubPlaintextData, &key, pIV );
  482. #else
  483. AESDecryption aesDecrypt( pubKey, cubKey );
  484. Assert( k_nSymmetricBlockSize == aesDecrypt.BlockSize() );
  485. return SymmetricDecryptWorker( pubEncryptedData, cubEncryptedData,
  486. pIV, cubIV,
  487. pubPlaintextData, pcubPlaintextData,
  488. aesDecrypt );
  489. #endif
  490. }
  491. //-----------------------------------------------------------------------------
  492. // Purpose: For specified plaintext data size, returns what size of symmetric
  493. // encrypted data will be
  494. //-----------------------------------------------------------------------------
  495. uint32 CCrypto::GetSymmetricEncryptedSize( uint32 cubPlaintextData )
  496. {
  497. // empirically determined encrypted size as function of plaintext size for AES encryption
  498. uint k_cubBlock = 16;
  499. uint k_cubHeader = 16;
  500. return k_cubHeader + ( ( cubPlaintextData / k_cubBlock ) * k_cubBlock ) + k_cubBlock;
  501. }
  502. //-----------------------------------------------------------------------------
  503. // Purpose: Encrypts the specified data with the specified text password.
  504. // Uses the SHA256 hash of the password as the key for AES (Rijndael) symmetric
  505. // encryption. A SHA1 HMAC of the result is appended, for authentication on
  506. // the receiving end.
  507. // The encrypted data may then be decrypted by calling DecryptWithPasswordAndAuthenticate
  508. // with the same password.
  509. // Input: pubPlaintextData - Data to be encrypted
  510. // cubPlaintextData - Size of data to be encrypted
  511. // pubEncryptedData - Pointer to buffer to receive encrypted data
  512. // pcubEncryptedData - Pointer to a variable that at time of call contains the size of
  513. // the receive buffer for encrypted data. When the method returns, this will contain
  514. // the actual size of the encrypted data.
  515. // pchPassword - text password
  516. // Output: true if successful, false if encryption failed
  517. //-----------------------------------------------------------------------------
  518. bool CCrypto::EncryptWithPasswordAndHMAC( const uint8 *pubPlaintextData, uint32 cubPlaintextData,
  519. uint8 * pubEncryptedData, uint32 * pcubEncryptedData,
  520. const char *pchPassword )
  521. {
  522. //
  523. // Generate a random IV
  524. //
  525. byte rgubIV[k_nSymmetricBlockSize];
  526. CPoolAllocatedRNG rng;
  527. rng.GetRNG().GenerateBlock( rgubIV, k_nSymmetricBlockSize );
  528. return EncryptWithPasswordAndHMACWithIV( pubPlaintextData, cubPlaintextData, rgubIV, k_nSymmetricBlockSize, pubEncryptedData, pcubEncryptedData, pchPassword );
  529. }
  530. //-----------------------------------------------------------------------------
  531. // Purpose: Encrypts the specified data with the specified text password.
  532. // Uses the SHA256 hash of the password as the key for AES (Rijndael) symmetric
  533. // encryption. A SHA1 HMAC of the result is appended, for authentication on
  534. // the receiving end.
  535. // The encrypted data may then be decrypted by calling DecryptWithPasswordAndAuthenticate
  536. // with the same password.
  537. // Input: pubPlaintextData - Data to be encrypted
  538. // cubPlaintextData - Size of data to be encrypted
  539. // pIV - IV to use for AES encryption. Should be random and never used before unless you know
  540. // exactly what you're doing.
  541. // cubIV - size of the IV - should be same ase the AES blocksize.
  542. // pubEncryptedData - Pointer to buffer to receive encrypted data
  543. // pcubEncryptedData - Pointer to a variable that at time of call contains the size of
  544. // the receive buffer for encrypted data. When the method returns, this will contain
  545. // the actual size of the encrypted data.
  546. // pchPassword - text password
  547. // Output: true if successful, false if encryption failed
  548. //-----------------------------------------------------------------------------
  549. bool CCrypto::EncryptWithPasswordAndHMACWithIV( const uint8 *pubPlaintextData, uint32 cubPlaintextData,
  550. const uint8 * pIV, uint32 cubIV,
  551. uint8 * pubEncryptedData, uint32 * pcubEncryptedData,
  552. const char *pchPassword )
  553. {
  554. uint8 rgubKey[k_nSymmetricKeyLen];
  555. if ( !pchPassword || !pchPassword[0] )
  556. return false;
  557. if ( !cubPlaintextData )
  558. return false;
  559. uint32 cubBuffer = *pcubEncryptedData;
  560. uint32 cubExpectedResult = GetSymmetricEncryptedSize( cubPlaintextData ) + sizeof( SHADigest_t );
  561. if ( cubBuffer < cubExpectedResult )
  562. return false;
  563. try
  564. {
  565. CryptoPP::SHA256().CalculateDigest( rgubKey, (const uint8 *)pchPassword, Q_strlen( pchPassword ) );
  566. }
  567. catch ( Exception e )
  568. {
  569. DMsg( SPEW_CRYPTO, 4, "CCrypto::EncryptWithPassword: crypto++ threw exception %s (%d)\n",
  570. e.what(), e.GetErrorType() );
  571. return false;
  572. }
  573. bool bRet = SymmetricEncryptWithIV( pubPlaintextData, cubPlaintextData, pIV, cubIV, pubEncryptedData, pcubEncryptedData, rgubKey, k_nSymmetricKeyLen );
  574. if ( bRet )
  575. {
  576. // calc HMAC
  577. uint32 cubEncrypted = *pcubEncryptedData;
  578. *pcubEncryptedData += sizeof( SHADigest_t );
  579. if ( cubBuffer < *pcubEncryptedData )
  580. return false;
  581. SHADigest_t *pHMAC = (SHADigest_t*)( pubEncryptedData + cubEncrypted );
  582. bRet = CCrypto::GenerateHMAC( pubEncryptedData, cubEncrypted, rgubKey, k_nSymmetricKeyLen, pHMAC );
  583. }
  584. return bRet;
  585. }
  586. //-----------------------------------------------------------------------------
  587. // Purpose: Decrypts the specified data with the specified password. Uses AES (Rijndael) symmetric
  588. // decryption. First, the HMAC is verified - if it is not correct, then we know that
  589. // the key is incorrect or the data is corrupted, and the decryption fails.
  590. // Input: pubEncryptedData - Data to be decrypted
  591. // cubEncryptedData - Size of data to be decrypted
  592. // pubPlaintextData - Pointer to buffer to receive decrypted data
  593. // pcubPlaintextData - Pointer to a variable that at time of call contains the size of
  594. // the receive buffer for decrypted data. When the method returns, this will contain
  595. // the actual size of the decrypted data.
  596. // pchPassword - the text password to decrypt the data with
  597. // Output: true if successful, false if decryption failed
  598. //-----------------------------------------------------------------------------
  599. bool CCrypto::DecryptWithPasswordAndAuthenticate( const uint8 * pubEncryptedData, uint32 cubEncryptedData,
  600. uint8 * pubPlaintextData, uint32 * pcubPlaintextData,
  601. const char *pchPassword )
  602. {
  603. uint8 rgubKey[k_nSymmetricKeyLen];
  604. if ( !pchPassword || !pchPassword[0] )
  605. return false;
  606. if ( cubEncryptedData <= sizeof( SHADigest_t ) )
  607. return false;
  608. try
  609. {
  610. CryptoPP::SHA256().CalculateDigest( rgubKey, (const uint8 *)pchPassword, Q_strlen( pchPassword ) );
  611. }
  612. catch ( Exception e )
  613. {
  614. DMsg( SPEW_CRYPTO, 4, "CCrypto::EncryptWithPassword: crypto++ threw exception %s (%d)\n",
  615. e.what(), e.GetErrorType() );
  616. return false;
  617. }
  618. uint32 cubCiphertext = cubEncryptedData - sizeof( SHADigest_t );
  619. SHADigest_t *pHMAC = (SHADigest_t*)( pubEncryptedData + cubCiphertext );
  620. SHADigest_t hmacActual;
  621. bool bRet = CCrypto::GenerateHMAC( pubEncryptedData, cubCiphertext, rgubKey, k_nSymmetricKeyLen, &hmacActual );
  622. if ( bRet )
  623. {
  624. // invalid ciphertext or key
  625. if ( Q_memcmp( &hmacActual, pHMAC, sizeof( SHADigest_t ) ) )
  626. return false;
  627. bRet = SymmetricDecrypt( pubEncryptedData, cubCiphertext, pubPlaintextData, pcubPlaintextData, rgubKey, k_nSymmetricKeyLen );
  628. }
  629. return bRet;
  630. }
  631. //-----------------------------------------------------------------------------
  632. // Purpose: Generates a new pair of private/public RSA keys
  633. // Input: pubPublicKey - Pointer to buffer to receive public key (should be of size k_nRSAKeyLenMax)
  634. // pcubPublicKey - Pointer to variable that contains size of pubPublicKey buffer. At exit,
  635. // this is filled in with the actual size of the public key
  636. // pubPrivateKey - Pointer to buffer to receive private key (should be of size k_nRSAKeyLenMax)
  637. // pcubPrivateKey - Pointer to variable that contains size of pubPrivateKey buffer. At exit,
  638. // this is filled in with the actual size of the private key
  639. // Output: true if successful, false if key generation failed
  640. //-----------------------------------------------------------------------------
  641. bool CCrypto::RSAGenerateKeys( uint8 *pubPublicKey, uint32 *pcubPublicKey, uint8 *pubPrivateKey, uint32 *pcubPrivateKey )
  642. {
  643. VPROF_BUDGET( "CCrypto::RSAGenerateKeys", VPROF_BUDGETGROUP_ENCRYPTION );
  644. bool bRet = false;
  645. Assert( pubPublicKey );
  646. Assert( pcubPublicKey );
  647. Assert( pubPrivateKey );
  648. Assert( pcubPrivateKey );
  649. try // handle any exceptions crypto++ may throw
  650. {
  651. // generate private key
  652. ArraySink arraySinkPrivateKey( pubPrivateKey, *pcubPrivateKey );
  653. CPoolAllocatedRNG rng;
  654. RSAES_OAEP_SHA_Decryptor priv( rng.GetRNG(), k_nRSAKeyBits );
  655. priv.DEREncode( arraySinkPrivateKey );
  656. *pcubPrivateKey = arraySinkPrivateKey.TotalPutLength();
  657. // generate public key
  658. ArraySink arraySinkPublicKey( pubPublicKey, *pcubPublicKey );
  659. RSAES_OAEP_SHA_Encryptor pub(priv);
  660. pub.DEREncode( arraySinkPublicKey );
  661. *pcubPublicKey = arraySinkPublicKey.TotalPutLength();
  662. bRet = true;
  663. }
  664. catch ( Exception e )
  665. {
  666. DMsg( SPEW_CRYPTO, 2, "CCrypto::RSAGenerateKeys: crypto++ threw exception %s (%d)\n",
  667. e.what(), e.GetErrorType() );
  668. }
  669. return bRet;
  670. }
  671. //-----------------------------------------------------------------------------
  672. // Purpose: Encrypts the specified data with the specified RSA public key.
  673. // The encrypted data may then be decrypted by calling RSADecrypt with the
  674. // corresponding RSA private key.
  675. // Input: pubPlaintextData - Data to be encrypted
  676. // cubPlaintextData - Size of data to be encrypted
  677. // pubEncryptedData - Pointer to buffer to receive encrypted data
  678. // pcubEncryptedData - Pointer to a variable that at time of call contains the size of
  679. // the receive buffer for encrypted data. When the method returns, this will contain
  680. // the actual size of the encrypted data.
  681. // pubPublicKey - the RSA public key to encrypt the data with
  682. // cubPublicKey - Size of the key (must be k_nSymmetricKeyLen)
  683. // Output: true if successful, false if encryption failed
  684. //-----------------------------------------------------------------------------
  685. bool CCrypto::RSAEncrypt( const uint8 *pubPlaintextData, uint32 cubPlaintextData,
  686. uint8 *pubEncryptedData, uint32 *pcubEncryptedData,
  687. const uint8 *pubPublicKey, const uint32 cubPublicKey )
  688. {
  689. VPROF_BUDGET( "CCrypto::RSAEncrypt", VPROF_BUDGETGROUP_ENCRYPTION );
  690. bool bRet = false;
  691. Assert( cubPlaintextData > 0 ); // must pass in some data
  692. try // handle any exceptions crypto++ may throw
  693. {
  694. StringSource stringSourcePublicKey( pubPublicKey, cubPublicKey, true );
  695. RSAES_OAEP_SHA_Encryptor rsaEncryptor( stringSourcePublicKey );
  696. // calculate how many blocks of encryption will we need to do
  697. AssertFatal( rsaEncryptor.FixedMaxPlaintextLength() <= ULONG_MAX );
  698. uint32 cBlocks = 1 + ( ( cubPlaintextData - 1 ) / (uint32)rsaEncryptor.FixedMaxPlaintextLength() );
  699. // calculate how big the output will be
  700. AssertFatal( rsaEncryptor.FixedCiphertextLength() <= ULONG_MAX / cBlocks );
  701. uint32 cubCipherText = cBlocks * (uint32)rsaEncryptor.FixedCiphertextLength();
  702. Assert( cubCipherText > 0 );
  703. // ensure there is sufficient room in output buffer for result
  704. if ( cubCipherText > ( *pcubEncryptedData ) )
  705. {
  706. AssertMsg2( false, "CCrypto::RSAEncrypt: insufficient output buffer for encryption, needed %d got %d\n",
  707. cubCipherText, *pcubEncryptedData );
  708. return false;
  709. }
  710. // encrypt the message, using as many blocks as required
  711. CPoolAllocatedRNG rng;
  712. for ( uint32 nBlock = 0; nBlock < cBlocks; nBlock++ )
  713. {
  714. // encrypt either all remaining plaintext, or maximum allowed plaintext per RSA encryption operation
  715. uint32 cubToEncrypt = min( cubPlaintextData, (uint32)rsaEncryptor.FixedMaxPlaintextLength() );
  716. // encrypt the plaintext
  717. rsaEncryptor.Encrypt( rng.GetRNG(), pubPlaintextData, cubToEncrypt, pubEncryptedData );
  718. // adjust input and output pointers and remaining plaintext byte count
  719. pubPlaintextData += cubToEncrypt;
  720. cubPlaintextData -= cubToEncrypt;
  721. pubEncryptedData += rsaEncryptor.FixedCiphertextLength();
  722. }
  723. Assert( 0 == cubPlaintextData ); // should have no remaining plaintext to encrypt
  724. *pcubEncryptedData = cubCipherText;
  725. bRet = true;
  726. }
  727. catch ( Exception e )
  728. {
  729. DMsg( SPEW_CRYPTO, 2, "CCrypto::RSAEncrypt: Encrypt() threw exception %s (%d)\n",
  730. e.what(), e.GetErrorType() );
  731. }
  732. return bRet;
  733. }
  734. //-----------------------------------------------------------------------------
  735. // Purpose: Decrypts the specified data with the specified RSA private key
  736. // Input: pubEncryptedData - Data to be decrypted
  737. // cubEncryptedData - Size of data to be decrypted
  738. // pubPlaintextData - Pointer to buffer to receive decrypted data
  739. // pcubPlaintextData - Pointer to a variable that at time of call contains the size of
  740. // the receive buffer for decrypted data. When the method returns, this will contain
  741. // the actual size of the decrypted data.
  742. // pubPrivateKey - the RSA private key key to decrypt the data with
  743. // cubPrivateKey - Size of the key (must be k_nSymmetricKeyLen)
  744. // Output: true if successful, false if decryption failed
  745. //-----------------------------------------------------------------------------
  746. bool CCrypto::RSADecrypt( const uint8 *pubEncryptedData, uint32 cubEncryptedData,
  747. uint8 *pubPlaintextData, uint32 *pcubPlaintextData,
  748. const uint8 *pubPrivateKey, const uint32 cubPrivateKey )
  749. {
  750. VPROF_BUDGET( "CCrypto::RSADecrypt", VPROF_BUDGETGROUP_ENCRYPTION );
  751. bool bRet = false;
  752. Assert( cubEncryptedData > 0 ); // must pass in some data
  753. try // handle any exceptions crypto++ may throw
  754. {
  755. StringSource stringSourcePrivateKey( pubPrivateKey, cubPrivateKey, true );
  756. RSAES_OAEP_SHA_Decryptor rsaDecryptor( stringSourcePrivateKey );
  757. // calculate how many blocks of decryption will we need to do
  758. AssertFatal( rsaDecryptor.FixedCiphertextLength() <= ULONG_MAX );
  759. uint32 cubFixedCiphertextLength = (uint32)rsaDecryptor.FixedCiphertextLength();
  760. // Ensure encrypted data is valid and has length that is exact multiple of 128 bytes
  761. if ( 0 != ( cubEncryptedData % cubFixedCiphertextLength ) )
  762. {
  763. DMsg( SPEW_CRYPTO, 2, "CCrypto::RSADecrypt: invalid ciphertext length %d, needs to be a multiple of %d\n",
  764. cubEncryptedData, cubFixedCiphertextLength );
  765. return false;
  766. }
  767. uint32 cBlocks = cubEncryptedData / cubFixedCiphertextLength;
  768. // calculate how big the maximum output will be
  769. size_t cubMaxPlaintext = rsaDecryptor.MaxPlaintextLength( rsaDecryptor.FixedCiphertextLength() );
  770. AssertFatal( cubMaxPlaintext <= ULONG_MAX / cBlocks );
  771. uint32 cubPlaintextDataMax = cBlocks * (uint32)cubMaxPlaintext;
  772. Assert( cubPlaintextDataMax > 0 );
  773. // ensure there is sufficient room in output buffer for result
  774. if ( cubPlaintextDataMax >= ( *pcubPlaintextData ) )
  775. {
  776. AssertMsg2( false, "CCrypto::RSADecrypt: insufficient output buffer for decryption, needed %d got %d\n",
  777. cubPlaintextDataMax, *pcubPlaintextData );
  778. return false;
  779. }
  780. // decrypt the data, using as many blocks as required
  781. CPoolAllocatedRNG rng;
  782. uint32 cubPlaintextData = 0;
  783. for ( uint32 nBlock = 0; nBlock < cBlocks; nBlock++ )
  784. {
  785. // decrypt one block (always of fixed size)
  786. int cubToDecrypt = cubFixedCiphertextLength;
  787. DecodingResult decodingResult = rsaDecryptor.Decrypt( rng.GetRNG(), pubEncryptedData, cubToDecrypt, pubPlaintextData );
  788. if ( !decodingResult.isValidCoding )
  789. {
  790. DMsg( SPEW_CRYPTO, 2, "CCrypto::RSADecrypt: failed to decrypt\n" );
  791. return false;
  792. }
  793. // adjust input and output pointers and remaining encrypted byte count
  794. pubEncryptedData += cubToDecrypt;
  795. cubEncryptedData -= cubToDecrypt;
  796. pubPlaintextData += decodingResult.messageLength;
  797. AssertFatal( decodingResult.messageLength <= ULONG_MAX );
  798. cubPlaintextData += (uint32)decodingResult.messageLength;
  799. }
  800. Assert( 0 == cubEncryptedData ); // should have no remaining encrypted data to decrypt
  801. *pcubPlaintextData = cubPlaintextData;
  802. bRet = true;
  803. }
  804. catch ( Exception e )
  805. {
  806. DMsg( SPEW_CRYPTO, 2, "CCrypto::RSADecrypt: Decrypt() threw exception %s (%d)\n",
  807. e.what(), e.GetErrorType() );
  808. }
  809. return bRet;
  810. }
  811. //-----------------------------------------------------------------------------
  812. // Purpose: Decrypts the specified data with the specified RSA PUBLIC key,
  813. // using no padding (eg un-padded signature).
  814. // Input: pubEncryptedData - Data to be decrypted
  815. // cubEncryptedData - Size of data to be decrypted
  816. // pubPlaintextData - Pointer to buffer to receive decrypted data
  817. // pcubPlaintextData - Pointer to a variable that at time of call contains the size of
  818. // the receive buffer for decrypted data. When the method returns, this will contain
  819. // the actual size of the decrypted data.
  820. // pubPublicKey - the RSA public key key to decrypt the data with
  821. // cubPublicKey - Size of the key
  822. // Output: true if successful, false if decryption failed
  823. //-----------------------------------------------------------------------------
  824. bool CCrypto::RSAPublicDecrypt_NoPadding( const uint8 *pubEncryptedData, uint32 cubEncryptedData,
  825. uint8 *pubPlaintextData, uint32 *pcubPlaintextData,
  826. const uint8 *pubPublicKey, const uint32 cubPublicKey )
  827. {
  828. VPROF_BUDGET( "CCrypto::RSADecrypt", VPROF_BUDGETGROUP_ENCRYPTION );
  829. bool bRet = false;
  830. Assert( cubEncryptedData > 0 ); // must pass in some data
  831. // BUGBUG taylor
  832. // This probably only works for reasonably small ciphertext sizes.
  833. try // handle any exceptions crypto++-5.2 may throw
  834. {
  835. StringSource stringSourcePublicKey( pubPublicKey, cubPublicKey, true );
  836. // 1. We need to use a Verifier because a Decryptor expects a private key,
  837. // which is encoded differently
  838. // 2. We are using neither PKCS1v15 padding nor SHA in any way, we are simply
  839. // using this object as a means of instantiating the key decryption function
  840. RSASSA_PKCS1v15_SHA_Verifier pub( stringSourcePublicKey );
  841. // Ask for the data to be decrypted
  842. // Caveat: this may "succeed" even if the ciphertext is bogus, so it
  843. // is up to the caller to do any MAC or other sanity checking
  844. Integer x = pub.AccessKey().ApplyFunction(Integer(pubEncryptedData, cubEncryptedData));
  845. // Result is an 'Integer', essentially a string of bytes for our
  846. // purposes though.
  847. uint32 nBytes = x.ByteCount();
  848. if ( nBytes > *pcubPlaintextData )
  849. {
  850. return false;
  851. }
  852. // don't tell it to encode to the full buffer size, because it will
  853. // pre-pad with zeros. Just squeeze it in to the first nBytes of the
  854. // buffer.
  855. x.Encode( pubPlaintextData, nBytes );
  856. *pcubPlaintextData = nBytes;
  857. bRet = true;
  858. }
  859. catch ( Exception e )
  860. {
  861. DMsg( SPEW_CRYPTO, 2, "CCrypto::RSAPublicDecrypt_NoPadding: Decrypt() threw exception %s (%d)\n",
  862. e.what(), e.GetErrorType() );
  863. }
  864. return bRet;
  865. }
  866. //-----------------------------------------------------------------------------
  867. // Purpose: Generates an RSA signature block for the specified data with the specified
  868. // RSA private key. The signature can be verified by calling RSAVerifySignature
  869. // with the RSA public key.
  870. // Input: pubData - Data to be signed
  871. // cubData - Size of data to be signed
  872. // pubSignature - Pointer to buffer to receive signature block
  873. // pcubSignature - Pointer to a variable that at time of call contains the size of
  874. // the pubSignature buffer. When the method returns, this will contain
  875. // the actual size of the signature block
  876. // pubPrivateKey - The RSA private key to use to sign the data
  877. // cubPrivateKey - Size of the key
  878. // Output: true if successful, false if signature failed
  879. //-----------------------------------------------------------------------------
  880. bool CCrypto::RSASign( const uint8 *pubData, const uint32 cubData,
  881. uint8 *pubSignature, uint32 *pcubSignature,
  882. const uint8 *pubPrivateKey, const uint32 cubPrivateKey )
  883. {
  884. VPROF_BUDGET( "CCrypto::RSASign", VPROF_BUDGETGROUP_ENCRYPTION );
  885. Assert( pubData );
  886. Assert( pubPrivateKey );
  887. Assert( cubPrivateKey > 0 );
  888. Assert( pubSignature );
  889. Assert( pcubSignature );
  890. bool bRet = false;
  891. try // handle any exceptions crypto++ may throw
  892. {
  893. StringSource stringSourcePrivateKey( pubPrivateKey, cubPrivateKey, true );
  894. RSASSA_PKCS1v15_SHA_Signer rsaSigner( stringSourcePrivateKey );
  895. CPoolAllocatedRNG rng;
  896. size_t len = rsaSigner.SignMessage( rng.GetRNG(), (byte *)pubData, cubData, pubSignature );
  897. AssertFatal( len <= ULONG_MAX );
  898. *pcubSignature = (uint32)len;
  899. bRet = true;
  900. }
  901. catch ( Exception e )
  902. {
  903. DMsg( SPEW_CRYPTO, 2, "CCrypto::RSASign: SignMessage threw exception %s (%d)\n",
  904. e.what(), e.GetErrorType() );
  905. }
  906. return bRet;
  907. }
  908. //-----------------------------------------------------------------------------
  909. // Purpose: Verifies that signature block is authentic for given data & RSA public key
  910. // Input: pubData - Data that was signed
  911. // cubData - Size of data that was signed signed
  912. // pubSignature - Signature block
  913. // cubSignature - Size of signature block
  914. // pubPublicKey - The RSA public key to use to verify the signature
  915. // (must be from same pair as RSA private key used to generate signature)
  916. // cubPublicKey - Size of the key
  917. // Output: true if successful and signature is authentic, false if signature does not match or other error
  918. //-----------------------------------------------------------------------------
  919. bool CCrypto::RSAVerifySignature( const uint8 *pubData, const uint32 cubData,
  920. const uint8 *pubSignature, const uint32 cubSignature,
  921. const uint8 *pubPublicKey, const uint32 cubPublicKey )
  922. {
  923. VPROF_BUDGET( "CCrypto::RSAVerifySignature", VPROF_BUDGETGROUP_ENCRYPTION );
  924. Assert( pubData );
  925. Assert( pubSignature );
  926. Assert( pubPublicKey );
  927. bool bRet = false;
  928. try // handle any exceptions crypto++ may throw
  929. {
  930. StringSource stringSourcePublicKey( pubPublicKey, cubPublicKey, true );
  931. RSASSA_PKCS1v15_SHA_Verifier pub( stringSourcePublicKey );
  932. bRet = pub.VerifyMessage( pubData, cubData, pubSignature, cubSignature );
  933. }
  934. catch ( Exception e )
  935. {
  936. DMsg( SPEW_CRYPTO, 2, "CCrypto::RSASign: VerifyMessage threw exception %s (%d)\n",
  937. e.what(), e.GetErrorType() );
  938. }
  939. return bRet;
  940. }
  941. //-----------------------------------------------------------------------------
  942. // Purpose: Generates an RSA signature block for the specified data with the specified
  943. // RSA private key. The signature can be verified by calling RSAVerifySignature
  944. // with the RSA public key.
  945. // Input: pubData - Data to be signed
  946. // cubData - Size of data to be signed
  947. // pubSignature - Pointer to buffer to receive signature block
  948. // pcubSignature - Pointer to a variable that at time of call contains the size of
  949. // the pubSignature buffer. When the method returns, this will contain
  950. // the actual size of the signature block
  951. // pubPrivateKey - The RSA private key to use to sign the data
  952. // cubPrivateKey - Size of the key
  953. // Output: true if successful, false if signature failed
  954. //-----------------------------------------------------------------------------
  955. bool CCrypto::RSASignSHA256( const uint8 *pubData, const uint32 cubData,
  956. uint8 *pubSignature, uint32 *pcubSignature,
  957. const uint8 *pubPrivateKey, const uint32 cubPrivateKey )
  958. {
  959. VPROF_BUDGET( "CCrypto::RSASign", VPROF_BUDGETGROUP_ENCRYPTION );
  960. Assert( pubData );
  961. Assert( pubPrivateKey );
  962. Assert( cubPrivateKey > 0 );
  963. Assert( pubSignature );
  964. Assert( pcubSignature );
  965. bool bRet = false;
  966. try // handle any exceptions crypto++ may throw
  967. {
  968. StringSource stringSourcePrivateKey( pubPrivateKey, cubPrivateKey, true );
  969. RSASS<PKCS1v15, SHA256>::Signer rsaSigner( stringSourcePrivateKey );
  970. CPoolAllocatedRNG rng;
  971. size_t len = rsaSigner.SignMessage( rng.GetRNG(), (byte *)pubData, cubData, pubSignature );
  972. AssertFatal( len <= ULONG_MAX );
  973. *pcubSignature = (uint32)len;
  974. bRet = true;
  975. }
  976. catch ( Exception e )
  977. {
  978. DMsg( SPEW_CRYPTO, 2, "CCrypto::RSASign: SignMessage threw exception %s (%d)\n",
  979. e.what(), e.GetErrorType() );
  980. }
  981. return bRet;
  982. }
  983. //-----------------------------------------------------------------------------
  984. // Purpose: Verifies that signature block is authentic for given data & RSA public key
  985. // Input: pubData - Data that was signed
  986. // cubData - Size of data that was signed signed
  987. // pubSignature - Signature block
  988. // cubSignature - Size of signature block
  989. // pubPublicKey - The RSA public key to use to verify the signature
  990. // (must be from same pair as RSA private key used to generate signature)
  991. // cubPublicKey - Size of the key
  992. // Output: true if successful and signature is authentic, false if signature does not match or other error
  993. //-----------------------------------------------------------------------------
  994. bool CCrypto::RSAVerifySignatureSHA256( const uint8 *pubData, const uint32 cubData,
  995. const uint8 *pubSignature, const uint32 cubSignature,
  996. const uint8 *pubPublicKey, const uint32 cubPublicKey )
  997. {
  998. VPROF_BUDGET( "CCrypto::RSAVerifySignature", VPROF_BUDGETGROUP_ENCRYPTION );
  999. Assert( pubData );
  1000. Assert( pubSignature );
  1001. Assert( pubPublicKey );
  1002. bool bRet = false;
  1003. try // handle any exceptions crypto++ may throw
  1004. {
  1005. StringSource stringSourcePublicKey( pubPublicKey, cubPublicKey, true );
  1006. RSASS<PKCS1v15, SHA256>::Verifier pub( stringSourcePublicKey );
  1007. bRet = pub.VerifyMessage( pubData, cubData, pubSignature, cubSignature );
  1008. }
  1009. catch ( Exception e )
  1010. {
  1011. DMsg( SPEW_CRYPTO, 2, "CCrypto::RSASign: VerifyMessage threw exception %s (%d)\n",
  1012. e.what(), e.GetErrorType() );
  1013. }
  1014. return bRet;
  1015. }
  1016. //-----------------------------------------------------------------------------
  1017. // Purpose: Hex-encodes a block of data. (Binary -> text representation.) The output
  1018. // is null-terminated and can be treated as a string.
  1019. // Input: pubData - Data to encode
  1020. // cubData - Size of data to encode
  1021. // pchEncodedData - Pointer to string buffer to store output in
  1022. // cchEncodedData - Size of pchEncodedData buffer
  1023. //-----------------------------------------------------------------------------
  1024. bool CCrypto::HexEncode( const uint8 *pubData, const uint32 cubData, char *pchEncodedData, uint32 cchEncodedData )
  1025. {
  1026. VPROF_BUDGET( "CCrypto::HexEncode", VPROF_BUDGETGROUP_ENCRYPTION );
  1027. Assert( pubData );
  1028. Assert( cubData );
  1029. Assert( pchEncodedData );
  1030. Assert( cchEncodedData > 0 );
  1031. if ( cchEncodedData < ( ( cubData * 2 ) + 1 ) )
  1032. {
  1033. Assert( cchEncodedData >= ( cubData * 2 ) + 1 ); // expands to 2x input + NULL, must have room in output buffer
  1034. *pchEncodedData = '\0';
  1035. return false;
  1036. }
  1037. ArraySink * pArraySinkOutput = new ArraySink( (byte *) pchEncodedData, cchEncodedData );
  1038. // Note: HexEncoder now owns the pointer to pOutputSink and will free it when the encoder goes out of scope and destructs
  1039. HexEncoder hexEncoder( pArraySinkOutput );
  1040. hexEncoder.Put( pubData, cubData );
  1041. hexEncoder.MessageEnd();
  1042. uint32 len = pArraySinkOutput->TotalPutLength();
  1043. if ( len >= cchEncodedData )
  1044. {
  1045. AssertMsg2( false, "CCrypto::HexEncode: insufficient output buffer for encoding, needed %d got %d\n",
  1046. len, cchEncodedData );
  1047. return false;
  1048. }
  1049. pchEncodedData[len] = 0; // NULL-terminate
  1050. return true;
  1051. }
  1052. //-----------------------------------------------------------------------------
  1053. // Purpose: Hex-decodes a block of data. (Text -> binary representation.)
  1054. // Input: pchData - Null-terminated hex-encoded string
  1055. // pubDecodedData - Pointer to buffer to store output in
  1056. // pcubDecodedData - Pointer to variable that contains size of
  1057. // output buffer. At exit, is filled in with actual size
  1058. // of decoded data.
  1059. //-----------------------------------------------------------------------------
  1060. bool CCrypto::HexDecode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData )
  1061. {
  1062. VPROF_BUDGET( "CCrypto::HexDecode", VPROF_BUDGETGROUP_ENCRYPTION );
  1063. Assert( pchData );
  1064. Assert( pubDecodedData );
  1065. Assert( pcubDecodedData );
  1066. Assert( *pcubDecodedData );
  1067. ArraySink * pArraySinkOutput = new ArraySink( pubDecodedData, *pcubDecodedData );
  1068. // Note: HexEncoder now owns the pointer to pOutputSink and will free it when the encoder goes out of scope and destructs
  1069. HexDecoder hexDecoder( pArraySinkOutput );
  1070. hexDecoder.Put( (byte *) pchData, Q_strlen( pchData ) );
  1071. hexDecoder.MessageEnd();
  1072. uint32 len = pArraySinkOutput->TotalPutLength();
  1073. if ( len > *pcubDecodedData )
  1074. {
  1075. AssertMsg2( false, "CCrypto::HexDecode: insufficient output buffer for decoding, needed %d got %d\n",
  1076. len, *pcubDecodedData );
  1077. return false;
  1078. }
  1079. *pcubDecodedData = len;
  1080. return true;
  1081. }
  1082. static const int k_LineBreakEveryNGroups = 18; // line break every 18 groups of 4 characters (every 72 characters)
  1083. //-----------------------------------------------------------------------------
  1084. // Purpose: Returns the expected buffer size that should be passed to Base64Encode.
  1085. // Input: cubData - Size of data to encode
  1086. // bInsertLineBreaks - If line breaks should be inserted automatically
  1087. //-----------------------------------------------------------------------------
  1088. uint32 CCrypto::Base64EncodeMaxOutput( const uint32 cubData, const char *pszLineBreak )
  1089. {
  1090. // terminating null + 4 chars per 3-byte group + line break after every 18 groups (72 output chars) + final line break
  1091. uint32 nGroups = (cubData+2)/3;
  1092. str_size cchRequired = 1 + nGroups*4 + ( pszLineBreak ? Q_strlen(pszLineBreak)*(1+(nGroups-1)/k_LineBreakEveryNGroups) : 0 );
  1093. return cchRequired;
  1094. }
  1095. //-----------------------------------------------------------------------------
  1096. // Purpose: Base64-encodes a block of data. (Binary -> text representation.) The output
  1097. // is null-terminated and can be treated as a string.
  1098. // Input: pubData - Data to encode
  1099. // cubData - Size of data to encode
  1100. // pchEncodedData - Pointer to string buffer to store output in
  1101. // cchEncodedData - Size of pchEncodedData buffer
  1102. // bInsertLineBreaks - If "\n" line breaks should be inserted automatically
  1103. //-----------------------------------------------------------------------------
  1104. bool CCrypto::Base64Encode( const uint8 *pubData, uint32 cubData, char *pchEncodedData, uint32 cchEncodedData, bool bInsertLineBreaks )
  1105. {
  1106. const char *pszLineBreak = bInsertLineBreaks ? "\n" : NULL;
  1107. uint32 cchRequired = Base64EncodeMaxOutput( cubData, pszLineBreak );
  1108. (void)cchRequired;
  1109. AssertMsg2( cchEncodedData >= cchRequired, "CCrypto::Base64Encode: insufficient output buffer for encoding, needed %d got %d\n", cchRequired, cchEncodedData );
  1110. return Base64Encode( pubData, cubData, pchEncodedData, &cchEncodedData, pszLineBreak );
  1111. }
  1112. //-----------------------------------------------------------------------------
  1113. // Purpose: Base64-encodes a block of data. (Binary -> text representation.) The output
  1114. // is null-terminated and can be treated as a string.
  1115. // Input: pubData - Data to encode
  1116. // cubData - Size of data to encode
  1117. // pchEncodedData - Pointer to string buffer to store output in
  1118. // pcchEncodedData - Pointer to size of pchEncodedData buffer; adjusted to number of characters written (before NULL)
  1119. // pszLineBreak - String to be inserted every 72 characters; empty string or NULL pointer for no line breaks
  1120. // Note: if pchEncodedData is NULL and *pcchEncodedData is zero, *pcchEncodedData is filled with the actual required length
  1121. // for output. A simpler approximation for maximum output size is (cubData * 4 / 3) + 5 if there are no linebreaks.
  1122. //-----------------------------------------------------------------------------
  1123. bool CCrypto::Base64Encode( const uint8 *pubData, uint32 cubData, char *pchEncodedData, uint32* pcchEncodedData, const char *pszLineBreak )
  1124. {
  1125. VPROF_BUDGET( "CCrypto::Base64Encode", VPROF_BUDGETGROUP_ENCRYPTION );
  1126. if ( pchEncodedData == NULL )
  1127. {
  1128. AssertMsg( *pcchEncodedData == 0, "NULL output buffer with non-zero size passed to Base64Encode" );
  1129. *pcchEncodedData = Base64EncodeMaxOutput( cubData, pszLineBreak );
  1130. return true;
  1131. }
  1132. const uint8 *pubDataEnd = pubData + cubData;
  1133. char *pchEncodedDataStart = pchEncodedData;
  1134. str_size unLineBreakLen = pszLineBreak ? Q_strlen( pszLineBreak ) : 0;
  1135. int nNextLineBreak = unLineBreakLen ? k_LineBreakEveryNGroups : INT_MAX;
  1136. const char * const pszBase64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  1137. uint32 cchEncodedData = *pcchEncodedData;
  1138. if ( cchEncodedData == 0 )
  1139. goto out_of_space;
  1140. --cchEncodedData; // pre-decrement for the terminating null so we don't forget about it
  1141. // input 3 x 8-bit, output 4 x 6-bit
  1142. while ( pubDataEnd - pubData >= 3 )
  1143. {
  1144. if ( cchEncodedData < 4 + unLineBreakLen )
  1145. goto out_of_space;
  1146. if ( nNextLineBreak == 0 )
  1147. {
  1148. memcpy( pchEncodedData, pszLineBreak, unLineBreakLen );
  1149. pchEncodedData += unLineBreakLen;
  1150. cchEncodedData -= unLineBreakLen;
  1151. nNextLineBreak = k_LineBreakEveryNGroups;
  1152. }
  1153. uint32 un24BitsData;
  1154. un24BitsData = (uint32) pubData[0] << 16;
  1155. un24BitsData |= (uint32) pubData[1] << 8;
  1156. un24BitsData |= (uint32) pubData[2];
  1157. pubData += 3;
  1158. pchEncodedData[0] = pszBase64Chars[ (un24BitsData >> 18) & 63 ];
  1159. pchEncodedData[1] = pszBase64Chars[ (un24BitsData >> 12) & 63 ];
  1160. pchEncodedData[2] = pszBase64Chars[ (un24BitsData >> 6) & 63 ];
  1161. pchEncodedData[3] = pszBase64Chars[ (un24BitsData ) & 63 ];
  1162. pchEncodedData += 4;
  1163. cchEncodedData -= 4;
  1164. --nNextLineBreak;
  1165. }
  1166. // Clean up remaining 1 or 2 bytes of input, pad output with '='
  1167. if ( pubData != pubDataEnd )
  1168. {
  1169. if ( cchEncodedData < 4 + unLineBreakLen )
  1170. goto out_of_space;
  1171. if ( nNextLineBreak == 0 )
  1172. {
  1173. memcpy( pchEncodedData, pszLineBreak, unLineBreakLen );
  1174. pchEncodedData += unLineBreakLen;
  1175. cchEncodedData -= unLineBreakLen;
  1176. }
  1177. uint32 un24BitsData;
  1178. un24BitsData = (uint32) pubData[0] << 16;
  1179. if ( pubData+1 != pubDataEnd )
  1180. {
  1181. un24BitsData |= (uint32) pubData[1] << 8;
  1182. }
  1183. pchEncodedData[0] = pszBase64Chars[ (un24BitsData >> 18) & 63 ];
  1184. pchEncodedData[1] = pszBase64Chars[ (un24BitsData >> 12) & 63 ];
  1185. pchEncodedData[2] = pubData+1 != pubDataEnd ? pszBase64Chars[ (un24BitsData >> 6) & 63 ] : '=';
  1186. pchEncodedData[3] = '=';
  1187. pchEncodedData += 4;
  1188. cchEncodedData -= 4;
  1189. }
  1190. if ( unLineBreakLen )
  1191. {
  1192. if ( cchEncodedData < unLineBreakLen )
  1193. goto out_of_space;
  1194. memcpy( pchEncodedData, pszLineBreak, unLineBreakLen );
  1195. pchEncodedData += unLineBreakLen;
  1196. cchEncodedData -= unLineBreakLen;
  1197. }
  1198. *pchEncodedData = 0;
  1199. *pcchEncodedData = pchEncodedData - pchEncodedDataStart;
  1200. return true;
  1201. out_of_space:
  1202. *pchEncodedData = 0;
  1203. *pcchEncodedData = Base64EncodeMaxOutput( cubData, pszLineBreak );
  1204. AssertMsg( false, "CCrypto::Base64Encode: insufficient output buffer (up to n*4/3+5 bytes required, plus linebreaks)" );
  1205. return false;
  1206. }
  1207. //-----------------------------------------------------------------------------
  1208. // Purpose: Base64-decodes a block of data. (Text -> binary representation.)
  1209. // Input: pchData - Null-terminated hex-encoded string
  1210. // pubDecodedData - Pointer to buffer to store output in
  1211. // pcubDecodedData - Pointer to variable that contains size of
  1212. // output buffer. At exit, is filled in with actual size
  1213. // of decoded data.
  1214. // Note: if NULL is passed as the output buffer and *pcubDecodedData is zero, the function
  1215. // will calculate the actual required size and place it in *pcubDecodedData. A simpler upper
  1216. // bound on the required size is ( strlen(pchData)*3/4 + 1 ).
  1217. //-----------------------------------------------------------------------------
  1218. bool CCrypto::Base64Decode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData, bool bIgnoreInvalidCharacters )
  1219. {
  1220. return Base64Decode( pchData, ~0u, pubDecodedData, pcubDecodedData, bIgnoreInvalidCharacters );
  1221. }
  1222. //-----------------------------------------------------------------------------
  1223. // Purpose: Base64-decodes a block of data. (Text -> binary representation.)
  1224. // Input: pchData - base64-encoded string, null terminated
  1225. // cchDataMax - maximum length of string unless a null is encountered first
  1226. // pubDecodedData - Pointer to buffer to store output in
  1227. // pcubDecodedData - Pointer to variable that contains size of
  1228. // output buffer. At exit, is filled in with actual size
  1229. // of decoded data.
  1230. // Note: if NULL is passed as the output buffer and *pcubDecodedData is zero, the function
  1231. // will calculate the actual required size and place it in *pcubDecodedData. A simpler upper
  1232. // bound on the required size is ( strlen(pchData)*3/4 + 2 ).
  1233. //-----------------------------------------------------------------------------
  1234. bool CCrypto::Base64Decode( const char *pchData, uint32 cchDataMax, uint8 *pubDecodedData, uint32 *pcubDecodedData, bool bIgnoreInvalidCharacters )
  1235. {
  1236. VPROF_BUDGET( "CCrypto::Base64Decode", VPROF_BUDGETGROUP_ENCRYPTION );
  1237. uint32 cubDecodedData = *pcubDecodedData;
  1238. uint32 cubDecodedDataOrig = cubDecodedData;
  1239. if ( pubDecodedData == NULL )
  1240. {
  1241. AssertMsg( *pcubDecodedData == 0, "NULL output buffer with non-zero size passed to Base64Decode" );
  1242. cubDecodedDataOrig = cubDecodedData = ~0u;
  1243. }
  1244. // valid base64 character range: '+' (0x2B) to 'z' (0x7A)
  1245. // table entries are 0-63, -1 for invalid entries, -2 for '='
  1246. static const char rgchInvBase64[] = {
  1247. 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
  1248. -1, -1, -1, -2, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7,
  1249. 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
  1250. 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
  1251. 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
  1252. 47, 48, 49, 50, 51
  1253. };
  1254. COMPILE_TIME_ASSERT( Q_ARRAYSIZE(rgchInvBase64) == 0x7A - 0x2B + 1 );
  1255. uint32 un24BitsWithSentinel = 1;
  1256. while ( cchDataMax-- > 0 )
  1257. {
  1258. char c = *pchData++;
  1259. if ( (uint8)(c - 0x2B) >= Q_ARRAYSIZE( rgchInvBase64 ) )
  1260. {
  1261. if ( c == '\0' )
  1262. break;
  1263. if ( !bIgnoreInvalidCharacters && !( c == '\r' || c == '\n' || c == '\t' || c == ' ' ) )
  1264. goto decode_failed;
  1265. else
  1266. continue;
  1267. }
  1268. c = rgchInvBase64[(uint8)(c - 0x2B)];
  1269. if ( c < 0 )
  1270. {
  1271. if ( c == -2 ) // -2 -> terminating '='
  1272. break;
  1273. if ( !bIgnoreInvalidCharacters )
  1274. goto decode_failed;
  1275. else
  1276. continue;
  1277. }
  1278. un24BitsWithSentinel <<= 6;
  1279. un24BitsWithSentinel |= c;
  1280. if ( un24BitsWithSentinel & (1<<24) )
  1281. {
  1282. if ( cubDecodedData < 3 ) // out of space? go to final write logic
  1283. break;
  1284. if ( pubDecodedData )
  1285. {
  1286. pubDecodedData[0] = (uint8)( un24BitsWithSentinel >> 16 );
  1287. pubDecodedData[1] = (uint8)( un24BitsWithSentinel >> 8);
  1288. pubDecodedData[2] = (uint8)( un24BitsWithSentinel );
  1289. pubDecodedData += 3;
  1290. }
  1291. cubDecodedData -= 3;
  1292. un24BitsWithSentinel = 1;
  1293. }
  1294. }
  1295. // If un24BitsWithSentinel contains data, output the remaining full bytes
  1296. if ( un24BitsWithSentinel >= (1<<6) )
  1297. {
  1298. // Possibilities are 3, 2, 1, or 0 full output bytes.
  1299. int nWriteBytes = 3;
  1300. while ( un24BitsWithSentinel < (1<<24) )
  1301. {
  1302. nWriteBytes--;
  1303. un24BitsWithSentinel <<= 6;
  1304. }
  1305. // Write completed bytes to output
  1306. while ( nWriteBytes-- > 0 )
  1307. {
  1308. if ( cubDecodedData == 0 )
  1309. {
  1310. AssertMsg( false, "CCrypto::Base64Decode: insufficient output buffer (up to n*3/4+2 bytes required)" );
  1311. goto decode_failed;
  1312. }
  1313. if ( pubDecodedData )
  1314. {
  1315. *pubDecodedData++ = (uint8)(un24BitsWithSentinel >> 16);
  1316. }
  1317. --cubDecodedData;
  1318. un24BitsWithSentinel <<= 8;
  1319. }
  1320. }
  1321. *pcubDecodedData = cubDecodedDataOrig - cubDecodedData;
  1322. return true;
  1323. decode_failed:
  1324. *pcubDecodedData = cubDecodedDataOrig - cubDecodedData;
  1325. return false;
  1326. }
  1327. //-----------------------------------------------------------------------------
  1328. // Purpose: Generate a SHA1 hash
  1329. // Input: pchInput - Plaintext string of item to hash (null terminated)
  1330. // pOutDigest - Pointer to receive hashed digest output
  1331. //-----------------------------------------------------------------------------
  1332. bool CCrypto::GenerateSHA1Digest( const uint8 *pubInput, const int cubInput, SHADigest_t *pOutDigest )
  1333. {
  1334. VPROF_BUDGET( "CCrypto::GenerateSHA1Digest", VPROF_BUDGETGROUP_ENCRYPTION );
  1335. Assert( pubInput );
  1336. Assert( cubInput > 0 );
  1337. Assert( pOutDigest );
  1338. bool bSuccess = true;
  1339. try
  1340. {
  1341. CryptoPP::SHA().CalculateDigest( *pOutDigest, pubInput, cubInput );
  1342. }
  1343. catch(...)
  1344. {
  1345. bSuccess = false;
  1346. }
  1347. return bSuccess;
  1348. }
  1349. //-----------------------------------------------------------------------------
  1350. // Purpose: Generate a hash Salt - be careful, over-writing an existing salt
  1351. // will render the hashed value unverifiable.
  1352. //-----------------------------------------------------------------------------
  1353. bool CCrypto::GenerateSalt( Salt_t *pSalt )
  1354. {
  1355. VPROF_BUDGET( "CCrypto::GenerateSalt", VPROF_BUDGETGROUP_ENCRYPTION );
  1356. Assert( pSalt );
  1357. bool bSuccess = true;
  1358. try
  1359. {
  1360. CPoolAllocatedRNG rng;
  1361. rng.GetRNG().GenerateBlock( (byte*)pSalt, sizeof(Salt_t) );
  1362. }
  1363. catch(...)
  1364. {
  1365. bSuccess = false;
  1366. }
  1367. return bSuccess;
  1368. }
  1369. //-----------------------------------------------------------------------------
  1370. // Purpose: Generate a SHA1 hash using a salt.
  1371. // Input: pchInput - Plaintext string of item to hash (null terminated)
  1372. // pSalt - Salt
  1373. // pOutDigest - Pointer to receive salted digest output
  1374. //-----------------------------------------------------------------------------
  1375. bool CCrypto::GenerateSaltedSHA1Digest( const char *pchInput, const Salt_t *pSalt, SHADigest_t *pOutDigest )
  1376. {
  1377. VPROF_BUDGET( "CCrypto::GenerateSaltedSHA1Digest", VPROF_BUDGETGROUP_ENCRYPTION );
  1378. Assert( pchInput );
  1379. Assert( pSalt );
  1380. Assert( pOutDigest );
  1381. int iInputLen = Q_strlen( pchInput );
  1382. uint8 *pubSaltedInput = new uint8[ iInputLen + sizeof( Salt_t ) ];
  1383. // Insert half the salt before the input string and half at the end.
  1384. // This is probably unnecessary (to split the salt) but we're stuck with it for historical reasons.
  1385. uint8 *pubCursor = pubSaltedInput;
  1386. Q_memcpy( pubCursor, (uint8 *)pSalt, sizeof(Salt_t) / 2 );
  1387. pubCursor += sizeof( Salt_t ) / 2;
  1388. Q_memcpy( pubCursor, pchInput, iInputLen );
  1389. pubCursor += iInputLen;
  1390. Q_memcpy( pubCursor, (uint8 *)pSalt + sizeof(Salt_t) / 2, sizeof(Salt_t) / 2 );
  1391. bool bSuccess = true;
  1392. try
  1393. {
  1394. CryptoPP::SHA().CalculateDigest( *pOutDigest, pubSaltedInput, iInputLen + sizeof( Salt_t ) );
  1395. }
  1396. catch(...)
  1397. {
  1398. bSuccess = false;
  1399. }
  1400. delete [] pubSaltedInput;
  1401. return bSuccess;
  1402. }
  1403. //-----------------------------------------------------------------------------
  1404. // Purpose: Generates a random block of data
  1405. //-----------------------------------------------------------------------------
  1406. bool CCrypto::GenerateRandomBlock( uint8 *pubDest, int cubDest )
  1407. {
  1408. CPoolAllocatedRNG rng;
  1409. rng.GetRNG().GenerateBlock( pubDest, cubDest );
  1410. return true;
  1411. }
  1412. //-----------------------------------------------------------------------------
  1413. // Purpose: Generate a keyed-hash MAC using SHA1
  1414. // Input: pubData - Plaintext data to digest
  1415. // cubData - length of data
  1416. // pubKey - key to use in HMAC
  1417. // cubKey - length of key
  1418. // pOutDigest - Pointer to receive hashed digest output
  1419. //-----------------------------------------------------------------------------
  1420. bool CCrypto::GenerateHMAC( const uint8 *pubData, uint32 cubData, const uint8 *pubKey, uint32 cubKey, SHADigest_t *pOutputDigest )
  1421. {
  1422. VPROF_BUDGET( "CCrypto::GenerateHMAC", VPROF_BUDGETGROUP_ENCRYPTION );
  1423. Assert( pubData );
  1424. Assert( cubData > 0 );
  1425. Assert( pubKey );
  1426. Assert( cubKey > 0 );
  1427. Assert( pOutputDigest );
  1428. bool bSuccess = true;
  1429. try
  1430. {
  1431. CryptoPP::HMAC< CryptoPP::SHA1 > hmac( pubKey, cubKey );
  1432. hmac.CalculateDigest( *pOutputDigest, pubData, cubData );
  1433. }
  1434. catch(...)
  1435. {
  1436. bSuccess = false;
  1437. }
  1438. return bSuccess;
  1439. }
  1440. //-----------------------------------------------------------------------------
  1441. // Purpose: Generate a keyed-hash MAC using SHA-256
  1442. //-----------------------------------------------------------------------------
  1443. bool CCrypto::GenerateHMAC256( const uint8 *pubData, uint32 cubData, const uint8 *pubKey, uint32 cubKey, SHA256Digest_t *pOutputDigest )
  1444. {
  1445. VPROF_BUDGET( "CCrypto::GenerateHMAC256", VPROF_BUDGETGROUP_ENCRYPTION );
  1446. Assert( pubData );
  1447. Assert( cubData > 0 );
  1448. Assert( pubKey );
  1449. Assert( cubKey > 0 );
  1450. Assert( pOutputDigest );
  1451. bool bSuccess = true;
  1452. try
  1453. {
  1454. CryptoPP::HMAC< CryptoPP::SHA256 > hmac( pubKey, cubKey );
  1455. hmac.CalculateDigest( *pOutputDigest, pubData, cubData );
  1456. }
  1457. catch(...)
  1458. {
  1459. bSuccess = false;
  1460. }
  1461. return bSuccess;
  1462. }
  1463. bool CCrypto::BGzipBuffer( const uint8 *pubData, uint32 cubData, CCryptoOutBuffer &bufOutput )
  1464. {
  1465. bool bSuccess = true;
  1466. try
  1467. {
  1468. std::string gzip_output;
  1469. StringSource( (byte *)pubData, cubData, true, new Gzip( new StringSink( gzip_output ) ) );
  1470. bufOutput.Set( (uint8*)gzip_output.c_str(), (uint32)gzip_output.length() );
  1471. }
  1472. catch( ... )
  1473. {
  1474. bSuccess = false;
  1475. }
  1476. return bSuccess;
  1477. }
  1478. bool CCrypto::BGunzipBuffer( const uint8 *pubData, uint32 cubData, CCryptoOutBuffer &bufOutput )
  1479. {
  1480. bool bSuccess = true;
  1481. try
  1482. {
  1483. std::string gunzip_output;
  1484. StringSource( (byte *)pubData, cubData, true, new Gunzip( new StringSink( gunzip_output ) ) );
  1485. bufOutput.Set( (uint8*)gunzip_output.c_str(), (uint32)gunzip_output.length() );
  1486. }
  1487. catch( ... )
  1488. {
  1489. bSuccess = false;
  1490. }
  1491. return bSuccess;
  1492. }
  1493. //! These are all needed to get around stack-overflow bug in Initialize()
  1494. class HexDecoderTKS : public HexDecoder
  1495. {
  1496. public:
  1497. HexDecoderTKS(BufferedTransformation *attachment, const int *pnDecodingArray)
  1498. : HexDecoder(attachment)
  1499. {
  1500. BaseN_Decoder::IsolatedInitialize( MakeParameters( Name::DecodingLookupArray(), pnDecodingArray )( Name::Log2Base(), 4 ) );
  1501. }
  1502. };
  1503. class Base32DecoderTKS : public Base32Decoder
  1504. {
  1505. public:
  1506. Base32DecoderTKS(BufferedTransformation *attachment, const int *pnDecodingArray)
  1507. : Base32Decoder(attachment)
  1508. {
  1509. BaseN_Decoder::IsolatedInitialize( MakeParameters( Name::DecodingLookupArray(), pnDecodingArray )( Name::Log2Base(), 5 ) );
  1510. }
  1511. };
  1512. //-----------------------------------------------------------------------------
  1513. // Purpose: Implement hex encoding / decoding using a custom lookup table.
  1514. // This is a class because the decoding is done via a generated
  1515. // reverse-lookup table, and to save time it's best to just create
  1516. // that table once.
  1517. //-----------------------------------------------------------------------------
  1518. CCustomHexEncoder::CCustomHexEncoder( const char *pchEncodingTable )
  1519. {
  1520. m_bValidEncoding = false;
  1521. if ( Q_strlen( pchEncodingTable ) == sizeof( m_rgubEncodingTable ) )
  1522. {
  1523. Q_memcpy( m_rgubEncodingTable, pchEncodingTable, sizeof( m_rgubEncodingTable ) );
  1524. BaseN_Decoder::InitializeDecodingLookupArray( m_rgnDecodingTable, m_rgubEncodingTable, 16, false );
  1525. m_bValidEncoding = true;
  1526. }
  1527. else
  1528. {
  1529. AssertMsg( false, "CCrypto::CustomHexEncoder: Improper encoding table\n" );
  1530. }
  1531. }
  1532. //-----------------------------------------------------------------------------
  1533. // Purpose: Destructor
  1534. //-----------------------------------------------------------------------------
  1535. CCustomHexEncoder::~CCustomHexEncoder()
  1536. {
  1537. }
  1538. //-----------------------------------------------------------------------------
  1539. // Purpose: Hex-encodes a block of data. (Binary -> text representation.) The output
  1540. // is null-terminated and can be treated as a string.
  1541. // Uses the supplied custom encoding characters
  1542. // Input: pubData - Data to encode
  1543. // cubData - Size of data to encode
  1544. // pchEncodedData - Pointer to string buffer to store output in
  1545. // cchEncodedData - Size of pchEncodedData buffer
  1546. //-----------------------------------------------------------------------------
  1547. bool CCustomHexEncoder::Encode( const uint8 *pubData, const uint32 cubData, char *pchEncodedData, uint32 cchEncodedData )
  1548. {
  1549. VPROF_BUDGET( "CCrypto::CustomHexEncode", VPROF_BUDGETGROUP_ENCRYPTION );
  1550. Assert( pubData );
  1551. Assert( cubData );
  1552. Assert( pchEncodedData );
  1553. Assert( cchEncodedData > 0 );
  1554. if ( !m_bValidEncoding )
  1555. return false;
  1556. ArraySink * pArraySinkOutput = new ArraySink( (byte *) pchEncodedData, cchEncodedData );
  1557. // Note: HexEncoder now owns the pointer to pOutputSink and will free it when the encoder goes out of scope and destructs
  1558. HexEncoder hexEncoder( pArraySinkOutput );
  1559. hexEncoder.IsolatedInitialize( MakeParameters( Name::EncodingLookupArray(), (const uint8 *)m_rgubEncodingTable ) );
  1560. hexEncoder.Put( pubData, cubData );
  1561. hexEncoder.MessageEnd();
  1562. uint32 len = pArraySinkOutput->TotalPutLength();
  1563. pchEncodedData[len] = 0; // NULL-terminate
  1564. if ( len >= cchEncodedData )
  1565. {
  1566. AssertMsg2( false, "CCrypto::CustomHexEncode: insufficient output buffer for encoding, needed %d got %d\n",
  1567. len, cchEncodedData );
  1568. return false;
  1569. }
  1570. return true;
  1571. }
  1572. //-----------------------------------------------------------------------------
  1573. // Purpose: Hex-decodes a block of data. (Text -> binary representation.)
  1574. // With custom encoding-table
  1575. // Input: pchData - Null-terminated hex-encoded string
  1576. // pubDecodedData - Pointer to buffer to store output in
  1577. // pcubDecodedData - Pointer to variable that contains size of
  1578. // output buffer. At exit, is filled in with actual size
  1579. // of decoded data.
  1580. //-----------------------------------------------------------------------------
  1581. bool CCustomHexEncoder::Decode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData )
  1582. {
  1583. VPROF_BUDGET( "CCrypto::CustomHexDecode", VPROF_BUDGETGROUP_ENCRYPTION );
  1584. Assert( pchData );
  1585. Assert( pubDecodedData );
  1586. Assert( pcubDecodedData );
  1587. Assert( *pcubDecodedData );
  1588. if ( !m_bValidEncoding )
  1589. return false;
  1590. ArraySink * pArraySinkOutput = new ArraySink( pubDecodedData, *pcubDecodedData );
  1591. // Note: HexEncoder now owns the pointer to pOutputSink and will free it when the encoder goes out of scope and destructs
  1592. HexDecoderTKS hexDecoder( pArraySinkOutput, (const int *)m_rgnDecodingTable );
  1593. hexDecoder.Put( (byte *) pchData, Q_strlen( pchData ) );
  1594. hexDecoder.MessageEnd();
  1595. uint32 len = pArraySinkOutput->TotalPutLength();
  1596. if ( len > *pcubDecodedData )
  1597. {
  1598. AssertMsg2( false, "CCrypto::CustomHexDecode: insufficient output buffer for decoding, needed %d got %d\n",
  1599. len, *pcubDecodedData );
  1600. return false;
  1601. }
  1602. *pcubDecodedData = len;
  1603. return true;
  1604. }
  1605. //-----------------------------------------------------------------------------
  1606. // Purpose: Implement hex encoding / decoding using a custom lookup table.
  1607. // This is a class because the decoding is done via a generated
  1608. // reverse-lookup table, and to save time it's best to just create
  1609. // that table once.
  1610. //-----------------------------------------------------------------------------
  1611. CCustomBase32Encoder::CCustomBase32Encoder( const char *pchEncodingTable )
  1612. {
  1613. m_bValidEncoding = false;
  1614. if ( Q_strlen( pchEncodingTable ) == sizeof( m_rgubEncodingTable ) )
  1615. {
  1616. Q_memcpy( m_rgubEncodingTable, pchEncodingTable, sizeof( m_rgubEncodingTable ) );
  1617. BaseN_Decoder::InitializeDecodingLookupArray( m_rgnDecodingTable, m_rgubEncodingTable, 32, false );
  1618. m_bValidEncoding = true;
  1619. }
  1620. else
  1621. {
  1622. AssertMsg( false, "CCrypto::CustomBase32Encoder: Improper encoding table\n" );
  1623. }
  1624. }
  1625. //-----------------------------------------------------------------------------
  1626. // Purpose: Destructor
  1627. //-----------------------------------------------------------------------------
  1628. CCustomBase32Encoder::~CCustomBase32Encoder()
  1629. {
  1630. }
  1631. //-----------------------------------------------------------------------------
  1632. // Purpose: Base32-encodes a block of data. (Binary -> text representation.) The output
  1633. // is null-terminated and can be treated as a string.
  1634. // Uses the supplied custom encoding table
  1635. // Input: pubData - Data to encode
  1636. // cubData - Size of data to encode
  1637. // pchEncodedData - Pointer to string buffer to store output in
  1638. // cchEncodedData - Size of pchEncodedData buffer
  1639. //-----------------------------------------------------------------------------
  1640. bool CCustomBase32Encoder::Encode( const uint8 *pubData, const uint32 cubData, char *pchEncodedData, uint32 cchEncodedData )
  1641. {
  1642. VPROF_BUDGET( "CCrypto::CustomBase32Encode", VPROF_BUDGETGROUP_ENCRYPTION );
  1643. Assert( pubData );
  1644. Assert( cubData );
  1645. Assert( pchEncodedData );
  1646. Assert( cchEncodedData > 0 );
  1647. if ( !m_bValidEncoding )
  1648. return false;
  1649. ArraySink * pArraySinkOutput = new ArraySink( (byte *) pchEncodedData, cchEncodedData );
  1650. // Note: Base32Encoder now owns the pointer to pOutputSink and will free it when the encoder goes out of scope and destructs
  1651. Base32Encoder base32Encoder( pArraySinkOutput );
  1652. base32Encoder.IsolatedInitialize( MakeParameters( Name::EncodingLookupArray(), (const uint8 *)m_rgubEncodingTable ) );
  1653. base32Encoder.Put( pubData, cubData );
  1654. base32Encoder.MessageEnd();
  1655. uint32 len = pArraySinkOutput->TotalPutLength();
  1656. pchEncodedData[len] = 0; // NULL-terminate
  1657. if ( len >= cchEncodedData )
  1658. {
  1659. AssertMsg2( false, "CCrypto::CustomBase32Encode: insufficient output buffer for encoding, needed %d got %d\n",
  1660. len, cchEncodedData );
  1661. return false;
  1662. }
  1663. return true;
  1664. }
  1665. //-----------------------------------------------------------------------------
  1666. // Purpose: Base32-decodes a block of data. (Text -> binary representation.)
  1667. // With custom encoding table
  1668. // Input: pchData - Null-terminated hex-encoded string
  1669. // pubDecodedData - Pointer to buffer to store output in
  1670. // pcubDecodedData - Pointer to variable that contains size of
  1671. // output buffer. At exit, is filled in with actual size
  1672. // of decoded data.
  1673. //-----------------------------------------------------------------------------
  1674. bool CCustomBase32Encoder::Decode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData )
  1675. {
  1676. VPROF_BUDGET( "CCrypto::CustomBase32Decode", VPROF_BUDGETGROUP_ENCRYPTION );
  1677. Assert( pchData );
  1678. Assert( pubDecodedData );
  1679. Assert( pcubDecodedData );
  1680. Assert( *pcubDecodedData );
  1681. if ( !m_bValidEncoding )
  1682. return false;
  1683. ArraySink * pArraySinkOutput = new ArraySink( pubDecodedData, *pcubDecodedData );
  1684. // Note: Base32Encoder now owns the pointer to pOutputSink and will free it when the encoder goes out of scope and destructs
  1685. Base32DecoderTKS base32Decoder( pArraySinkOutput, (const int *)m_rgnDecodingTable );
  1686. base32Decoder.Put( (byte *) pchData, Q_strlen( pchData ) );
  1687. base32Decoder.MessageEnd();
  1688. uint32 len = pArraySinkOutput->TotalPutLength();
  1689. if ( len > *pcubDecodedData )
  1690. {
  1691. AssertMsg2( false, "CCrypto::CustomBase32Decode: insufficient output buffer for decoding, needed %d got %d\n",
  1692. len, *pcubDecodedData );
  1693. return false;
  1694. }
  1695. *pcubDecodedData = len;
  1696. return true;
  1697. }
  1698. //-----------------------------------------------------------------------------
  1699. // Purpose: Base32-encodes a block of data. (Binary -> text representation.) The output
  1700. // is null-terminated and can be treated as a string.
  1701. // Uses the supplied custom encoding table, and a bit-stream input source
  1702. // (not necessarily an integer number of bytes).
  1703. // Input: pBitStringData - Data to encode
  1704. // pchEncodedData - Pointer to string buffer to store output in
  1705. // cchEncodedData - Size of pchEncodedData buffer
  1706. //-----------------------------------------------------------------------------
  1707. bool CCustomBase32Encoder::Encode( CSimpleBitString *pBitStringData, char *pchEncodedData, uint32 cchEncodedData )
  1708. {
  1709. // This is useful if you have, say, 125 bits of information and
  1710. // want to encode them into 25 base32-encoded characters.
  1711. uint32 cBits = pBitStringData->GetCurrNumBits();
  1712. uint32 cCharacters = (cBits / 5);
  1713. uint32 cBitsRemainder = cBits % 5;
  1714. if ( cBitsRemainder )
  1715. cCharacters++;
  1716. // GTE because of NULL
  1717. if ( cCharacters >= cchEncodedData )
  1718. return false;
  1719. CSimpleBitString::iterator itBitString( *pBitStringData );
  1720. uint ich = 0;
  1721. for ( ; ich < cCharacters; ++ich )
  1722. {
  1723. uint32 unCodon = itBitString.GetNextBits( 5 );
  1724. // Pad w/ zero bits to integer num codons
  1725. if ( ich == (cCharacters - 1) )
  1726. unCodon <<= cBitsRemainder;
  1727. pchEncodedData[ich] = m_rgubEncodingTable[ unCodon ];
  1728. }
  1729. // NULL
  1730. pchEncodedData[ich] = 0;
  1731. return true;
  1732. }
  1733. //-----------------------------------------------------------------------------
  1734. // Purpose: Base32-decodes a block of data. (Text -> binary representation.)
  1735. // With custom encoding table, and a BitString output
  1736. // Input: pchData - Null-terminated base32-encoded string
  1737. // pBitStringDecodedData - Pointer to BitString to receive decoded data
  1738. //-----------------------------------------------------------------------------
  1739. bool CCustomBase32Encoder::Decode( const char *pchData, CSimpleBitString *pBitStringDecodedData )
  1740. {
  1741. // Note: 25 base32-encoded characters contain 125 bits of information.
  1742. // Decoded into a byte buffer, this yields 15 bytes plus 5 bits of padding.
  1743. // Decoded into a CSimpleBitString, it will yield all 125 bits
  1744. while ( *pchData )
  1745. {
  1746. uint32 unData = m_rgnDecodingTable[(unsigned)*pchData++];
  1747. if ( unData == 0xFFFFFFFF )
  1748. return false;
  1749. pBitStringDecodedData->AppendBits( unData, 5 );
  1750. }
  1751. return true;
  1752. }
  1753. #ifdef DBGFLAG_VALIDATE
  1754. //-----------------------------------------------------------------------------
  1755. // Purpose: validates memory structures
  1756. //-----------------------------------------------------------------------------
  1757. void CCrypto::ValidateStatics( CValidator &validator, const char *pchName )
  1758. {
  1759. ValidateObj( g_tslistPAutoSeededRNG );
  1760. }
  1761. #endif // DBGFLAG_VALIDATE
  1762. //-----------------------------------------------------------------------------
  1763. // Purpose: Given a plaintext password, check whether it matches an existing
  1764. // hash
  1765. //-----------------------------------------------------------------------------
  1766. bool CCrypto::BValidatePasswordHash( const char *pchInput, EPasswordHashAlg hashType, const PasswordHash_t &DigestStored, const Salt_t &Salt, PasswordHash_t *pDigestComputed )
  1767. {
  1768. VPROF_BUDGET( "CCrypto::BValidatePasswordHash", VPROF_BUDGETGROUP_ENCRYPTION );
  1769. bool bResult = false;
  1770. size_t cDigest = k_HashLengths[hashType];
  1771. Assert( cDigest != 0 );
  1772. PasswordHash_t tmpDigest;
  1773. PasswordHash_t *pOutputDigest = pDigestComputed;
  1774. if ( pOutputDigest == NULL )
  1775. {
  1776. pOutputDigest = &tmpDigest;
  1777. }
  1778. BGeneratePasswordHash( pchInput, hashType, Salt, *pOutputDigest );
  1779. bResult = ( 0 == Q_memcmp( &DigestStored, pOutputDigest, cDigest ) );
  1780. return bResult;
  1781. }
  1782. //-----------------------------------------------------------------------------
  1783. // Purpose: Given a plaintext password and salt, generate a password hash of
  1784. // the requested type.
  1785. //-----------------------------------------------------------------------------
  1786. bool CCrypto::BGeneratePasswordHash( const char *pchInput, EPasswordHashAlg hashType, const Salt_t &Salt, PasswordHash_t &OutPasswordHash )
  1787. {
  1788. VPROF_BUDGET( "CCrypto::BGeneratePasswordHash", VPROF_BUDGETGROUP_ENCRYPTION );
  1789. bool bResult = false;
  1790. size_t cDigest = k_HashLengths[hashType];
  1791. switch ( hashType )
  1792. {
  1793. case k_EHashSHA1:
  1794. bResult = CCrypto::GenerateSaltedSHA1Digest( pchInput, &Salt, (SHADigest_t *)&OutPasswordHash.sha );
  1795. break;
  1796. case k_EHashBigPassword:
  1797. {
  1798. //
  1799. // This is a fake algorithm to test widening of the column. It's a salted SHA-1 hash with 0x01 padding
  1800. // on either side of it.
  1801. //
  1802. size_t cDigestSHA1 = k_HashLengths[k_EHashSHA1];
  1803. size_t cPadding = ( cDigest - cDigestSHA1 ) / 2;
  1804. AssertMsg( ( ( cDigest - cDigestSHA1 ) % 2 ) == 0, "Invalid hash width for k_EHashBigPassword, needs to be even." );
  1805. CCrypto::GenerateSaltedSHA1Digest( pchInput, &Salt, (SHADigest_t *)( (uint8 *)&OutPasswordHash.bigpassword + cPadding ) );
  1806. Q_memset( (uint8 *)&OutPasswordHash, 0x01, cPadding );
  1807. Q_memset( (uint8 *)&OutPasswordHash + cPadding + cDigestSHA1 , 0x01, cPadding );
  1808. bResult = true;
  1809. break;
  1810. }
  1811. case k_EHashPBKDF2_1000:
  1812. bResult = CCrypto::BGeneratePBKDF2Hash( pchInput, Salt, 1000, OutPasswordHash );
  1813. break;
  1814. case k_EHashPBKDF2_5000:
  1815. bResult = CCrypto::BGeneratePBKDF2Hash( pchInput, Salt, 5000, OutPasswordHash );
  1816. break;
  1817. case k_EHashPBKDF2_10000:
  1818. bResult = CCrypto::BGeneratePBKDF2Hash( pchInput, Salt, 10000, OutPasswordHash );
  1819. break;
  1820. case k_EHashSHA1WrappedWithPBKDF2_10000:
  1821. bResult = CCrypto::BGenerateWrappedSHA1PasswordHash( pchInput, Salt, 10000, OutPasswordHash );
  1822. break;
  1823. default:
  1824. AssertMsg1( false, "Invalid password hash type %u passed to BGeneratePasswordHash\n", hashType );
  1825. bResult = false;
  1826. }
  1827. return bResult;
  1828. }
  1829. //-----------------------------------------------------------------------------
  1830. // Purpose: Given a plaintext password and salt and a count of rounds, generate a PBKDF2 hash
  1831. // with the requested number of rounds.
  1832. //-----------------------------------------------------------------------------
  1833. bool CCrypto::BGeneratePBKDF2Hash( const char* pchInput, const Salt_t &Salt, unsigned int rounds, PasswordHash_t &OutPasswordHash )
  1834. {
  1835. PKCS5_PBKDF2_HMAC<SHA256> pbkdf;
  1836. unsigned int iterations = pbkdf.DeriveKey( (byte *)&OutPasswordHash.pbkdf2, sizeof(OutPasswordHash.pbkdf2), 0, (const byte *)pchInput, Q_strlen(pchInput), (const byte *)&Salt, sizeof(Salt), rounds );
  1837. return ( iterations == rounds );
  1838. }
  1839. //-----------------------------------------------------------------------------
  1840. // Purpose: Given a plaintext password and salt and a count of rounds, generate a SHA1 hash wrapped with
  1841. // a PBKDF2 hash with the specified number of rounds.
  1842. // Used to provide a stronger password hash for accounts that haven't logged in in a while.
  1843. //-----------------------------------------------------------------------------
  1844. bool CCrypto::BGenerateWrappedSHA1PasswordHash( const char *pchInput, const Salt_t &Salt, unsigned int rounds, PasswordHash_t &OutPasswordHash )
  1845. {
  1846. bool bResult;
  1847. bResult = CCrypto::GenerateSaltedSHA1Digest( pchInput, &Salt, (SHADigest_t *)&OutPasswordHash.sha );
  1848. if ( bResult )
  1849. {
  1850. PKCS5_PBKDF2_HMAC<SHA256> pbkdf;
  1851. unsigned int iterations = pbkdf.DeriveKey( (byte *)&OutPasswordHash.pbkdf2, sizeof(OutPasswordHash.pbkdf2), 0, (const byte *)&OutPasswordHash.sha, sizeof(OutPasswordHash.sha), (const byte *)&Salt, sizeof(Salt), rounds );
  1852. bResult = ( iterations == rounds );
  1853. }
  1854. return bResult;
  1855. }
  1856. //-----------------------------------------------------------------------------
  1857. // Purpose: Given an existing password hash and salt, attempt to construct a stronger
  1858. // password hash and return the new hash type.
  1859. //
  1860. // Currently the only transformation available is from a SHA1 (or BigPassword)
  1861. // hash to a PBKDF2 hash with 10,000 rounds. In the future this function
  1862. // may be extended to allow additional transformations.
  1863. //-----------------------------------------------------------------------------
  1864. bool CCrypto::BUpgradeOrWrapPasswordHash( PasswordHash_t &InPasswordHash, EPasswordHashAlg hashTypeIn, const Salt_t &Salt, PasswordHash_t &OutPasswordHash, EPasswordHashAlg &hashTypeOut )
  1865. {
  1866. bool bResult = true;;
  1867. if ( hashTypeIn == k_EHashSHA1 || hashTypeIn == k_EHashBigPassword )
  1868. {
  1869. //
  1870. // Can wrap a SHA1 hash with any PBKDF variant, but right now only 10,000 rounds is
  1871. // implemented.
  1872. //
  1873. if ( hashTypeOut == k_EHashPBKDF2_10000 )
  1874. {
  1875. hashTypeOut = k_EHashSHA1WrappedWithPBKDF2_10000;
  1876. byte * pbHash;
  1877. if ( hashTypeIn == k_EHashSHA1 )
  1878. {
  1879. pbHash = (byte *)&InPasswordHash.sha;
  1880. }
  1881. else
  1882. {
  1883. //
  1884. // Need to unroll BigPasswordHash into unpadded SHA1
  1885. //
  1886. size_t cDigest = k_HashLengths[k_EHashBigPassword];
  1887. size_t cDigestSHA1 = k_HashLengths[k_EHashSHA1];
  1888. size_t cPadding = ( cDigest - cDigestSHA1 ) / 2;
  1889. AssertMsg( ( ( cDigest - cDigestSHA1 ) % 2 ) == 0, "Invalid hash width for k_EHashBigPassword, needs to be even." );
  1890. pbHash = (byte *)&InPasswordHash.sha + cPadding;
  1891. }
  1892. PKCS5_PBKDF2_HMAC<SHA256> pbkdf;
  1893. PasswordHash_t passOut;
  1894. unsigned int iterations = pbkdf.DeriveKey( (byte *)passOut.pbkdf2, sizeof(passOut.pbkdf2), 0, pbHash, k_HashLengths[k_EHashSHA1], (const byte *)&Salt, sizeof(Salt), 10000 );
  1895. bResult = ( iterations == 10000 );
  1896. if ( bResult )
  1897. {
  1898. Q_memcpy( &OutPasswordHash, &passOut, sizeof(OutPasswordHash) );
  1899. }
  1900. }
  1901. else
  1902. {
  1903. Assert( hashTypeOut == k_EHashPBKDF2_10000 );
  1904. bResult = false;
  1905. }
  1906. }
  1907. else
  1908. {
  1909. bResult = false;
  1910. Assert( false );
  1911. }
  1912. return bResult;
  1913. }