diff --git a/build.sh b/build.sh index 9c5bf576..5e1218e0 100755 --- a/build.sh +++ b/build.sh @@ -2,4 +2,4 @@ # example: ./build.sh everything togl -make NO_CHROOT=1 -f $1.mak $2 -j$(nproc --all) +make MAKE_VERBOSE=1 NO_CHROOT=1 -f $1.mak $2 -j$(nproc --all) diff --git a/common/crypto.cpp b/common/crypto.cpp deleted file mode 100644 index 2805b78e..00000000 --- a/common/crypto.cpp +++ /dev/null @@ -1,2219 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// Note: not using precompiled headers. The crypto++ headers create gunk that anyone including them -// has to link to, so they can't be included in the global project file. They also contain -// string functions which are deprecated by the global project file so they can't be included after, either. -// So we can't use the global precompiled header, need to manually include the things we need. - -#include "winlite.h" - -#ifdef POSIX -#include -#include -#endif - -/* this stuff needs to be before the crypto headers, as it relies on memdbg, which doesn't - do the right thing in the face of xdebug getting included below */ -// tier0 -//#include "tier0/tier0.h" -#include "tier0/basetypes.h" -#include "tier0/vprof.h" -//#include "constants.h" -#include "vstdlib/vstdlib.h" -#include "strtools.h" -//#include "version.h" -//#include "globals.h" -//#include "ivalidate.h" -#include "tier1/utlvector.h" -#include "simplebitstring.h" -#include "tier1/checksum_sha1.h" -#include "tier0/memdbgon.h" -#include "tier0/tslist.h" -#include "tier0/memdbgoff.h" - - -#ifdef ENABLE_OPENSSLCONNECTION -#define USE_OPENSSL_AES_DECRYPT 1 -#endif - -#ifdef USE_OPENSSL_AES_DECRYPT -// openssl optimized AES routines -#include "openssl/aes.h" -#if defined(_M_IX86) || defined (_M_X64) || defined(__i386__) || defined(__x86_64__) -#include -#endif -#endif - -// crypto ++ -#include "tier0/valve_off.h" -#include "../external/crypto++-5.6.3/cryptopushdisablewarnings.h" -#if _MSC_VER < 1400 // doesn't work with vc8, things below need xdebug -#define _XDEBUG_ // keep crypto++-5.2 from including xdebug -// these are defined in xdebug and used in some subsequent headers, define them to be our version -#define _NEW_CRT new -#define _DELETE_CRT(_P) delete (_P) -#define _DELETE_CRT_VEC(_P) delete[] (_P) -#define _STRING_CRT string -#endif -#define CRYPTOPP_DLL -#undef min -#undef max -#undef Verify -#define VPROF_BUDGETGROUP_ENCRYPTION _T("Encryption") -#define SPEW_CRYPTO "crypto" -const int k_cMedBuff = 1024; // medium buffer - -#if defined(GNUC) -#pragma GCC diagnostic ignored "-Wshadow" -#endif - -#include "../external/crypto++-5.6.3/cryptlib.h" -#include "../external/crypto++-5.6.3/osrng.h" -#include "../external/crypto++-5.6.3/crc.h" -#include "../external/crypto++-5.6.3/modes.h" -#include "../external/crypto++-5.6.3/files.h" -#include "../external/crypto++-5.6.3/hex.h" -#include "../external/crypto++-5.6.3/base64.h" -#include "../external/crypto++-5.6.3/base32.h" -#include "../external/crypto++-5.6.3/words.h" -#include "../external/crypto++-5.6.3/rsa.h" -#include "../external/crypto++-5.6.3/aes.h" -#include "../external/crypto++-5.6.3/hmac.h" -#include "../external/crypto++-5.6.3/zlib.h" -#include "../external/crypto++-5.6.3/gzip.h" -#include "../external/crypto++-5.6.3/pwdbased.h" -using namespace CryptoPP; -typedef AutoSeededX917RNG CAutoSeededRNG; -#include "../external/crypto++-5.6.3/cryptopopdisablewarnings.h" - -#if defined(GNUC) -#pragma GCC diagnostic warning "-Wshadow" -#endif - -#include "tier0/memdbgon.h" -#include "tier0/valve_on.h" - -#include "crypto.h" -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#define min(a,b) (((a) < (b)) ? (a) : (b)) - - -// list of auto-seeded RNG pointers -// these are very expensive to construct, so it makes sense to cache them -CTSList g_tslistPAutoSeededRNG; - -// to avoid deconstructor order issuses we allow to manually free the list -void FreeListRNG() -{ - g_tslistPAutoSeededRNG.Purge(); -} - -//----------------------------------------------------------------------------- -// Purpose: thread-safe access to a pool of cryptoPP random number generators -//----------------------------------------------------------------------------- -class CPoolAllocatedRNG -{ -public: - CPoolAllocatedRNG() - { - m_pRNGNode = g_tslistPAutoSeededRNG.Pop(); - if ( !m_pRNGNode ) - { - m_pRNGNode = new CTSList::Node_t; - } - } - - ~CPoolAllocatedRNG() - { - g_tslistPAutoSeededRNG.Push( m_pRNGNode ); - } - - CAutoSeededRNG &GetRNG() - { - return m_pRNGNode->elem; - } - -private: - CTSList::Node_t *m_pRNGNode; -}; - -// force run this static construction code -class CGlobalInitConstructor -{ -public: - CGlobalInitConstructor() - { - // we have to use this function once since the underlying static constructor - // is not thread safe. See use of MicrosoftCryptoProvider in Crypto++ - CAutoSeededRNG rng; - rng.GenerateByte(); - } -}; - -volatile static CGlobalInitConstructor s_StaticCryptoConstructor; - -//----------------------------------------------------------------------------- -// Purpose: Encrypts the specified data with the specified key. Uses AES (Rijndael) symmetric -// encryption. The encrypted data may then be decrypted by calling SymmetricDecrypt -// with the same key. -// Input: pubPlaintextData - Data to be encrypted -// cubPlaintextData - Size of data to be encrypted -// pIV - Pointer to initialization vector -// cubIV - Size of initialization vector -// pubEncryptedData - Pointer to buffer to receive encrypted data -// pcubEncryptedData - Pointer to a variable that at time of call contains the size of -// the receive buffer for encrypted data. When the method returns, this will contain -// the actual size of the encrypted data. -// pubKey - the key to encrypt the data with -// cubKey - Size of the key (must be k_nSymmetricKeyLen) -// Output: true if successful, false if encryption failed -//----------------------------------------------------------------------------- -bool CCrypto::SymmetricEncryptWithIV( const uint8 *pubPlaintextData, const uint32 cubPlaintextData, - const uint8 *pIV, const uint32 cubIV, - uint8 *pubEncryptedData, uint32 *pcubEncryptedData, - const uint8 *pubKey, const uint32 cubKey ) -{ - VPROF_BUDGET( "CCrypto::SymmetricEncrypt", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pubPlaintextData ); - Assert( cubPlaintextData ); - Assert( pubEncryptedData ); - Assert( pcubEncryptedData ); - Assert( *pcubEncryptedData ); - Assert( pubKey ); - Assert( k_nSymmetricKeyLen == cubKey ); // the only key length supported is k_nSymmetricKeyLen - - bool bRet = false; - - uint32 cubEncryptedData = *pcubEncryptedData; // remember how big the caller's buffer is - bool bUseTempBuffer = false; - uint8 *pTemp = pubEncryptedData; - - - // - // Crypto++ does not play well with overlapping buffers. If the buffers are - // overlapping, then allocate some temp space to use for the encryption. - // - // It does work fine with _identical_ buffers. - // - if ( ( pubEncryptedData + cubEncryptedData >= pubPlaintextData ) && - ( pubPlaintextData + cubPlaintextData >= pubEncryptedData ) ) - { - pTemp = new uint8[cubEncryptedData]; - bUseTempBuffer = true; - } - - try // handle any exceptions crypto++ may throw - { - if ( pTemp != NULL ) - { - AESEncryption aesEncrypt( pubKey, cubKey ); - - byte rgubIVEncrypted[k_cMedBuff]; - Assert( Q_ARRAYSIZE( rgubIVEncrypted ) >= aesEncrypt.BlockSize() ); - Assert( pIV != NULL && cubIV >= aesEncrypt.BlockSize() ); - - ArraySink * pOutputSink = new ArraySink( pTemp, *pcubEncryptedData ); - - // encrypt the initial vector with the key - aesEncrypt.ProcessBlock( pIV, rgubIVEncrypted ); - - // store the encrypted IV in the output - the recipient will need it - pOutputSink->Put( rgubIVEncrypted, aesEncrypt.BlockSize() ); - - // encrypt the message, given the key & IV - CBC_Mode_ExternalCipher::Encryption cipher( aesEncrypt, pIV ); - // Note: StreamTransformationFilter now owns the pointer to pOutputSink and will - // free it when the filter goes out of scope and destructs - StreamTransformationFilter filter( cipher, pOutputSink ); - filter.Put( (byte *) pubPlaintextData, cubPlaintextData ); - filter.MessageEnd(); - // return length of encrypted data to caller - *pcubEncryptedData = pOutputSink->TotalPutLength(); - // CryptoPP may leave garbage hanging around in the caller's buffer past the stated output length. - // Just to be safe, zero out caller's buffer from end out output to end of max buffer - if ( bUseTempBuffer ) - { - Q_memcpy( pubEncryptedData, pTemp, *pcubEncryptedData ); - } - Q_memset( pubEncryptedData + *pcubEncryptedData, 0, (cubEncryptedData - *pcubEncryptedData ) ); - bRet = true; - } - } - catch ( Exception e ) - { - DMsg( SPEW_CRYPTO, 2, "CCrypto::SymmetricEncrypt: crypto++ threw exception %s (%d)\n", - e.what(), e.GetErrorType() ); - } - - if ( bUseTempBuffer ) - { - delete[] pTemp; - } - - return bRet; -} - -//----------------------------------------------------------------------------- -// Purpose: Encrypts the specified data with the specified key. Uses AES (Rijndael) symmetric -// encryption. The encrypted data may then be decrypted by calling SymmetricDecrypt -// with the same key. Generates a random initialization vector of the -// appropriate size. -// Input: pubPlaintextData - Data to be encrypted -// cubPlaintextData - Size of data to be encrypted -// pubEncryptedData - Pointer to buffer to receive encrypted data -// pcubEncryptedData - Pointer to a variable that at time of call contains the size of -// the receive buffer for encrypted data. When the method returns, this will contain -// the actual size of the encrypted data. -// pubKey - the key to encrypt the data with -// cubKey - Size of the key (must be k_nSymmetricKeyLen) -// Output: true if successful, false if encryption failed -//----------------------------------------------------------------------------- - -bool CCrypto::SymmetricEncrypt( const uint8 *pubPlaintextData, const uint32 cubPlaintextData, - uint8 *pubEncryptedData, uint32 *pcubEncryptedData, - const uint8 *pubKey, const uint32 cubKey ) -{ - bool bRet = false; - - // - // Generate a random IV - // - AESEncryption aesEncrypt( pubKey, cubKey ); - byte rgubIV[k_cMedBuff]; - CPoolAllocatedRNG rng; - rng.GetRNG().GenerateBlock( rgubIV, aesEncrypt.BlockSize() ); - - bRet = SymmetricEncryptWithIV( pubPlaintextData, cubPlaintextData, rgubIV, aesEncrypt.BlockSize(), pubEncryptedData, pcubEncryptedData, pubKey, cubKey ); - - return bRet; -} - - -#ifdef USE_OPENSSL_AES_DECRYPT - -// Local helper to perform AES+CBC decryption using optimized OpenSSL AES routines -static bool BDecryptAESUsingOpenSSL( const uint8 *pubEncryptedData, uint32 cubEncryptedData, uint8 *pubPlaintextData, uint32 *pcubPlaintextData, AES_KEY *key, const uint8 *pIV ) -{ - COMPILE_TIME_ASSERT( k_nSymmetricBlockSize == 16 ); - - // Block cipher encrypted text must be a multiple of the block size - if ( cubEncryptedData % k_nSymmetricBlockSize != 0 ) - return false; - - // Enough input? Requirement is one padded final block - if ( cubEncryptedData < k_nSymmetricBlockSize ) - return false; - - // Enough output space for all the full non-final blocks? - if ( *pcubPlaintextData < cubEncryptedData - k_nSymmetricBlockSize ) - return false; - - uint8 rgubWorking[k_nSymmetricBlockSize]; - uint32 nDecrypted = 0; - - // Process non-final blocks -#if defined(_M_IX86) || defined (_M_X64) || defined(__i386__) || defined(__x86_64__) - // ... believe it or not, Steam client on Windows supports Athlon XP without SSE2 - if ( !IsWindows() || GetCPUInformation().m_bSSE2 ) - { - while ( nDecrypted < cubEncryptedData - k_nSymmetricBlockSize ) - { - AES_decrypt( pubEncryptedData + nDecrypted, rgubWorking, key ); - __m128i m128Temp = _mm_xor_si128( _mm_loadu_si128( (__m128i*)pIV ), _mm_loadu_si128( (__m128i*)rgubWorking ) ); - pIV = pubEncryptedData + nDecrypted; - nDecrypted += k_nSymmetricBlockSize; - _mm_storeu_si128( (__m128i* RESTRICT)( pubPlaintextData + nDecrypted - k_nSymmetricBlockSize ), m128Temp ); - } - } - else -#endif - { - while ( nDecrypted < cubEncryptedData - k_nSymmetricBlockSize ) - { - AES_decrypt( pubEncryptedData + nDecrypted, rgubWorking, key ); - for ( int i = 0; i < k_nSymmetricBlockSize; ++i ) - pubPlaintextData[nDecrypted + i] = rgubWorking[i] ^ pIV[i]; - pIV = pubEncryptedData + nDecrypted; - nDecrypted += k_nSymmetricBlockSize; - } - } - - // Process final block into rgubWorking for padding inspection - Assert( nDecrypted == cubEncryptedData - k_nSymmetricBlockSize ); - AES_decrypt( pubEncryptedData + nDecrypted, rgubWorking, key ); - for ( int i = 0; i < k_nSymmetricBlockSize; ++i ) - rgubWorking[i] ^= pIV[i]; - - // Get final block padding length and make sure it is backfilled properly (PKCS#5) - uint8 pad = rgubWorking[ k_nSymmetricBlockSize - 1 ]; - if ( pad < 1 || pad > k_nSymmetricBlockSize ) - return false; - for ( int i = k_nSymmetricBlockSize - pad; i < k_nSymmetricBlockSize; ++i ) - if ( rgubWorking[i] != pad ) - return false; - - // Check that we have enough space for final bytes - if ( *pcubPlaintextData < nDecrypted + k_nSymmetricBlockSize - pad ) - return false; - - // Write any non-pad bytes from rgubWorking to pubPlaintextData - for ( int i = 0; i < k_nSymmetricBlockSize - pad; ++i ) - pubPlaintextData[nDecrypted++] = rgubWorking[i]; - - // The old CryptoPP path zeros out the entire destination buffer, but that - // behavior isn't documented or even expected. We'll just zero out one byte - // in case anyone relies on string termination, but that zero isn't counted. - if ( *pcubPlaintextData > nDecrypted ) - pubPlaintextData[nDecrypted] = 0; - - *pcubPlaintextData = nDecrypted; - return true; -} - -#else - -/* function, not method */ -static bool SymmetricDecryptWorker( const uint8 *pubEncryptedData, uint32 cubEncryptedData, - const uint8 * pIV, uint32 cubIV, - uint8 *pubPlaintextData, uint32 *pcubPlaintextData, - AESDecryption &aesDecrypt ) -{ - VPROF_BUDGET( "CCrypto::SymmetricDecrypt", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pubEncryptedData ); - Assert( cubEncryptedData); - Assert( pIV ); - Assert( cubIV ); - Assert( pubPlaintextData ); - Assert( pcubPlaintextData ); - Assert( *pcubPlaintextData ); - - bool bRet = false; - - uint32 cubPlaintextData = *pcubPlaintextData; // remember how big the caller's buffer is - bool bUseTempBuffer = false; - uint8* pTemp = pubPlaintextData; - - // - // Crypto++ does not play nice with decrypting in place. If the buffers are - // overlapping, then allocate some temp space to use for the decryption. - // - // It does work fine with _identical_ buffers, but due to the way we store - // the IV in the returned encrypted data we never actually hit that case. - // - if ( ( pubEncryptedData + cubEncryptedData >= pubPlaintextData ) && - ( pubPlaintextData + cubPlaintextData >= pubEncryptedData ) ) - { - pTemp = new uint8[cubPlaintextData]; - bUseTempBuffer = true; - } - - try // handle any exceptions crypto++ may throw - { - if ( pTemp != NULL ) - { - CryptoPP::ArraySink* pOutputSink = new CryptoPP::ArraySink( pTemp, *pcubPlaintextData ); - CryptoPP::CBC_Mode_ExternalCipher::Decryption cbc( aesDecrypt, pIV ); - // Note: StreamTransformationFilter now owns the pointer to pOutputSink and will - // free it when the filter goes out of scope and destructs - CryptoPP::StreamTransformationFilter padding( cbc, pOutputSink ); - padding.Put( pubEncryptedData, cubEncryptedData ); - padding.MessageEnd(); - // return length of decrypted data to caller - *pcubPlaintextData = pOutputSink->TotalPutLength(); - // CryptoPP may leave garbage hanging around in the caller's buffer past the stated output length. - // Just to be safe, zero out caller's buffer from end out output to end of max buffer - if ( bUseTempBuffer ) - { - Q_memcpy( pubPlaintextData, pTemp, *pcubPlaintextData ); - } - Q_memset( pubPlaintextData + *pcubPlaintextData, 0, (cubPlaintextData - *pcubPlaintextData ) ); - - bRet = true; - } - } - catch ( Exception e ) - { - DMsg( SPEW_CRYPTO, 4, "CCrypto::SymmetricDecrypt: crypto++ threw exception %s (%d)\n", - e.what(), e.GetErrorType() ); - } - - if ( bUseTempBuffer ) - { - delete[] pTemp; - } - - return bRet; -} - -#endif - - -//----------------------------------------------------------------------------- -// Purpose: Decrypts the specified data with the specified key. Uses AES (Rijndael) symmetric -// decryption. -// Input: pubEncryptedData - Data to be decrypted -// cubEncryptedData - Size of data to be decrypted -// pubPlaintextData - Pointer to buffer to receive decrypted data -// pcubPlaintextData - Pointer to a variable that at time of call contains the size of -// the receive buffer for decrypted data. When the method returns, this will contain -// the actual size of the decrypted data. -// pubKey - the key to decrypt the data with -// cubKey - Size of the key (must be k_nSymmetricKeyLen) -// Output: true if successful, false if decryption failed -//----------------------------------------------------------------------------- -bool CCrypto::SymmetricDecrypt( const uint8 *pubEncryptedData, uint32 cubEncryptedData, - uint8 *pubPlaintextData, uint32 *pcubPlaintextData, - const uint8 *pubKey, const uint32 cubKey ) -{ - Assert( pubEncryptedData ); - Assert( cubEncryptedData); - Assert( pubPlaintextData ); - Assert( pcubPlaintextData ); - Assert( *pcubPlaintextData ); - Assert( pubKey ); - Assert( k_nSymmetricKeyLen == cubKey ); // the only key length supported is k_nSymmetricKeyLen - - // the initialization vector (IV) must be stored in the first block of bytes. - // If the size of encrypted data is not at least the block size, it is not valid - if ( cubEncryptedData < k_nSymmetricBlockSize ) - return false; - -#ifdef USE_OPENSSL_AES_DECRYPT - - AES_KEY key; - if ( AES_set_decrypt_key( pubKey, cubKey * 8, &key ) < 0 ) - return false; - - // Our first block is straight AES block encryption of IV with user key, no XOR. - uint8 rgubIV[ k_nSymmetricBlockSize ]; - AES_decrypt( pubEncryptedData, rgubIV, &key ); - pubEncryptedData += k_nSymmetricBlockSize; - cubEncryptedData -= k_nSymmetricBlockSize; - - return BDecryptAESUsingOpenSSL( pubEncryptedData, cubEncryptedData, pubPlaintextData, pcubPlaintextData, &key, rgubIV ); - -#else - - AESDecryption aesDecrypt( pubKey, cubKey ); - Assert( k_nSymmetricBlockSize == aesDecrypt.BlockSize() ); - - // Decrypt the IV - byte rgubIV[k_cMedBuff]; - Assert( Q_ARRAYSIZE( rgubIV ) >= aesDecrypt.BlockSize() ); - aesDecrypt.ProcessBlock( pubEncryptedData, rgubIV ); - - // We have now consumed the IV, so remove it from the front of the message - pubEncryptedData += k_nSymmetricBlockSize; - cubEncryptedData -= k_nSymmetricBlockSize; - - // given the IV stored in the message, and the key, decrypt the message - return SymmetricDecryptWorker( pubEncryptedData, cubEncryptedData, - rgubIV, aesDecrypt.BlockSize(), - pubPlaintextData, pcubPlaintextData, - aesDecrypt ); - -#endif -} - -//----------------------------------------------------------------------------- -// Purpose: Decrypts the specified data with the specified key. Uses AES (Rijndael) symmetric -// decryption. -// Input: pubEncryptedData - Data to be decrypted -// cubEncryptedData - Size of data to be decrypted -// pIV - Initialization vector. Byte array one block in size. -// cubIV - size of IV. This should be 16 (one block, 128 bits) -// pubPlaintextData - Pointer to buffer to receive decrypted data -// pcubPlaintextData - Pointer to a variable that at time of call contains the size of -// the receive buffer for decrypted data. When the method returns, this will contain -// the actual size of the decrypted data. -// pubKey - the key to decrypt the data with -// cubKey - Size of the key (must be k_nSymmetricKeyLen) -// Output: true if successful, false if decryption failed -//----------------------------------------------------------------------------- -bool CCrypto::SymmetricDecryptWithIV( const uint8 *pubEncryptedData, uint32 cubEncryptedData, - const uint8 * pIV, uint32 cubIV, - uint8 *pubPlaintextData, uint32 *pcubPlaintextData, - const uint8 *pubKey, const uint32 cubKey ) -{ - Assert( pubEncryptedData ); - Assert( cubEncryptedData); - Assert( pIV ); - Assert( cubIV ); - Assert( pubPlaintextData ); - Assert( pcubPlaintextData ); - Assert( *pcubPlaintextData ); - Assert( pubKey ); - Assert( k_nSymmetricKeyLen == cubKey ); // the only key length supported is k_nSymmetricKeyLen - - // IV input into CBC must be exactly one block size - if ( cubIV != k_nSymmetricBlockSize ) - return false; - -#ifdef USE_OPENSSL_AES_DECRYPT - - AES_KEY key; - if ( AES_set_decrypt_key( pubKey, cubKey * 8, &key ) < 0 ) - return false; - - return BDecryptAESUsingOpenSSL( pubEncryptedData, cubEncryptedData, pubPlaintextData, pcubPlaintextData, &key, pIV ); - -#else - - AESDecryption aesDecrypt( pubKey, cubKey ); - Assert( k_nSymmetricBlockSize == aesDecrypt.BlockSize() ); - - return SymmetricDecryptWorker( pubEncryptedData, cubEncryptedData, - pIV, cubIV, - pubPlaintextData, pcubPlaintextData, - aesDecrypt ); - -#endif -} - - -//----------------------------------------------------------------------------- -// Purpose: For specified plaintext data size, returns what size of symmetric -// encrypted data will be -//----------------------------------------------------------------------------- -uint32 CCrypto::GetSymmetricEncryptedSize( uint32 cubPlaintextData ) -{ - // empirically determined encrypted size as function of plaintext size for AES encryption - uint k_cubBlock = 16; - uint k_cubHeader = 16; - return k_cubHeader + ( ( cubPlaintextData / k_cubBlock ) * k_cubBlock ) + k_cubBlock; -} - - -//----------------------------------------------------------------------------- -// Purpose: Encrypts the specified data with the specified text password. -// Uses the SHA256 hash of the password as the key for AES (Rijndael) symmetric -// encryption. A SHA1 HMAC of the result is appended, for authentication on -// the receiving end. -// The encrypted data may then be decrypted by calling DecryptWithPasswordAndAuthenticate -// with the same password. -// Input: pubPlaintextData - Data to be encrypted -// cubPlaintextData - Size of data to be encrypted -// pubEncryptedData - Pointer to buffer to receive encrypted data -// pcubEncryptedData - Pointer to a variable that at time of call contains the size of -// the receive buffer for encrypted data. When the method returns, this will contain -// the actual size of the encrypted data. -// pchPassword - text password -// Output: true if successful, false if encryption failed -//----------------------------------------------------------------------------- -bool CCrypto::EncryptWithPasswordAndHMAC( const uint8 *pubPlaintextData, uint32 cubPlaintextData, - uint8 * pubEncryptedData, uint32 * pcubEncryptedData, - const char *pchPassword ) -{ - // - // Generate a random IV - // - byte rgubIV[k_nSymmetricBlockSize]; - CPoolAllocatedRNG rng; - rng.GetRNG().GenerateBlock( rgubIV, k_nSymmetricBlockSize ); - - return EncryptWithPasswordAndHMACWithIV( pubPlaintextData, cubPlaintextData, rgubIV, k_nSymmetricBlockSize, pubEncryptedData, pcubEncryptedData, pchPassword ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Encrypts the specified data with the specified text password. -// Uses the SHA256 hash of the password as the key for AES (Rijndael) symmetric -// encryption. A SHA1 HMAC of the result is appended, for authentication on -// the receiving end. -// The encrypted data may then be decrypted by calling DecryptWithPasswordAndAuthenticate -// with the same password. -// Input: pubPlaintextData - Data to be encrypted -// cubPlaintextData - Size of data to be encrypted -// pIV - IV to use for AES encryption. Should be random and never used before unless you know -// exactly what you're doing. -// cubIV - size of the IV - should be same ase the AES blocksize. -// pubEncryptedData - Pointer to buffer to receive encrypted data -// pcubEncryptedData - Pointer to a variable that at time of call contains the size of -// the receive buffer for encrypted data. When the method returns, this will contain -// the actual size of the encrypted data. -// pchPassword - text password -// Output: true if successful, false if encryption failed -//----------------------------------------------------------------------------- -bool CCrypto::EncryptWithPasswordAndHMACWithIV( const uint8 *pubPlaintextData, uint32 cubPlaintextData, - const uint8 * pIV, uint32 cubIV, - uint8 * pubEncryptedData, uint32 * pcubEncryptedData, - const char *pchPassword ) -{ - uint8 rgubKey[k_nSymmetricKeyLen]; - if ( !pchPassword || !pchPassword[0] ) - return false; - - if ( !cubPlaintextData ) - return false; - - uint32 cubBuffer = *pcubEncryptedData; - uint32 cubExpectedResult = GetSymmetricEncryptedSize( cubPlaintextData ) + sizeof( SHADigest_t ); - - if ( cubBuffer < cubExpectedResult ) - return false; - - try - { - CryptoPP::SHA256().CalculateDigest( rgubKey, (const uint8 *)pchPassword, Q_strlen( pchPassword ) ); - } - catch ( Exception e ) - { - DMsg( SPEW_CRYPTO, 4, "CCrypto::EncryptWithPassword: crypto++ threw exception %s (%d)\n", - e.what(), e.GetErrorType() ); - return false; - } - - bool bRet = SymmetricEncryptWithIV( pubPlaintextData, cubPlaintextData, pIV, cubIV, pubEncryptedData, pcubEncryptedData, rgubKey, k_nSymmetricKeyLen ); - if ( bRet ) - { - // calc HMAC - uint32 cubEncrypted = *pcubEncryptedData; - *pcubEncryptedData += sizeof( SHADigest_t ); - if ( cubBuffer < *pcubEncryptedData ) - return false; - - SHADigest_t *pHMAC = (SHADigest_t*)( pubEncryptedData + cubEncrypted ); - bRet = CCrypto::GenerateHMAC( pubEncryptedData, cubEncrypted, rgubKey, k_nSymmetricKeyLen, pHMAC ); - } - - return bRet; -} - - -//----------------------------------------------------------------------------- -// Purpose: Decrypts the specified data with the specified password. Uses AES (Rijndael) symmetric -// decryption. First, the HMAC is verified - if it is not correct, then we know that -// the key is incorrect or the data is corrupted, and the decryption fails. -// Input: pubEncryptedData - Data to be decrypted -// cubEncryptedData - Size of data to be decrypted -// pubPlaintextData - Pointer to buffer to receive decrypted data -// pcubPlaintextData - Pointer to a variable that at time of call contains the size of -// the receive buffer for decrypted data. When the method returns, this will contain -// the actual size of the decrypted data. -// pchPassword - the text password to decrypt the data with -// Output: true if successful, false if decryption failed -//----------------------------------------------------------------------------- -bool CCrypto::DecryptWithPasswordAndAuthenticate( const uint8 * pubEncryptedData, uint32 cubEncryptedData, - uint8 * pubPlaintextData, uint32 * pcubPlaintextData, - const char *pchPassword ) -{ - uint8 rgubKey[k_nSymmetricKeyLen]; - if ( !pchPassword || !pchPassword[0] ) - return false; - - if ( cubEncryptedData <= sizeof( SHADigest_t ) ) - return false; - - try - { - CryptoPP::SHA256().CalculateDigest( rgubKey, (const uint8 *)pchPassword, Q_strlen( pchPassword ) ); - } - catch ( Exception e ) - { - DMsg( SPEW_CRYPTO, 4, "CCrypto::EncryptWithPassword: crypto++ threw exception %s (%d)\n", - e.what(), e.GetErrorType() ); - return false; - } - - uint32 cubCiphertext = cubEncryptedData - sizeof( SHADigest_t ); - SHADigest_t *pHMAC = (SHADigest_t*)( pubEncryptedData + cubCiphertext ); - SHADigest_t hmacActual; - bool bRet = CCrypto::GenerateHMAC( pubEncryptedData, cubCiphertext, rgubKey, k_nSymmetricKeyLen, &hmacActual ); - - if ( bRet ) - { - // invalid ciphertext or key - if ( Q_memcmp( &hmacActual, pHMAC, sizeof( SHADigest_t ) ) ) - return false; - - bRet = SymmetricDecrypt( pubEncryptedData, cubCiphertext, pubPlaintextData, pcubPlaintextData, rgubKey, k_nSymmetricKeyLen ); - } - - return bRet; -} - - -//----------------------------------------------------------------------------- -// Purpose: Generates a new pair of private/public RSA keys -// Input: pubPublicKey - Pointer to buffer to receive public key (should be of size k_nRSAKeyLenMax) -// pcubPublicKey - Pointer to variable that contains size of pubPublicKey buffer. At exit, -// this is filled in with the actual size of the public key -// pubPrivateKey - Pointer to buffer to receive private key (should be of size k_nRSAKeyLenMax) -// pcubPrivateKey - Pointer to variable that contains size of pubPrivateKey buffer. At exit, -// this is filled in with the actual size of the private key -// Output: true if successful, false if key generation failed -//----------------------------------------------------------------------------- -bool CCrypto::RSAGenerateKeys( uint8 *pubPublicKey, uint32 *pcubPublicKey, uint8 *pubPrivateKey, uint32 *pcubPrivateKey ) -{ - VPROF_BUDGET( "CCrypto::RSAGenerateKeys", VPROF_BUDGETGROUP_ENCRYPTION ); - bool bRet = false; - Assert( pubPublicKey ); - Assert( pcubPublicKey ); - Assert( pubPrivateKey ); - Assert( pcubPrivateKey ); - - try // handle any exceptions crypto++ may throw - { - // generate private key - ArraySink arraySinkPrivateKey( pubPrivateKey, *pcubPrivateKey ); - CPoolAllocatedRNG rng; - RSAES_OAEP_SHA_Decryptor priv( rng.GetRNG(), k_nRSAKeyBits ); - priv.DEREncode( arraySinkPrivateKey ); - *pcubPrivateKey = arraySinkPrivateKey.TotalPutLength(); - // generate public key - ArraySink arraySinkPublicKey( pubPublicKey, *pcubPublicKey ); - RSAES_OAEP_SHA_Encryptor pub(priv); - pub.DEREncode( arraySinkPublicKey ); - *pcubPublicKey = arraySinkPublicKey.TotalPutLength(); - bRet = true; - } - catch ( Exception e ) - { - DMsg( SPEW_CRYPTO, 2, "CCrypto::RSAGenerateKeys: crypto++ threw exception %s (%d)\n", - e.what(), e.GetErrorType() ); - } - - return bRet; -} - - -//----------------------------------------------------------------------------- -// Purpose: Encrypts the specified data with the specified RSA public key. -// The encrypted data may then be decrypted by calling RSADecrypt with the -// corresponding RSA private key. -// Input: pubPlaintextData - Data to be encrypted -// cubPlaintextData - Size of data to be encrypted -// pubEncryptedData - Pointer to buffer to receive encrypted data -// pcubEncryptedData - Pointer to a variable that at time of call contains the size of -// the receive buffer for encrypted data. When the method returns, this will contain -// the actual size of the encrypted data. -// pubPublicKey - the RSA public key to encrypt the data with -// cubPublicKey - Size of the key (must be k_nSymmetricKeyLen) -// Output: true if successful, false if encryption failed -//----------------------------------------------------------------------------- -bool CCrypto::RSAEncrypt( const uint8 *pubPlaintextData, uint32 cubPlaintextData, - uint8 *pubEncryptedData, uint32 *pcubEncryptedData, - const uint8 *pubPublicKey, const uint32 cubPublicKey ) -{ - VPROF_BUDGET( "CCrypto::RSAEncrypt", VPROF_BUDGETGROUP_ENCRYPTION ); - bool bRet = false; - Assert( cubPlaintextData > 0 ); // must pass in some data - - try // handle any exceptions crypto++ may throw - { - StringSource stringSourcePublicKey( pubPublicKey, cubPublicKey, true ); - RSAES_OAEP_SHA_Encryptor rsaEncryptor( stringSourcePublicKey ); - - // calculate how many blocks of encryption will we need to do - AssertFatal( rsaEncryptor.FixedMaxPlaintextLength() <= ULONG_MAX ); - uint32 cBlocks = 1 + ( ( cubPlaintextData - 1 ) / (uint32)rsaEncryptor.FixedMaxPlaintextLength() ); - // calculate how big the output will be - AssertFatal( rsaEncryptor.FixedCiphertextLength() <= ULONG_MAX / cBlocks ); - uint32 cubCipherText = cBlocks * (uint32)rsaEncryptor.FixedCiphertextLength(); - Assert( cubCipherText > 0 ); - - // ensure there is sufficient room in output buffer for result - if ( cubCipherText > ( *pcubEncryptedData ) ) - { - AssertMsg2( false, "CCrypto::RSAEncrypt: insufficient output buffer for encryption, needed %d got %d\n", - cubCipherText, *pcubEncryptedData ); - return false; - } - - // encrypt the message, using as many blocks as required - CPoolAllocatedRNG rng; - for ( uint32 nBlock = 0; nBlock < cBlocks; nBlock++ ) - { - // encrypt either all remaining plaintext, or maximum allowed plaintext per RSA encryption operation - uint32 cubToEncrypt = min( cubPlaintextData, (uint32)rsaEncryptor.FixedMaxPlaintextLength() ); - // encrypt the plaintext - rsaEncryptor.Encrypt( rng.GetRNG(), pubPlaintextData, cubToEncrypt, pubEncryptedData ); - // adjust input and output pointers and remaining plaintext byte count - pubPlaintextData += cubToEncrypt; - cubPlaintextData -= cubToEncrypt; - pubEncryptedData += rsaEncryptor.FixedCiphertextLength(); - } - Assert( 0 == cubPlaintextData ); // should have no remaining plaintext to encrypt - *pcubEncryptedData = cubCipherText; - - bRet = true; - } - catch ( Exception e ) - { - DMsg( SPEW_CRYPTO, 2, "CCrypto::RSAEncrypt: Encrypt() threw exception %s (%d)\n", - e.what(), e.GetErrorType() ); - } - - return bRet; -} - - -//----------------------------------------------------------------------------- -// Purpose: Decrypts the specified data with the specified RSA private key -// Input: pubEncryptedData - Data to be decrypted -// cubEncryptedData - Size of data to be decrypted -// pubPlaintextData - Pointer to buffer to receive decrypted data -// pcubPlaintextData - Pointer to a variable that at time of call contains the size of -// the receive buffer for decrypted data. When the method returns, this will contain -// the actual size of the decrypted data. -// pubPrivateKey - the RSA private key key to decrypt the data with -// cubPrivateKey - Size of the key (must be k_nSymmetricKeyLen) -// Output: true if successful, false if decryption failed -//----------------------------------------------------------------------------- -bool CCrypto::RSADecrypt( const uint8 *pubEncryptedData, uint32 cubEncryptedData, - uint8 *pubPlaintextData, uint32 *pcubPlaintextData, - const uint8 *pubPrivateKey, const uint32 cubPrivateKey ) -{ - VPROF_BUDGET( "CCrypto::RSADecrypt", VPROF_BUDGETGROUP_ENCRYPTION ); - bool bRet = false; - - Assert( cubEncryptedData > 0 ); // must pass in some data - - try // handle any exceptions crypto++ may throw - { - StringSource stringSourcePrivateKey( pubPrivateKey, cubPrivateKey, true ); - RSAES_OAEP_SHA_Decryptor rsaDecryptor( stringSourcePrivateKey ); - - // calculate how many blocks of decryption will we need to do - AssertFatal( rsaDecryptor.FixedCiphertextLength() <= ULONG_MAX ); - uint32 cubFixedCiphertextLength = (uint32)rsaDecryptor.FixedCiphertextLength(); - // Ensure encrypted data is valid and has length that is exact multiple of 128 bytes - if ( 0 != ( cubEncryptedData % cubFixedCiphertextLength ) ) - { - DMsg( SPEW_CRYPTO, 2, "CCrypto::RSADecrypt: invalid ciphertext length %d, needs to be a multiple of %d\n", - cubEncryptedData, cubFixedCiphertextLength ); - return false; - } - uint32 cBlocks = cubEncryptedData / cubFixedCiphertextLength; - - // calculate how big the maximum output will be - size_t cubMaxPlaintext = rsaDecryptor.MaxPlaintextLength( rsaDecryptor.FixedCiphertextLength() ); - AssertFatal( cubMaxPlaintext <= ULONG_MAX / cBlocks ); - uint32 cubPlaintextDataMax = cBlocks * (uint32)cubMaxPlaintext; - Assert( cubPlaintextDataMax > 0 ); - // ensure there is sufficient room in output buffer for result - if ( cubPlaintextDataMax >= ( *pcubPlaintextData ) ) - { - AssertMsg2( false, "CCrypto::RSADecrypt: insufficient output buffer for decryption, needed %d got %d\n", - cubPlaintextDataMax, *pcubPlaintextData ); - return false; - } - - // decrypt the data, using as many blocks as required - CPoolAllocatedRNG rng; - uint32 cubPlaintextData = 0; - for ( uint32 nBlock = 0; nBlock < cBlocks; nBlock++ ) - { - // decrypt one block (always of fixed size) - int cubToDecrypt = cubFixedCiphertextLength; - DecodingResult decodingResult = rsaDecryptor.Decrypt( rng.GetRNG(), pubEncryptedData, cubToDecrypt, pubPlaintextData ); - if ( !decodingResult.isValidCoding ) - { - DMsg( SPEW_CRYPTO, 2, "CCrypto::RSADecrypt: failed to decrypt\n" ); - return false; - } - // adjust input and output pointers and remaining encrypted byte count - pubEncryptedData += cubToDecrypt; - cubEncryptedData -= cubToDecrypt; - pubPlaintextData += decodingResult.messageLength; - AssertFatal( decodingResult.messageLength <= ULONG_MAX ); - cubPlaintextData += (uint32)decodingResult.messageLength; - } - Assert( 0 == cubEncryptedData ); // should have no remaining encrypted data to decrypt - *pcubPlaintextData = cubPlaintextData; - - bRet = true; - } - catch ( Exception e ) - { - DMsg( SPEW_CRYPTO, 2, "CCrypto::RSADecrypt: Decrypt() threw exception %s (%d)\n", - e.what(), e.GetErrorType() ); - } - - return bRet; -} - - -//----------------------------------------------------------------------------- -// Purpose: Decrypts the specified data with the specified RSA PUBLIC key, -// using no padding (eg un-padded signature). -// Input: pubEncryptedData - Data to be decrypted -// cubEncryptedData - Size of data to be decrypted -// pubPlaintextData - Pointer to buffer to receive decrypted data -// pcubPlaintextData - Pointer to a variable that at time of call contains the size of -// the receive buffer for decrypted data. When the method returns, this will contain -// the actual size of the decrypted data. -// pubPublicKey - the RSA public key key to decrypt the data with -// cubPublicKey - Size of the key -// Output: true if successful, false if decryption failed -//----------------------------------------------------------------------------- -bool CCrypto::RSAPublicDecrypt_NoPadding( const uint8 *pubEncryptedData, uint32 cubEncryptedData, - uint8 *pubPlaintextData, uint32 *pcubPlaintextData, - const uint8 *pubPublicKey, const uint32 cubPublicKey ) -{ - VPROF_BUDGET( "CCrypto::RSADecrypt", VPROF_BUDGETGROUP_ENCRYPTION ); - bool bRet = false; - - Assert( cubEncryptedData > 0 ); // must pass in some data - - // BUGBUG taylor - // This probably only works for reasonably small ciphertext sizes. - - try // handle any exceptions crypto++-5.2 may throw - { - StringSource stringSourcePublicKey( pubPublicKey, cubPublicKey, true ); - - // 1. We need to use a Verifier because a Decryptor expects a private key, - // which is encoded differently - // 2. We are using neither PKCS1v15 padding nor SHA in any way, we are simply - // using this object as a means of instantiating the key decryption function - RSASSA_PKCS1v15_SHA_Verifier pub( stringSourcePublicKey ); - - // Ask for the data to be decrypted - // Caveat: this may "succeed" even if the ciphertext is bogus, so it - // is up to the caller to do any MAC or other sanity checking - Integer x = pub.AccessKey().ApplyFunction(Integer(pubEncryptedData, cubEncryptedData)); - - // Result is an 'Integer', essentially a string of bytes for our - // purposes though. - uint32 nBytes = x.ByteCount(); - if ( nBytes > *pcubPlaintextData ) - { - return false; - } - - // don't tell it to encode to the full buffer size, because it will - // pre-pad with zeros. Just squeeze it in to the first nBytes of the - // buffer. - x.Encode( pubPlaintextData, nBytes ); - *pcubPlaintextData = nBytes; - - bRet = true; - } - catch ( Exception e ) - { - DMsg( SPEW_CRYPTO, 2, "CCrypto::RSAPublicDecrypt_NoPadding: Decrypt() threw exception %s (%d)\n", - e.what(), e.GetErrorType() ); - } - - return bRet; -} - - -//----------------------------------------------------------------------------- -// Purpose: Generates an RSA signature block for the specified data with the specified -// RSA private key. The signature can be verified by calling RSAVerifySignature -// with the RSA public key. -// Input: pubData - Data to be signed -// cubData - Size of data to be signed -// pubSignature - Pointer to buffer to receive signature block -// pcubSignature - Pointer to a variable that at time of call contains the size of -// the pubSignature buffer. When the method returns, this will contain -// the actual size of the signature block -// pubPrivateKey - The RSA private key to use to sign the data -// cubPrivateKey - Size of the key -// Output: true if successful, false if signature failed -//----------------------------------------------------------------------------- -bool CCrypto::RSASign( const uint8 *pubData, const uint32 cubData, - uint8 *pubSignature, uint32 *pcubSignature, - const uint8 *pubPrivateKey, const uint32 cubPrivateKey ) -{ - VPROF_BUDGET( "CCrypto::RSASign", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pubData ); - Assert( pubPrivateKey ); - Assert( cubPrivateKey > 0 ); - Assert( pubSignature ); - Assert( pcubSignature ); - bool bRet = false; - try // handle any exceptions crypto++ may throw - { - StringSource stringSourcePrivateKey( pubPrivateKey, cubPrivateKey, true ); - RSASSA_PKCS1v15_SHA_Signer rsaSigner( stringSourcePrivateKey ); - CPoolAllocatedRNG rng; - size_t len = rsaSigner.SignMessage( rng.GetRNG(), (byte *)pubData, cubData, pubSignature ); - AssertFatal( len <= ULONG_MAX ); - *pcubSignature = (uint32)len; - bRet = true; - } - catch ( Exception e ) - { - DMsg( SPEW_CRYPTO, 2, "CCrypto::RSASign: SignMessage threw exception %s (%d)\n", - e.what(), e.GetErrorType() ); - } - - return bRet; -} - - -//----------------------------------------------------------------------------- -// Purpose: Verifies that signature block is authentic for given data & RSA public key -// Input: pubData - Data that was signed -// cubData - Size of data that was signed signed -// pubSignature - Signature block -// cubSignature - Size of signature block -// pubPublicKey - The RSA public key to use to verify the signature -// (must be from same pair as RSA private key used to generate signature) -// cubPublicKey - Size of the key -// Output: true if successful and signature is authentic, false if signature does not match or other error -//----------------------------------------------------------------------------- -bool CCrypto::RSAVerifySignature( const uint8 *pubData, const uint32 cubData, - const uint8 *pubSignature, const uint32 cubSignature, - const uint8 *pubPublicKey, const uint32 cubPublicKey ) -{ - VPROF_BUDGET( "CCrypto::RSAVerifySignature", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pubData ); - Assert( pubSignature ); - Assert( pubPublicKey ); - - bool bRet = false; - try // handle any exceptions crypto++ may throw - { - StringSource stringSourcePublicKey( pubPublicKey, cubPublicKey, true ); - RSASSA_PKCS1v15_SHA_Verifier pub( stringSourcePublicKey ); - bRet = pub.VerifyMessage( pubData, cubData, pubSignature, cubSignature ); - } - catch ( Exception e ) - { - DMsg( SPEW_CRYPTO, 2, "CCrypto::RSASign: VerifyMessage threw exception %s (%d)\n", - e.what(), e.GetErrorType() ); - } - - return bRet; -} - -//----------------------------------------------------------------------------- -// Purpose: Generates an RSA signature block for the specified data with the specified -// RSA private key. The signature can be verified by calling RSAVerifySignature -// with the RSA public key. -// Input: pubData - Data to be signed -// cubData - Size of data to be signed -// pubSignature - Pointer to buffer to receive signature block -// pcubSignature - Pointer to a variable that at time of call contains the size of -// the pubSignature buffer. When the method returns, this will contain -// the actual size of the signature block -// pubPrivateKey - The RSA private key to use to sign the data -// cubPrivateKey - Size of the key -// Output: true if successful, false if signature failed -//----------------------------------------------------------------------------- -bool CCrypto::RSASignSHA256( const uint8 *pubData, const uint32 cubData, - uint8 *pubSignature, uint32 *pcubSignature, - const uint8 *pubPrivateKey, const uint32 cubPrivateKey ) -{ - VPROF_BUDGET( "CCrypto::RSASign", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pubData ); - Assert( pubPrivateKey ); - Assert( cubPrivateKey > 0 ); - Assert( pubSignature ); - Assert( pcubSignature ); - bool bRet = false; - try // handle any exceptions crypto++ may throw - { - StringSource stringSourcePrivateKey( pubPrivateKey, cubPrivateKey, true ); - RSASS::Signer rsaSigner( stringSourcePrivateKey ); - CPoolAllocatedRNG rng; - size_t len = rsaSigner.SignMessage( rng.GetRNG(), (byte *)pubData, cubData, pubSignature ); - AssertFatal( len <= ULONG_MAX ); - *pcubSignature = (uint32)len; - bRet = true; - } - catch ( Exception e ) - { - DMsg( SPEW_CRYPTO, 2, "CCrypto::RSASign: SignMessage threw exception %s (%d)\n", - e.what(), e.GetErrorType() ); - } - - return bRet; -} - - -//----------------------------------------------------------------------------- -// Purpose: Verifies that signature block is authentic for given data & RSA public key -// Input: pubData - Data that was signed -// cubData - Size of data that was signed signed -// pubSignature - Signature block -// cubSignature - Size of signature block -// pubPublicKey - The RSA public key to use to verify the signature -// (must be from same pair as RSA private key used to generate signature) -// cubPublicKey - Size of the key -// Output: true if successful and signature is authentic, false if signature does not match or other error -//----------------------------------------------------------------------------- -bool CCrypto::RSAVerifySignatureSHA256( const uint8 *pubData, const uint32 cubData, - const uint8 *pubSignature, const uint32 cubSignature, - const uint8 *pubPublicKey, const uint32 cubPublicKey ) -{ - VPROF_BUDGET( "CCrypto::RSAVerifySignature", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pubData ); - Assert( pubSignature ); - Assert( pubPublicKey ); - - bool bRet = false; - try // handle any exceptions crypto++ may throw - { - StringSource stringSourcePublicKey( pubPublicKey, cubPublicKey, true ); - RSASS::Verifier pub( stringSourcePublicKey ); - bRet = pub.VerifyMessage( pubData, cubData, pubSignature, cubSignature ); - } - catch ( Exception e ) - { - DMsg( SPEW_CRYPTO, 2, "CCrypto::RSASign: VerifyMessage threw exception %s (%d)\n", - e.what(), e.GetErrorType() ); - } - - return bRet; -} - - -//----------------------------------------------------------------------------- -// Purpose: Hex-encodes a block of data. (Binary -> text representation.) The output -// is null-terminated and can be treated as a string. -// Input: pubData - Data to encode -// cubData - Size of data to encode -// pchEncodedData - Pointer to string buffer to store output in -// cchEncodedData - Size of pchEncodedData buffer -//----------------------------------------------------------------------------- -bool CCrypto::HexEncode( const uint8 *pubData, const uint32 cubData, char *pchEncodedData, uint32 cchEncodedData ) -{ - VPROF_BUDGET( "CCrypto::HexEncode", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pubData ); - Assert( cubData ); - Assert( pchEncodedData ); - Assert( cchEncodedData > 0 ); - - if ( cchEncodedData < ( ( cubData * 2 ) + 1 ) ) - { - Assert( cchEncodedData >= ( cubData * 2 ) + 1 ); // expands to 2x input + NULL, must have room in output buffer - *pchEncodedData = '\0'; - return false; - } - - ArraySink * pArraySinkOutput = new ArraySink( (byte *) pchEncodedData, cchEncodedData ); - // Note: HexEncoder now owns the pointer to pOutputSink and will free it when the encoder goes out of scope and destructs - HexEncoder hexEncoder( pArraySinkOutput ); - hexEncoder.Put( pubData, cubData ); - hexEncoder.MessageEnd(); - - uint32 len = pArraySinkOutput->TotalPutLength(); - if ( len >= cchEncodedData ) - { - AssertMsg2( false, "CCrypto::HexEncode: insufficient output buffer for encoding, needed %d got %d\n", - len, cchEncodedData ); - return false; - } - - pchEncodedData[len] = 0; // NULL-terminate - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Hex-decodes a block of data. (Text -> binary representation.) -// Input: pchData - Null-terminated hex-encoded string -// pubDecodedData - Pointer to buffer to store output in -// pcubDecodedData - Pointer to variable that contains size of -// output buffer. At exit, is filled in with actual size -// of decoded data. -//----------------------------------------------------------------------------- -bool CCrypto::HexDecode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData ) -{ - VPROF_BUDGET( "CCrypto::HexDecode", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pchData ); - Assert( pubDecodedData ); - Assert( pcubDecodedData ); - Assert( *pcubDecodedData ); - - ArraySink * pArraySinkOutput = new ArraySink( pubDecodedData, *pcubDecodedData ); - // Note: HexEncoder now owns the pointer to pOutputSink and will free it when the encoder goes out of scope and destructs - HexDecoder hexDecoder( pArraySinkOutput ); - hexDecoder.Put( (byte *) pchData, Q_strlen( pchData ) ); - hexDecoder.MessageEnd(); - - uint32 len = pArraySinkOutput->TotalPutLength(); - if ( len > *pcubDecodedData ) - { - AssertMsg2( false, "CCrypto::HexDecode: insufficient output buffer for decoding, needed %d got %d\n", - len, *pcubDecodedData ); - return false; - } - *pcubDecodedData = len; - - return true; -} - - -static const int k_LineBreakEveryNGroups = 18; // line break every 18 groups of 4 characters (every 72 characters) - -//----------------------------------------------------------------------------- -// Purpose: Returns the expected buffer size that should be passed to Base64Encode. -// Input: cubData - Size of data to encode -// bInsertLineBreaks - If line breaks should be inserted automatically -//----------------------------------------------------------------------------- -uint32 CCrypto::Base64EncodeMaxOutput( const uint32 cubData, const char *pszLineBreak ) -{ - // terminating null + 4 chars per 3-byte group + line break after every 18 groups (72 output chars) + final line break - uint32 nGroups = (cubData+2)/3; - str_size cchRequired = 1 + nGroups*4 + ( pszLineBreak ? Q_strlen(pszLineBreak)*(1+(nGroups-1)/k_LineBreakEveryNGroups) : 0 ); - return cchRequired; -} - - -//----------------------------------------------------------------------------- -// Purpose: Base64-encodes a block of data. (Binary -> text representation.) The output -// is null-terminated and can be treated as a string. -// Input: pubData - Data to encode -// cubData - Size of data to encode -// pchEncodedData - Pointer to string buffer to store output in -// cchEncodedData - Size of pchEncodedData buffer -// bInsertLineBreaks - If "\n" line breaks should be inserted automatically -//----------------------------------------------------------------------------- -bool CCrypto::Base64Encode( const uint8 *pubData, uint32 cubData, char *pchEncodedData, uint32 cchEncodedData, bool bInsertLineBreaks ) -{ - const char *pszLineBreak = bInsertLineBreaks ? "\n" : NULL; - uint32 cchRequired = Base64EncodeMaxOutput( cubData, pszLineBreak ); - (void)cchRequired; - AssertMsg2( cchEncodedData >= cchRequired, "CCrypto::Base64Encode: insufficient output buffer for encoding, needed %d got %d\n", cchRequired, cchEncodedData ); - return Base64Encode( pubData, cubData, pchEncodedData, &cchEncodedData, pszLineBreak ); -} - -//----------------------------------------------------------------------------- -// Purpose: Base64-encodes a block of data. (Binary -> text representation.) The output -// is null-terminated and can be treated as a string. -// Input: pubData - Data to encode -// cubData - Size of data to encode -// pchEncodedData - Pointer to string buffer to store output in -// pcchEncodedData - Pointer to size of pchEncodedData buffer; adjusted to number of characters written (before NULL) -// pszLineBreak - String to be inserted every 72 characters; empty string or NULL pointer for no line breaks -// Note: if pchEncodedData is NULL and *pcchEncodedData is zero, *pcchEncodedData is filled with the actual required length -// for output. A simpler approximation for maximum output size is (cubData * 4 / 3) + 5 if there are no linebreaks. -//----------------------------------------------------------------------------- -bool CCrypto::Base64Encode( const uint8 *pubData, uint32 cubData, char *pchEncodedData, uint32* pcchEncodedData, const char *pszLineBreak ) -{ - VPROF_BUDGET( "CCrypto::Base64Encode", VPROF_BUDGETGROUP_ENCRYPTION ); - - if ( pchEncodedData == NULL ) - { - AssertMsg( *pcchEncodedData == 0, "NULL output buffer with non-zero size passed to Base64Encode" ); - *pcchEncodedData = Base64EncodeMaxOutput( cubData, pszLineBreak ); - return true; - } - - const uint8 *pubDataEnd = pubData + cubData; - char *pchEncodedDataStart = pchEncodedData; - str_size unLineBreakLen = pszLineBreak ? Q_strlen( pszLineBreak ) : 0; - int nNextLineBreak = unLineBreakLen ? k_LineBreakEveryNGroups : INT_MAX; - - const char * const pszBase64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - uint32 cchEncodedData = *pcchEncodedData; - if ( cchEncodedData == 0 ) - goto out_of_space; - - --cchEncodedData; // pre-decrement for the terminating null so we don't forget about it - - // input 3 x 8-bit, output 4 x 6-bit - while ( pubDataEnd - pubData >= 3 ) - { - if ( cchEncodedData < 4 + unLineBreakLen ) - goto out_of_space; - - if ( nNextLineBreak == 0 ) - { - memcpy( pchEncodedData, pszLineBreak, unLineBreakLen ); - pchEncodedData += unLineBreakLen; - cchEncodedData -= unLineBreakLen; - nNextLineBreak = k_LineBreakEveryNGroups; - } - - uint32 un24BitsData; - un24BitsData = (uint32) pubData[0] << 16; - un24BitsData |= (uint32) pubData[1] << 8; - un24BitsData |= (uint32) pubData[2]; - pubData += 3; - - pchEncodedData[0] = pszBase64Chars[ (un24BitsData >> 18) & 63 ]; - pchEncodedData[1] = pszBase64Chars[ (un24BitsData >> 12) & 63 ]; - pchEncodedData[2] = pszBase64Chars[ (un24BitsData >> 6) & 63 ]; - pchEncodedData[3] = pszBase64Chars[ (un24BitsData ) & 63 ]; - pchEncodedData += 4; - cchEncodedData -= 4; - --nNextLineBreak; - } - - // Clean up remaining 1 or 2 bytes of input, pad output with '=' - if ( pubData != pubDataEnd ) - { - if ( cchEncodedData < 4 + unLineBreakLen ) - goto out_of_space; - - if ( nNextLineBreak == 0 ) - { - memcpy( pchEncodedData, pszLineBreak, unLineBreakLen ); - pchEncodedData += unLineBreakLen; - cchEncodedData -= unLineBreakLen; - } - - uint32 un24BitsData; - un24BitsData = (uint32) pubData[0] << 16; - if ( pubData+1 != pubDataEnd ) - { - un24BitsData |= (uint32) pubData[1] << 8; - } - pchEncodedData[0] = pszBase64Chars[ (un24BitsData >> 18) & 63 ]; - pchEncodedData[1] = pszBase64Chars[ (un24BitsData >> 12) & 63 ]; - pchEncodedData[2] = pubData+1 != pubDataEnd ? pszBase64Chars[ (un24BitsData >> 6) & 63 ] : '='; - pchEncodedData[3] = '='; - pchEncodedData += 4; - cchEncodedData -= 4; - } - - if ( unLineBreakLen ) - { - if ( cchEncodedData < unLineBreakLen ) - goto out_of_space; - memcpy( pchEncodedData, pszLineBreak, unLineBreakLen ); - pchEncodedData += unLineBreakLen; - cchEncodedData -= unLineBreakLen; - } - - *pchEncodedData = 0; - *pcchEncodedData = pchEncodedData - pchEncodedDataStart; - return true; - -out_of_space: - *pchEncodedData = 0; - *pcchEncodedData = Base64EncodeMaxOutput( cubData, pszLineBreak ); - AssertMsg( false, "CCrypto::Base64Encode: insufficient output buffer (up to n*4/3+5 bytes required, plus linebreaks)" ); - return false; -} - - -//----------------------------------------------------------------------------- -// Purpose: Base64-decodes a block of data. (Text -> binary representation.) -// Input: pchData - Null-terminated hex-encoded string -// pubDecodedData - Pointer to buffer to store output in -// pcubDecodedData - Pointer to variable that contains size of -// output buffer. At exit, is filled in with actual size -// of decoded data. -// Note: if NULL is passed as the output buffer and *pcubDecodedData is zero, the function -// will calculate the actual required size and place it in *pcubDecodedData. A simpler upper -// bound on the required size is ( strlen(pchData)*3/4 + 1 ). -//----------------------------------------------------------------------------- -bool CCrypto::Base64Decode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData, bool bIgnoreInvalidCharacters ) -{ - return Base64Decode( pchData, ~0u, pubDecodedData, pcubDecodedData, bIgnoreInvalidCharacters ); -} - -//----------------------------------------------------------------------------- -// Purpose: Base64-decodes a block of data. (Text -> binary representation.) -// Input: pchData - base64-encoded string, null terminated -// cchDataMax - maximum length of string unless a null is encountered first -// pubDecodedData - Pointer to buffer to store output in -// pcubDecodedData - Pointer to variable that contains size of -// output buffer. At exit, is filled in with actual size -// of decoded data. -// Note: if NULL is passed as the output buffer and *pcubDecodedData is zero, the function -// will calculate the actual required size and place it in *pcubDecodedData. A simpler upper -// bound on the required size is ( strlen(pchData)*3/4 + 2 ). -//----------------------------------------------------------------------------- -bool CCrypto::Base64Decode( const char *pchData, uint32 cchDataMax, uint8 *pubDecodedData, uint32 *pcubDecodedData, bool bIgnoreInvalidCharacters ) -{ - VPROF_BUDGET( "CCrypto::Base64Decode", VPROF_BUDGETGROUP_ENCRYPTION ); - - uint32 cubDecodedData = *pcubDecodedData; - uint32 cubDecodedDataOrig = cubDecodedData; - - if ( pubDecodedData == NULL ) - { - AssertMsg( *pcubDecodedData == 0, "NULL output buffer with non-zero size passed to Base64Decode" ); - cubDecodedDataOrig = cubDecodedData = ~0u; - } - - // valid base64 character range: '+' (0x2B) to 'z' (0x7A) - // table entries are 0-63, -1 for invalid entries, -2 for '=' - static const char rgchInvBase64[] = { - 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - -1, -1, -1, -2, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51 - }; - COMPILE_TIME_ASSERT( Q_ARRAYSIZE(rgchInvBase64) == 0x7A - 0x2B + 1 ); - - uint32 un24BitsWithSentinel = 1; - while ( cchDataMax-- > 0 ) - { - char c = *pchData++; - - if ( (uint8)(c - 0x2B) >= Q_ARRAYSIZE( rgchInvBase64 ) ) - { - if ( c == '\0' ) - break; - - if ( !bIgnoreInvalidCharacters && !( c == '\r' || c == '\n' || c == '\t' || c == ' ' ) ) - goto decode_failed; - else - continue; - } - - c = rgchInvBase64[(uint8)(c - 0x2B)]; - if ( c < 0 ) - { - if ( c == -2 ) // -2 -> terminating '=' - break; - - if ( !bIgnoreInvalidCharacters ) - goto decode_failed; - else - continue; - } - - un24BitsWithSentinel <<= 6; - un24BitsWithSentinel |= c; - if ( un24BitsWithSentinel & (1<<24) ) - { - if ( cubDecodedData < 3 ) // out of space? go to final write logic - break; - if ( pubDecodedData ) - { - pubDecodedData[0] = (uint8)( un24BitsWithSentinel >> 16 ); - pubDecodedData[1] = (uint8)( un24BitsWithSentinel >> 8); - pubDecodedData[2] = (uint8)( un24BitsWithSentinel ); - pubDecodedData += 3; - } - cubDecodedData -= 3; - un24BitsWithSentinel = 1; - } - } - - // If un24BitsWithSentinel contains data, output the remaining full bytes - if ( un24BitsWithSentinel >= (1<<6) ) - { - // Possibilities are 3, 2, 1, or 0 full output bytes. - int nWriteBytes = 3; - while ( un24BitsWithSentinel < (1<<24) ) - { - nWriteBytes--; - un24BitsWithSentinel <<= 6; - } - - // Write completed bytes to output - while ( nWriteBytes-- > 0 ) - { - if ( cubDecodedData == 0 ) - { - AssertMsg( false, "CCrypto::Base64Decode: insufficient output buffer (up to n*3/4+2 bytes required)" ); - goto decode_failed; - } - if ( pubDecodedData ) - { - *pubDecodedData++ = (uint8)(un24BitsWithSentinel >> 16); - } - --cubDecodedData; - un24BitsWithSentinel <<= 8; - } - } - - *pcubDecodedData = cubDecodedDataOrig - cubDecodedData; - return true; - -decode_failed: - *pcubDecodedData = cubDecodedDataOrig - cubDecodedData; - return false; -} - - -//----------------------------------------------------------------------------- -// Purpose: Generate a SHA1 hash -// Input: pchInput - Plaintext string of item to hash (null terminated) -// pOutDigest - Pointer to receive hashed digest output -//----------------------------------------------------------------------------- -bool CCrypto::GenerateSHA1Digest( const uint8 *pubInput, const int cubInput, SHADigest_t *pOutDigest ) -{ - VPROF_BUDGET( "CCrypto::GenerateSHA1Digest", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pubInput ); - Assert( cubInput > 0 ); - Assert( pOutDigest ); - - bool bSuccess = true; - try - { - CryptoPP::SHA().CalculateDigest( *pOutDigest, pubInput, cubInput ); - } - catch(...) - { - bSuccess = false; - } - - return bSuccess; -} - - -//----------------------------------------------------------------------------- -// Purpose: Generate a hash Salt - be careful, over-writing an existing salt -// will render the hashed value unverifiable. -//----------------------------------------------------------------------------- -bool CCrypto::GenerateSalt( Salt_t *pSalt ) -{ - VPROF_BUDGET( "CCrypto::GenerateSalt", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pSalt ); - - bool bSuccess = true; - try - { - CPoolAllocatedRNG rng; - rng.GetRNG().GenerateBlock( (byte*)pSalt, sizeof(Salt_t) ); - } - catch(...) - { - bSuccess = false; - } - - return bSuccess; -} - - -//----------------------------------------------------------------------------- -// Purpose: Generate a SHA1 hash using a salt. -// Input: pchInput - Plaintext string of item to hash (null terminated) -// pSalt - Salt -// pOutDigest - Pointer to receive salted digest output -//----------------------------------------------------------------------------- -bool CCrypto::GenerateSaltedSHA1Digest( const char *pchInput, const Salt_t *pSalt, SHADigest_t *pOutDigest ) -{ - VPROF_BUDGET( "CCrypto::GenerateSaltedSHA1Digest", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pchInput ); - Assert( pSalt ); - Assert( pOutDigest ); - - int iInputLen = Q_strlen( pchInput ); - uint8 *pubSaltedInput = new uint8[ iInputLen + sizeof( Salt_t ) ]; - - // Insert half the salt before the input string and half at the end. - // This is probably unnecessary (to split the salt) but we're stuck with it for historical reasons. - uint8 *pubCursor = pubSaltedInput; - Q_memcpy( pubCursor, (uint8 *)pSalt, sizeof(Salt_t) / 2 ); - pubCursor += sizeof( Salt_t ) / 2; - Q_memcpy( pubCursor, pchInput, iInputLen ); - pubCursor += iInputLen; - Q_memcpy( pubCursor, (uint8 *)pSalt + sizeof(Salt_t) / 2, sizeof(Salt_t) / 2 ); - - bool bSuccess = true; - try - { - CryptoPP::SHA().CalculateDigest( *pOutDigest, pubSaltedInput, iInputLen + sizeof( Salt_t ) ); - } - catch(...) - { - bSuccess = false; - } - - delete [] pubSaltedInput; - - return bSuccess; -} - - -//----------------------------------------------------------------------------- -// Purpose: Generates a random block of data -//----------------------------------------------------------------------------- -bool CCrypto::GenerateRandomBlock( uint8 *pubDest, int cubDest ) -{ - CPoolAllocatedRNG rng; - rng.GetRNG().GenerateBlock( pubDest, cubDest ); - - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Generate a keyed-hash MAC using SHA1 -// Input: pubData - Plaintext data to digest -// cubData - length of data -// pubKey - key to use in HMAC -// cubKey - length of key -// pOutDigest - Pointer to receive hashed digest output -//----------------------------------------------------------------------------- -bool CCrypto::GenerateHMAC( const uint8 *pubData, uint32 cubData, const uint8 *pubKey, uint32 cubKey, SHADigest_t *pOutputDigest ) -{ - VPROF_BUDGET( "CCrypto::GenerateHMAC", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pubData ); - Assert( cubData > 0 ); - Assert( pubKey ); - Assert( cubKey > 0 ); - Assert( pOutputDigest ); - - bool bSuccess = true; - try - { - CryptoPP::HMAC< CryptoPP::SHA1 > hmac( pubKey, cubKey ); - hmac.CalculateDigest( *pOutputDigest, pubData, cubData ); - } - catch(...) - { - bSuccess = false; - } - - return bSuccess; -} - - -//----------------------------------------------------------------------------- -// Purpose: Generate a keyed-hash MAC using SHA-256 -//----------------------------------------------------------------------------- -bool CCrypto::GenerateHMAC256( const uint8 *pubData, uint32 cubData, const uint8 *pubKey, uint32 cubKey, SHA256Digest_t *pOutputDigest ) -{ - VPROF_BUDGET( "CCrypto::GenerateHMAC256", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pubData ); - Assert( cubData > 0 ); - Assert( pubKey ); - Assert( cubKey > 0 ); - Assert( pOutputDigest ); - - bool bSuccess = true; - try - { - CryptoPP::HMAC< CryptoPP::SHA256 > hmac( pubKey, cubKey ); - hmac.CalculateDigest( *pOutputDigest, pubData, cubData ); - } - catch(...) - { - bSuccess = false; - } - - return bSuccess; -} - - -bool CCrypto::BGzipBuffer( const uint8 *pubData, uint32 cubData, CCryptoOutBuffer &bufOutput ) -{ - bool bSuccess = true; - try - { - std::string gzip_output; - StringSource( (byte *)pubData, cubData, true, new Gzip( new StringSink( gzip_output ) ) ); - bufOutput.Set( (uint8*)gzip_output.c_str(), (uint32)gzip_output.length() ); - } - catch( ... ) - { - bSuccess = false; - } - return bSuccess; -} - - -bool CCrypto::BGunzipBuffer( const uint8 *pubData, uint32 cubData, CCryptoOutBuffer &bufOutput ) -{ - bool bSuccess = true; - try - { - std::string gunzip_output; - StringSource( (byte *)pubData, cubData, true, new Gunzip( new StringSink( gunzip_output ) ) ); - bufOutput.Set( (uint8*)gunzip_output.c_str(), (uint32)gunzip_output.length() ); - } - catch( ... ) - { - bSuccess = false; - } - return bSuccess; -} - - -//! These are all needed to get around stack-overflow bug in Initialize() -class HexDecoderTKS : public HexDecoder -{ -public: - HexDecoderTKS(BufferedTransformation *attachment, const int *pnDecodingArray) - : HexDecoder(attachment) - { - BaseN_Decoder::IsolatedInitialize( MakeParameters( Name::DecodingLookupArray(), pnDecodingArray )( Name::Log2Base(), 4 ) ); - } -}; - -class Base32DecoderTKS : public Base32Decoder -{ -public: - Base32DecoderTKS(BufferedTransformation *attachment, const int *pnDecodingArray) - : Base32Decoder(attachment) - { - BaseN_Decoder::IsolatedInitialize( MakeParameters( Name::DecodingLookupArray(), pnDecodingArray )( Name::Log2Base(), 5 ) ); - } -}; - - -//----------------------------------------------------------------------------- -// Purpose: Implement hex encoding / decoding using a custom lookup table. -// This is a class because the decoding is done via a generated -// reverse-lookup table, and to save time it's best to just create -// that table once. -//----------------------------------------------------------------------------- -CCustomHexEncoder::CCustomHexEncoder( const char *pchEncodingTable ) -{ - m_bValidEncoding = false; - if ( Q_strlen( pchEncodingTable ) == sizeof( m_rgubEncodingTable ) ) - { - Q_memcpy( m_rgubEncodingTable, pchEncodingTable, sizeof( m_rgubEncodingTable ) ); - - BaseN_Decoder::InitializeDecodingLookupArray( m_rgnDecodingTable, m_rgubEncodingTable, 16, false ); - m_bValidEncoding = true; - } - else - { - AssertMsg( false, "CCrypto::CustomHexEncoder: Improper encoding table\n" ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Destructor -//----------------------------------------------------------------------------- -CCustomHexEncoder::~CCustomHexEncoder() -{ -} - - -//----------------------------------------------------------------------------- -// Purpose: Hex-encodes a block of data. (Binary -> text representation.) The output -// is null-terminated and can be treated as a string. -// Uses the supplied custom encoding characters -// Input: pubData - Data to encode -// cubData - Size of data to encode -// pchEncodedData - Pointer to string buffer to store output in -// cchEncodedData - Size of pchEncodedData buffer -//----------------------------------------------------------------------------- -bool CCustomHexEncoder::Encode( const uint8 *pubData, const uint32 cubData, char *pchEncodedData, uint32 cchEncodedData ) -{ - VPROF_BUDGET( "CCrypto::CustomHexEncode", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pubData ); - Assert( cubData ); - Assert( pchEncodedData ); - Assert( cchEncodedData > 0 ); - - if ( !m_bValidEncoding ) - return false; - - ArraySink * pArraySinkOutput = new ArraySink( (byte *) pchEncodedData, cchEncodedData ); - // Note: HexEncoder now owns the pointer to pOutputSink and will free it when the encoder goes out of scope and destructs - HexEncoder hexEncoder( pArraySinkOutput ); - hexEncoder.IsolatedInitialize( MakeParameters( Name::EncodingLookupArray(), (const uint8 *)m_rgubEncodingTable ) ); - hexEncoder.Put( pubData, cubData ); - hexEncoder.MessageEnd(); - - uint32 len = pArraySinkOutput->TotalPutLength(); - pchEncodedData[len] = 0; // NULL-terminate - if ( len >= cchEncodedData ) - { - AssertMsg2( false, "CCrypto::CustomHexEncode: insufficient output buffer for encoding, needed %d got %d\n", - len, cchEncodedData ); - return false; - } - - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Hex-decodes a block of data. (Text -> binary representation.) -// With custom encoding-table -// Input: pchData - Null-terminated hex-encoded string -// pubDecodedData - Pointer to buffer to store output in -// pcubDecodedData - Pointer to variable that contains size of -// output buffer. At exit, is filled in with actual size -// of decoded data. -//----------------------------------------------------------------------------- -bool CCustomHexEncoder::Decode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData ) -{ - VPROF_BUDGET( "CCrypto::CustomHexDecode", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pchData ); - Assert( pubDecodedData ); - Assert( pcubDecodedData ); - Assert( *pcubDecodedData ); - - if ( !m_bValidEncoding ) - return false; - - ArraySink * pArraySinkOutput = new ArraySink( pubDecodedData, *pcubDecodedData ); - // Note: HexEncoder now owns the pointer to pOutputSink and will free it when the encoder goes out of scope and destructs - HexDecoderTKS hexDecoder( pArraySinkOutput, (const int *)m_rgnDecodingTable ); - hexDecoder.Put( (byte *) pchData, Q_strlen( pchData ) ); - hexDecoder.MessageEnd(); - - uint32 len = pArraySinkOutput->TotalPutLength(); - if ( len > *pcubDecodedData ) - { - AssertMsg2( false, "CCrypto::CustomHexDecode: insufficient output buffer for decoding, needed %d got %d\n", - len, *pcubDecodedData ); - return false; - } - *pcubDecodedData = len; - - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Implement hex encoding / decoding using a custom lookup table. -// This is a class because the decoding is done via a generated -// reverse-lookup table, and to save time it's best to just create -// that table once. -//----------------------------------------------------------------------------- -CCustomBase32Encoder::CCustomBase32Encoder( const char *pchEncodingTable ) -{ - m_bValidEncoding = false; - if ( Q_strlen( pchEncodingTable ) == sizeof( m_rgubEncodingTable ) ) - { - Q_memcpy( m_rgubEncodingTable, pchEncodingTable, sizeof( m_rgubEncodingTable ) ); - - BaseN_Decoder::InitializeDecodingLookupArray( m_rgnDecodingTable, m_rgubEncodingTable, 32, false ); - m_bValidEncoding = true; - } - else - { - AssertMsg( false, "CCrypto::CustomBase32Encoder: Improper encoding table\n" ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Destructor -//----------------------------------------------------------------------------- -CCustomBase32Encoder::~CCustomBase32Encoder() -{ -} - - -//----------------------------------------------------------------------------- -// Purpose: Base32-encodes a block of data. (Binary -> text representation.) The output -// is null-terminated and can be treated as a string. -// Uses the supplied custom encoding table -// Input: pubData - Data to encode -// cubData - Size of data to encode -// pchEncodedData - Pointer to string buffer to store output in -// cchEncodedData - Size of pchEncodedData buffer -//----------------------------------------------------------------------------- -bool CCustomBase32Encoder::Encode( const uint8 *pubData, const uint32 cubData, char *pchEncodedData, uint32 cchEncodedData ) -{ - VPROF_BUDGET( "CCrypto::CustomBase32Encode", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pubData ); - Assert( cubData ); - Assert( pchEncodedData ); - Assert( cchEncodedData > 0 ); - - if ( !m_bValidEncoding ) - return false; - - ArraySink * pArraySinkOutput = new ArraySink( (byte *) pchEncodedData, cchEncodedData ); - // Note: Base32Encoder now owns the pointer to pOutputSink and will free it when the encoder goes out of scope and destructs - Base32Encoder base32Encoder( pArraySinkOutput ); - base32Encoder.IsolatedInitialize( MakeParameters( Name::EncodingLookupArray(), (const uint8 *)m_rgubEncodingTable ) ); - base32Encoder.Put( pubData, cubData ); - base32Encoder.MessageEnd(); - - uint32 len = pArraySinkOutput->TotalPutLength(); - pchEncodedData[len] = 0; // NULL-terminate - if ( len >= cchEncodedData ) - { - AssertMsg2( false, "CCrypto::CustomBase32Encode: insufficient output buffer for encoding, needed %d got %d\n", - len, cchEncodedData ); - return false; - } - - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Base32-decodes a block of data. (Text -> binary representation.) -// With custom encoding table -// Input: pchData - Null-terminated hex-encoded string -// pubDecodedData - Pointer to buffer to store output in -// pcubDecodedData - Pointer to variable that contains size of -// output buffer. At exit, is filled in with actual size -// of decoded data. -//----------------------------------------------------------------------------- -bool CCustomBase32Encoder::Decode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData ) -{ - VPROF_BUDGET( "CCrypto::CustomBase32Decode", VPROF_BUDGETGROUP_ENCRYPTION ); - Assert( pchData ); - Assert( pubDecodedData ); - Assert( pcubDecodedData ); - Assert( *pcubDecodedData ); - - if ( !m_bValidEncoding ) - return false; - - ArraySink * pArraySinkOutput = new ArraySink( pubDecodedData, *pcubDecodedData ); - // Note: Base32Encoder now owns the pointer to pOutputSink and will free it when the encoder goes out of scope and destructs - Base32DecoderTKS base32Decoder( pArraySinkOutput, (const int *)m_rgnDecodingTable ); - base32Decoder.Put( (byte *) pchData, Q_strlen( pchData ) ); - base32Decoder.MessageEnd(); - - uint32 len = pArraySinkOutput->TotalPutLength(); - if ( len > *pcubDecodedData ) - { - AssertMsg2( false, "CCrypto::CustomBase32Decode: insufficient output buffer for decoding, needed %d got %d\n", - len, *pcubDecodedData ); - return false; - } - *pcubDecodedData = len; - - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Base32-encodes a block of data. (Binary -> text representation.) The output -// is null-terminated and can be treated as a string. -// Uses the supplied custom encoding table, and a bit-stream input source -// (not necessarily an integer number of bytes). -// Input: pBitStringData - Data to encode -// pchEncodedData - Pointer to string buffer to store output in -// cchEncodedData - Size of pchEncodedData buffer -//----------------------------------------------------------------------------- -bool CCustomBase32Encoder::Encode( CSimpleBitString *pBitStringData, char *pchEncodedData, uint32 cchEncodedData ) -{ - // This is useful if you have, say, 125 bits of information and - // want to encode them into 25 base32-encoded characters. - uint32 cBits = pBitStringData->GetCurrNumBits(); - - uint32 cCharacters = (cBits / 5); - uint32 cBitsRemainder = cBits % 5; - if ( cBitsRemainder ) - cCharacters++; - - // GTE because of NULL - if ( cCharacters >= cchEncodedData ) - return false; - - CSimpleBitString::iterator itBitString( *pBitStringData ); - uint ich = 0; - for ( ; ich < cCharacters; ++ich ) - { - uint32 unCodon = itBitString.GetNextBits( 5 ); - // Pad w/ zero bits to integer num codons - if ( ich == (cCharacters - 1) ) - unCodon <<= cBitsRemainder; - - pchEncodedData[ich] = m_rgubEncodingTable[ unCodon ]; - } - - // NULL - pchEncodedData[ich] = 0; - - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Base32-decodes a block of data. (Text -> binary representation.) -// With custom encoding table, and a BitString output -// Input: pchData - Null-terminated base32-encoded string -// pBitStringDecodedData - Pointer to BitString to receive decoded data -//----------------------------------------------------------------------------- -bool CCustomBase32Encoder::Decode( const char *pchData, CSimpleBitString *pBitStringDecodedData ) -{ - // Note: 25 base32-encoded characters contain 125 bits of information. - // Decoded into a byte buffer, this yields 15 bytes plus 5 bits of padding. - // Decoded into a CSimpleBitString, it will yield all 125 bits - while ( *pchData ) - { - uint32 unData = m_rgnDecodingTable[(unsigned)*pchData++]; - if ( unData == 0xFFFFFFFF ) - return false; - - pBitStringDecodedData->AppendBits( unData, 5 ); - } - - return true; -} - -#ifdef DBGFLAG_VALIDATE -//----------------------------------------------------------------------------- -// Purpose: validates memory structures -//----------------------------------------------------------------------------- -void CCrypto::ValidateStatics( CValidator &validator, const char *pchName ) -{ - ValidateObj( g_tslistPAutoSeededRNG ); -} -#endif // DBGFLAG_VALIDATE - - -//----------------------------------------------------------------------------- -// Purpose: Given a plaintext password, check whether it matches an existing -// hash -//----------------------------------------------------------------------------- -bool CCrypto::BValidatePasswordHash( const char *pchInput, EPasswordHashAlg hashType, const PasswordHash_t &DigestStored, const Salt_t &Salt, PasswordHash_t *pDigestComputed ) -{ - VPROF_BUDGET( "CCrypto::BValidatePasswordHash", VPROF_BUDGETGROUP_ENCRYPTION ); - - bool bResult = false; - size_t cDigest = k_HashLengths[hashType]; - Assert( cDigest != 0 ); - PasswordHash_t tmpDigest; - PasswordHash_t *pOutputDigest = pDigestComputed; - if ( pOutputDigest == NULL ) - { - pOutputDigest = &tmpDigest; - } - - BGeneratePasswordHash( pchInput, hashType, Salt, *pOutputDigest ); - bResult = ( 0 == Q_memcmp( &DigestStored, pOutputDigest, cDigest ) ); - - return bResult; -} - -//----------------------------------------------------------------------------- -// Purpose: Given a plaintext password and salt, generate a password hash of -// the requested type. -//----------------------------------------------------------------------------- -bool CCrypto::BGeneratePasswordHash( const char *pchInput, EPasswordHashAlg hashType, const Salt_t &Salt, PasswordHash_t &OutPasswordHash ) -{ - VPROF_BUDGET( "CCrypto::BGeneratePasswordHash", VPROF_BUDGETGROUP_ENCRYPTION ); - - bool bResult = false; - size_t cDigest = k_HashLengths[hashType]; - - switch ( hashType ) - { - case k_EHashSHA1: - bResult = CCrypto::GenerateSaltedSHA1Digest( pchInput, &Salt, (SHADigest_t *)&OutPasswordHash.sha ); - break; - case k_EHashBigPassword: - { - // - // This is a fake algorithm to test widening of the column. It's a salted SHA-1 hash with 0x01 padding - // on either side of it. - // - size_t cDigestSHA1 = k_HashLengths[k_EHashSHA1]; - size_t cPadding = ( cDigest - cDigestSHA1 ) / 2; - - AssertMsg( ( ( cDigest - cDigestSHA1 ) % 2 ) == 0, "Invalid hash width for k_EHashBigPassword, needs to be even." ); - - CCrypto::GenerateSaltedSHA1Digest( pchInput, &Salt, (SHADigest_t *)( (uint8 *)&OutPasswordHash.bigpassword + cPadding ) ); - Q_memset( (uint8 *)&OutPasswordHash, 0x01, cPadding ); - Q_memset( (uint8 *)&OutPasswordHash + cPadding + cDigestSHA1 , 0x01, cPadding ); - bResult = true; - break; - } - case k_EHashPBKDF2_1000: - bResult = CCrypto::BGeneratePBKDF2Hash( pchInput, Salt, 1000, OutPasswordHash ); - break; - case k_EHashPBKDF2_5000: - bResult = CCrypto::BGeneratePBKDF2Hash( pchInput, Salt, 5000, OutPasswordHash ); - break; - case k_EHashPBKDF2_10000: - bResult = CCrypto::BGeneratePBKDF2Hash( pchInput, Salt, 10000, OutPasswordHash ); - break; - case k_EHashSHA1WrappedWithPBKDF2_10000: - bResult = CCrypto::BGenerateWrappedSHA1PasswordHash( pchInput, Salt, 10000, OutPasswordHash ); - break; - default: - AssertMsg1( false, "Invalid password hash type %u passed to BGeneratePasswordHash\n", hashType ); - bResult = false; - } - - return bResult; -} - -//----------------------------------------------------------------------------- -// Purpose: Given a plaintext password and salt and a count of rounds, generate a PBKDF2 hash -// with the requested number of rounds. -//----------------------------------------------------------------------------- -bool CCrypto::BGeneratePBKDF2Hash( const char* pchInput, const Salt_t &Salt, unsigned int rounds, PasswordHash_t &OutPasswordHash ) -{ - PKCS5_PBKDF2_HMAC pbkdf; - - unsigned int iterations = pbkdf.DeriveKey( (byte *)&OutPasswordHash.pbkdf2, sizeof(OutPasswordHash.pbkdf2), 0, (const byte *)pchInput, Q_strlen(pchInput), (const byte *)&Salt, sizeof(Salt), rounds ); - - return ( iterations == rounds ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Given a plaintext password and salt and a count of rounds, generate a SHA1 hash wrapped with -// a PBKDF2 hash with the specified number of rounds. -// Used to provide a stronger password hash for accounts that haven't logged in in a while. -//----------------------------------------------------------------------------- -bool CCrypto::BGenerateWrappedSHA1PasswordHash( const char *pchInput, const Salt_t &Salt, unsigned int rounds, PasswordHash_t &OutPasswordHash ) -{ - bool bResult; - bResult = CCrypto::GenerateSaltedSHA1Digest( pchInput, &Salt, (SHADigest_t *)&OutPasswordHash.sha ); - if ( bResult ) - { - PKCS5_PBKDF2_HMAC pbkdf; - 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 ); - - bResult = ( iterations == rounds ); - } - return bResult; -} - -//----------------------------------------------------------------------------- -// Purpose: Given an existing password hash and salt, attempt to construct a stronger -// password hash and return the new hash type. -// -// Currently the only transformation available is from a SHA1 (or BigPassword) -// hash to a PBKDF2 hash with 10,000 rounds. In the future this function -// may be extended to allow additional transformations. -//----------------------------------------------------------------------------- -bool CCrypto::BUpgradeOrWrapPasswordHash( PasswordHash_t &InPasswordHash, EPasswordHashAlg hashTypeIn, const Salt_t &Salt, PasswordHash_t &OutPasswordHash, EPasswordHashAlg &hashTypeOut ) -{ - bool bResult = true;; - - if ( hashTypeIn == k_EHashSHA1 || hashTypeIn == k_EHashBigPassword ) - { - // - // Can wrap a SHA1 hash with any PBKDF variant, but right now only 10,000 rounds is - // implemented. - // - if ( hashTypeOut == k_EHashPBKDF2_10000 ) - { - hashTypeOut = k_EHashSHA1WrappedWithPBKDF2_10000; - - byte * pbHash; - if ( hashTypeIn == k_EHashSHA1 ) - { - pbHash = (byte *)&InPasswordHash.sha; - } - else - { - // - // Need to unroll BigPasswordHash into unpadded SHA1 - // - size_t cDigest = k_HashLengths[k_EHashBigPassword]; - size_t cDigestSHA1 = k_HashLengths[k_EHashSHA1]; - size_t cPadding = ( cDigest - cDigestSHA1 ) / 2; - - AssertMsg( ( ( cDigest - cDigestSHA1 ) % 2 ) == 0, "Invalid hash width for k_EHashBigPassword, needs to be even." ); - pbHash = (byte *)&InPasswordHash.sha + cPadding; - } - - PKCS5_PBKDF2_HMAC pbkdf; - PasswordHash_t passOut; - unsigned int iterations = pbkdf.DeriveKey( (byte *)passOut.pbkdf2, sizeof(passOut.pbkdf2), 0, pbHash, k_HashLengths[k_EHashSHA1], (const byte *)&Salt, sizeof(Salt), 10000 ); - - bResult = ( iterations == 10000 ); - if ( bResult ) - { - Q_memcpy( &OutPasswordHash, &passOut, sizeof(OutPasswordHash) ); - } - } - else - { - Assert( hashTypeOut == k_EHashPBKDF2_10000 ); - bResult = false; - } - } - else - { - bResult = false; - Assert( false ); - } - - return bResult; -} - diff --git a/common/crypto.h b/common/crypto.h deleted file mode 100644 index 80b25b2c..00000000 --- a/common/crypto.h +++ /dev/null @@ -1,281 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: This module is for wrapping Crypto++ functions, including crypto++ -// directly has nasty consequences polluting the global namespace, and -// conflicting with xdebug and locale stuff, so we only include it here -// and use this wrapper in the rest of our code. -// -// $NoKeywords: $ -//============================================================================= - -#ifndef CRYPTO_H -#define CRYPTO_H - -#include // for Assert & AssertMsg -#include "tier1/passwordhash.h" -#include "tier1/utlmemory.h" -#include // for Salt_t - -extern void FreeListRNG(); - -const unsigned int k_cubSHA256Hash = 32; -typedef unsigned char SHA256Digest_t[ k_cubSHA256Hash ]; - -const int k_nSymmetricBlockSize = 16; // AES block size (128 bits) -const int k_nSymmetricKeyLen = 32; // length in bytes of keys used for symmetric encryption - -const int k_nRSAKeyLenMax = 1024; // max length in bytes of keys used for RSA encryption (includes DER encoding) -const int k_nRSAKeyLenMaxEncoded = k_nRSAKeyLenMax*2; // max length in bytes of hex-encoded key (hex encoding exactly doubles size) -const int k_nRSAKeyBits = 1024; // length in bits of keys used for RSA encryption -const int k_cubRSAEncryptedBlockSize = 128; -const int k_cubRSAPlaintextBlockSize = 86 + 1; // assume plaintext is text, so add a byte for the trailing \0 -const uint32 k_cubRSASignature = k_cubRSAEncryptedBlockSize; - -// Simple buffer class to encapsulate output from crypto functions with unknown output size -class CCryptoOutBuffer -{ -public: - - CCryptoOutBuffer() - { - m_pubData = NULL; - m_cubData = 0; - } - - ~CCryptoOutBuffer() - { - if ( m_pubData ) - delete[] m_pubData; - m_pubData = NULL; - m_cubData = 0; - } - - void Set( uint8 *pubData, uint32 cubData ) - { - if ( !pubData || !cubData ) - return; - - if ( m_pubData ) - delete[] m_pubData; - - m_pubData = new uint8[ cubData ]; - memcpy( m_pubData, pubData, cubData ); - m_cubData = cubData; - } - - void Allocate( uint32 cubData ) - { - if ( m_pubData ) - delete[] m_pubData; - - m_pubData = new uint8[ cubData ]; - m_cubData = cubData; - } - - void Trim( uint32 cubTrim ) - { - Assert( cubTrim <= m_cubData ); - m_cubData = cubTrim; - } - - uint8 *PubData() { return m_pubData; } - uint32 CubData() { return m_cubData; } - -private: - uint8 *m_pubData; - uint32 m_cubData; -}; - -#if !defined(_PS3) -class CCrypto -{ -public: - static uint32 GetSymmetricEncryptedSize( uint32 cubPlaintextData ); - - // this method writes the encrypted IV, then the ciphertext - static bool SymmetricEncryptWithIV( const uint8 * pubPlaintextData, uint32 cubPlaintextData, - const uint8 * pIV, uint32 cubIV, - uint8 * pubEncryptedData, uint32 * pcubEncryptedData, - const uint8 * pubKey, uint32 cubKey ); - static bool SymmetricEncrypt( const uint8 * pubPlaintextData, uint32 cubPlaintextData, - uint8 * pubEncryptedData, uint32 * pcubEncryptedData, - const uint8 * pubKey, uint32 cubKey ); - // this method assumes there is no IV before the payload - dissimilar to SymmetricEncryptWithIV - static bool SymmetricDecryptWithIV( const uint8 * pubEncryptedData, uint32 cubEncryptedData, - const uint8 * pIV, uint32 cubIV, - uint8 * pubPlaintextData, uint32 * pcubPlaintextData, - const uint8 * pubKey, uint32 cubKey ); - static bool SymmetricDecrypt( const uint8 * pubEncryptedData, uint32 cubEncryptedData, - uint8 * pubPlaintextData, uint32 * pcubPlaintextData, - const uint8 * pubKey, uint32 cubKey ); - - // symmetrically encrypt data with a text password. A SHA256 hash of the password - // is used as an AES encryption key (calls SymmetricEncrypt, above). - // An HMAC of the ciphertext is appended, for authentication. - static bool EncryptWithPasswordAndHMAC( const uint8 *pubPlaintextData, uint32 cubPlaintextData, - uint8 * pubEncryptedData, uint32 * pcubEncryptedData, - const char *pchPassword ); - - // Same as above but uses an explicit IV. The format of the ciphertext is the same. - // Be sure you know what you're doing if you use this - a random IV is much more secure in general! - static bool EncryptWithPasswordAndHMACWithIV( const uint8 *pubPlaintextData, uint32 cubPlaintextData, - const uint8 * pIV, uint32 cubIV, - uint8 * pubEncryptedData, uint32 * pcubEncryptedData, - const char *pchPassword ); - - // Symmetrically decrypt data with the given password (see above). - // If the HMAC does not match what we expect, then we know that either the password is - // incorrect or the message is corrupted. - static bool DecryptWithPasswordAndAuthenticate( const uint8 * pubEncryptedData, uint32 cubEncryptedData, - uint8 * pubPlaintextData, uint32 * pcubPlaintextData, - const char *pchPassword ); - - static bool RSAGenerateKeys( uint8 *pubPublicKey, uint32 *pcubPublicKey, uint8 *pubPrivateKey, uint32 *pcubPrivateKey ); - - static bool RSAEncrypt( const uint8 *pubPlaintextPlaintextData, const uint32 cubData, uint8 *pubEncryptedData, - uint32 *pcubEncryptedData, const uint8 *pubPublicKey, const uint32 cubPublicKey ); - static bool RSADecrypt( const uint8 *pubEncryptedData, uint32 cubEncryptedData, - uint8 *pubPlaintextData, uint32 *pcubPlaintextData, const uint8 *pubPrivateKey, const uint32 cubPrivateKey ); - - // decrypt using a public key, and no padding - static bool RSAPublicDecrypt_NoPadding( const uint8 *pubEncryptedData, uint32 cubEncryptedData, - uint8 *pubPlaintextData, uint32 *pcubPlaintextData, const uint8 *pubPublicKey, const uint32 cubPublicKey ); - - static bool RSASign( const uint8 *pubData, const uint32 cubData, - uint8 *pubSignature, uint32 *pcubSignature, - const uint8 * pubPrivateKey, const uint32 cubPrivateKey ); - static bool RSAVerifySignature( const uint8 *pubData, const uint32 cubData, - const uint8 *pubSignature, const uint32 cubSignature, - const uint8 *pubPublicKey, const uint32 cubPublicKey ); - - static bool RSASignSHA256( const uint8 *pubData, const uint32 cubData, - uint8 *pubSignature, uint32 *pcubSignature, - const uint8 * pubPrivateKey, const uint32 cubPrivateKey ); - static bool RSAVerifySignatureSHA256( const uint8 *pubData, const uint32 cubData, - const uint8 *pubSignature, const uint32 cubSignature, - const uint8 *pubPublicKey, const uint32 cubPublicKey ); - - static bool HexEncode( const uint8 *pubData, const uint32 cubData, char *pchEncodedData, uint32 cchEncodedData ); - static bool HexDecode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData ); - - static uint32 Base64EncodeMaxOutput( uint32 cubData, const char *pszLineBreakOrNull ); - static bool Base64Encode( const uint8 *pubData, uint32 cubData, char *pchEncodedData, uint32 cchEncodedData, bool bInsertLineBreaks = true ); // legacy, deprecated - static bool Base64Encode( const uint8 *pubData, uint32 cubData, char *pchEncodedData, uint32 *pcchEncodedData, const char *pszLineBreak = "\n" ); - - static uint32 Base64DecodeMaxOutput( uint32 cubData ) { return ( (cubData + 3 ) / 4) * 3 + 1; } - static bool Base64Decode( const char *pchEncodedData, uint8 *pubDecodedData, uint32 *pcubDecodedData, bool bIgnoreInvalidCharacters = true ); // legacy, deprecated - static bool Base64Decode( const char *pchEncodedData, uint32 cchEncodedData, uint8 *pubDecodedData, uint32 *pcubDecodedData, bool bIgnoreInvalidCharacters = true ); - - static bool GenerateSalt( Salt_t *pSalt ); - static bool GenerateSHA1Digest( const uint8 *pubInput, const int cubInput, SHADigest_t *pOutDigest ); - static bool GenerateSaltedSHA1Digest( const char *pchInput, const Salt_t *pSalt, SHADigest_t *pOutDigest ); - static bool GenerateRandomBlock( uint8 *pubDest, int cubDest ); - - static bool GenerateHMAC( const uint8 *pubData, uint32 cubData, const uint8 *pubKey, uint32 cubKey, SHADigest_t *pOutputDigest ); - static bool GenerateHMAC256( const uint8 *pubData, uint32 cubData, const uint8 *pubKey, uint32 cubKey, SHA256Digest_t *pOutputDigest ); - - static bool BGeneratePasswordHash( const char *pchInput, EPasswordHashAlg hashType, const Salt_t &Salt, PasswordHash_t &OutPasswordHash ); - static bool BValidatePasswordHash( const char *pchInput, EPasswordHashAlg hashType, const PasswordHash_t &DigestStored, const Salt_t &Salt, PasswordHash_t *pDigestComputed ); - static bool BGeneratePBKDF2Hash( const char *pchInput, const Salt_t &Salt, unsigned int rounds, PasswordHash_t &OutPasswordHash ); - static bool BGenerateWrappedSHA1PasswordHash( const char *pchInput, const Salt_t &Salt, unsigned int rounds, PasswordHash_t &OutPasswordHash ); - static bool BUpgradeOrWrapPasswordHash( PasswordHash_t &InPasswordHash, EPasswordHashAlg hashTypeIn, const Salt_t &Salt, PasswordHash_t &OutPasswordHash, EPasswordHashAlg &hashTypeOut ); - - static bool BGzipBuffer( const uint8 *pubData, uint32 cubData, CCryptoOutBuffer &bufOutput ); - static bool BGunzipBuffer( const uint8 *pubData, uint32 cubData, CCryptoOutBuffer &bufOutput ); - -#ifdef DBGFLAG_VALIDATE - static void ValidateStatics( CValidator &validator, const char *pchName ); -#endif -}; - -#else - -// bugbug ps3 - stub until we implement from PS3 libs -class CCrypto -{ -public: - // ps3 only - static bool Init(); - static void Shutdown(); - - //shared - static uint32 GetSymmetricEncryptedSize( uint32 cubPlaintextData ); - - static bool SymmetricEncrypt( const uint8 * pubPlaintextData, uint32 cubPlaintextData, uint8 * pubEncryptedData, uint32 * pcubEncryptedData, const uint8 * pubKey, uint32 cubKey ); - static bool SymmetricDecrypt( const uint8 * pubEncryptedData, uint32 cubEncryptedData, uint8 * pubPlaintextData, uint32 * pcubPlaintextData, const uint8 * pubKey, uint32 cubKey ); - static bool RSAGenerateKeys( uint8 *pubPublicKey, uint32 *pcubPublicKey, uint8 *pubPrivateKey, uint32 *pcubPrivateKey ) { AssertMsg( false, "RSAGenerateKeys not implemented on PS3" ); return false; } - static bool RSAEncrypt( const uint8 *pubPlaintextPlaintextData, const uint32 cubData, uint8 *pubEncryptedData, uint32 *pcubEncryptedData, const uint8 *pubPublicKey, const uint32 cubPublicKey ); - static bool RSADecrypt( const uint8 *pubEncryptedData, uint32 cubEncryptedData, uint8 *pubPlaintextData, uint32 *pcubPlaintextData, const uint8 *pubPrivateKey, const uint32 cubPrivateKey ); - static bool RSAPublicDecrypt_NoPadding( const uint8 *pubEncryptedData, uint32 cubEncryptedData, uint8 *pubPlaintextData, uint32 *pcubPlaintextData, const uint8 *pubPublicKey, const uint32 cubPublicKey ) { AssertMsg( false, "RSAPublicDecrypt_NoPadding not implemented on PS3" ); return false; } - static bool RSASign( const uint8 *pubData, const uint32 cubData, uint8 *pubSignature, uint32 *pcubSignature, const uint8 * pubPrivateKey, const uint32 cubPrivateKey ); - static bool RSAVerifySignature( const uint8 *pubData, const uint32 cubData, const uint8 *pubSignature, const uint32 cubSignature, const uint8 *pubPublicKey, const uint32 cubPublicKey ); - static bool HexEncode( const uint8 *pubData, const uint32 cubData, char *pchEncodedData, uint32 cchEncodedData ); - static bool HexDecode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData ); - static bool Base64Encode( const uint8 *pubData, const uint32 cubData, char *pchEncodedData, uint32 cchEncodedData, bool bInsertLineBreaks = true ) { AssertMsg( false, "Base64Encode not implemented on PS3" ); return false; } // cellHttpUtilBase64Encoder() - static bool Base64Decode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData, bool bIgnoreInvalidCharacters = true ) { AssertMsg( false, "Base64Decode not implemented on PS3" ); return false; } // cellHttpUtilBase64Decoder() - static bool GenerateSalt( Salt_t *pSalt ); - static bool GenerateSHA1Digest( const uint8 *pubInput, const int cubInput, SHADigest_t *pOutDigest ); - static bool GenerateSaltedSHA1Digest( const char *pchInput, const Salt_t *pSalt, SHADigest_t *pOutDigest ) { AssertMsg( false, "GenerateSaltedSHA1Digest not implemented on PS3" ); return false; } - static bool GenerateRandomBlock( uint8 *pubDest, int cubDest ); - static bool GenerateHMAC( const uint8 *pubData, uint32 cubData, const uint8 *pubKey, uint32 cubKey, SHADigest_t *pOutputDigest ) { AssertMsg( false, "GenerateHMAC not implemented on PS3" ); return false; } - static bool GenerateHMAC256( const uint8 *pubData, uint32 cubData, const uint8 *pubKey, uint32 cubKey, SHA256Digest_t *pOutputDigest ) { AssertMsg( false, "GenerateHMAC256 not implemented on PS3" ); return false; } - static bool BGzipBuffer( const uint8 *pubData, uint32 cubData, CCryptoOutBuffer &bufOutput ); - static bool BGunzipBuffer( const uint8 *pubData, uint32 cubData, CCryptoOutBuffer &bufOutput ); - -#ifdef DBGFLAG_VALIDATE - static void ValidateStatics( CValidator &validator, const char *pchName ); -#endif -}; - - -#endif //!_PS3 - - -class CSimpleBitString; - -//----------------------------------------------------------------------------- -// Purpose: Implement hex encoding / decoding using a custom lookup table. -// This is a class because the decoding is done via a generated -// reverse-lookup table, and to save time it's best to just create -// that table once. -//----------------------------------------------------------------------------- -class CCustomHexEncoder -{ -public: - CCustomHexEncoder( const char *pchEncodingTable ); - ~CCustomHexEncoder(); - - bool Encode( const uint8 *pubData, const uint32 cubData, char *pchEncodedData, uint32 cchEncodedData ); - bool Decode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData ); - -private: - bool m_bValidEncoding; - uint8 m_rgubEncodingTable[16]; - int m_rgnDecodingTable[256]; -}; - -//----------------------------------------------------------------------------- -// Purpose: Implement base32 encoding / decoding using a custom lookup table. -// This is a class because the decoding is done via a generated -// reverse-lookup table, and to save time it's best to just create -// that table once. -//----------------------------------------------------------------------------- -class CCustomBase32Encoder -{ -public: - CCustomBase32Encoder( const char *pchEncodingTable ); - ~CCustomBase32Encoder(); - - bool Encode( const uint8 *pubData, const uint32 cubData, char *pchEncodedData, uint32 cchEncodedData ); - bool Decode( const char *pchData, uint8 *pubDecodedData, uint32 *pcubDecodedData ); - - bool Encode( CSimpleBitString *pBitStringData, char *pchEncodedData, uint32 cchEncodedData ); - bool Decode( const char *pchData, CSimpleBitString *pBitStringDecodedData ); - -private: - bool m_bValidEncoding; - uint8 m_rgubEncodingTable[32]; - int m_rgnDecodingTable[256]; -}; - -#endif // CRYPTO_H diff --git a/engine/engine.vpc b/engine/engine.vpc index 70bbfd1e..7d6eb143 100644 --- a/engine/engine.vpc +++ b/engine/engine.vpc @@ -1115,7 +1115,6 @@ $Project "engine" $ImpLib "$LIBCOMMON\curl" [$OSXALL] $Libexternal "libz" - $Libexternal "$SRCDIR\lib\common\$(CRYPTOPPDIR)\libcrypto" [$LINUXALL&&!$DEDICATED] // Link with the google profiler. // http://code.google.com/p/gperftools/wiki/GooglePerformanceTools diff --git a/external/crypto++-5.6.3/3way.cpp b/external/crypto++-5.6.3/3way.cpp deleted file mode 100644 index 066ab330..00000000 --- a/external/crypto++-5.6.3/3way.cpp +++ /dev/null @@ -1,143 +0,0 @@ -// 3way.cpp - modifed by Wei Dai from Joan Daemen's 3way.c -// The original code and all modifications are in the public domain. - -#include "pch.h" -#include "3way.h" -#include "misc.h" - -NAMESPACE_BEGIN(CryptoPP) - -#if !defined(NDEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) -void ThreeWay_TestInstantiations() -{ - ThreeWay::Encryption x1; - ThreeWay::Decryption x2; -} -#endif - -static const word32 START_E = 0x0b0b; // round constant of first encryption round -static const word32 START_D = 0xb1b1; // round constant of first decryption round -#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562 -static const word32 RC_MODULUS = 0x11011; -#endif - -static inline word32 reverseBits(word32 a) -{ - a = ((a & 0xAAAAAAAA) >> 1) | ((a & 0x55555555) << 1); - a = ((a & 0xCCCCCCCC) >> 2) | ((a & 0x33333333) << 2); - return ((a & 0xF0F0F0F0) >> 4) | ((a & 0x0F0F0F0F) << 4); -} - -#define mu(a0, a1, a2) \ -{ \ - a1 = reverseBits(a1); \ - word32 t = reverseBits(a0); \ - a0 = reverseBits(a2); \ - a2 = t; \ -} - -#define pi_gamma_pi(a0, a1, a2) \ -{ \ - word32 b0, b2; \ - b2 = rotlFixed(a2, 1U); \ - b0 = rotlFixed(a0, 22U); \ - a0 = rotlFixed(b0 ^ (a1|(~b2)), 1U); \ - a2 = rotlFixed(b2 ^ (b0|(~a1)), 22U);\ - a1 ^= (b2|(~b0)); \ -} - -// thanks to Paulo Barreto for this optimized theta() -#define theta(a0, a1, a2) \ -{ \ - word32 b0, b1, c; \ - c = a0 ^ a1 ^ a2; \ - c = rotlFixed(c, 16U) ^ rotlFixed(c, 8U); \ - b0 = (a0 << 24) ^ (a2 >> 8) ^ (a1 << 8) ^ (a0 >> 24); \ - b1 = (a1 << 24) ^ (a0 >> 8) ^ (a2 << 8) ^ (a1 >> 24); \ - a0 ^= c ^ b0; \ - a1 ^= c ^ b1; \ - a2 ^= c ^ (b0 >> 16) ^ (b1 << 16); \ -} - -#define rho(a0, a1, a2) \ -{ \ - theta(a0, a1, a2); \ - pi_gamma_pi(a0, a1, a2); \ -} - -void ThreeWay::Base::UncheckedSetKey(const byte *uk, unsigned int length, const NameValuePairs ¶ms) -{ - AssertValidKeyLength(length); - - m_rounds = GetRoundsAndThrowIfInvalid(params, this); - - for (unsigned int i=0; i<3; i++) - m_k[i] = (word32)uk[4*i+3] | ((word32)uk[4*i+2]<<8) | ((word32)uk[4*i+1]<<16) | ((word32)uk[4*i]<<24); - - if (!IsForwardTransformation()) - { - theta(m_k[0], m_k[1], m_k[2]); - mu(m_k[0], m_k[1], m_k[2]); - m_k[0] = ByteReverse(m_k[0]); - m_k[1] = ByteReverse(m_k[1]); - m_k[2] = ByteReverse(m_k[2]); - } -} - -void ThreeWay::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const -{ - typedef BlockGetAndPut Block; - - word32 a0, a1, a2; - Block::Get(inBlock)(a0)(a1)(a2); - - word32 rc = START_E; - - for(unsigned i=0; i Block; - - word32 a0, a1, a2; - Block::Get(inBlock)(a0)(a1)(a2); - - word32 rc = START_D; - - mu(a0, a1, a2); - for(unsigned i=0; i, public FixedKeyLength<12>, public VariableRounds<11> -{ - static const char *StaticAlgorithmName() {return "3-Way";} -}; - -// 3-Way - -//! \class ThreeWay -//! \brief Provides 3-Way encryption and decryption -class ThreeWay : public ThreeWay_Info, public BlockCipherDocumentation -{ - //! \class Base - //! \brief Class specific implementation and overrides used to operate the cipher. - //! \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions - class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl - { - public: - void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); - - protected: - unsigned int m_rounds; - FixedSizeSecBlock m_k; - }; - - //! \class Enc - //! \brief Class specific methods used to operate the cipher in the forward direction. - //! \details Implementations and overrides in \p Enc apply to \p ENCRYPTION. - class CRYPTOPP_NO_VTABLE Enc : public Base - { - public: - void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; - }; - - //! \class Dec - //! \brief Class specific methods used to operate the cipher in the reverse direction. - //! \details Implementations and overrides in \p Dec apply to \p DECRYPTION. - class CRYPTOPP_NO_VTABLE Dec : public Base - { - public: - void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; - }; - -public: - typedef BlockCipherFinal Encryption; - typedef BlockCipherFinal Decryption; -}; - -typedef ThreeWay::Encryption ThreeWayEncryption; -typedef ThreeWay::Decryption ThreeWayDecryption; - -NAMESPACE_END - -#endif diff --git a/external/crypto++-5.6.3/Doxyfile b/external/crypto++-5.6.3/Doxyfile deleted file mode 100644 index da7bbf4c..00000000 --- a/external/crypto++-5.6.3/Doxyfile +++ /dev/null @@ -1,2373 +0,0 @@ -# Doxyfile 1.8.9 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a double hash (##) is considered a comment and is placed in -# front of the TAG it is preceding. -# -# All text after a single hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists, items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (\" \"). -# -# The file can be upgraded to the latest version of Doxygen with `doxygen -u