/*++ Copyright (c) 1994-1998 Microsoft Corporation Module Name: encrypt.c Abstract: Contains functions that encrypt and decrypt data sent accross client and server. Author: Madan Appiah (madana) 24-Jan-1998 Environment: User Mode - Win32 Revision History: --*/ #include VOID GenerateMACSignature( LPBYTE pbData, DWORD dwDataLen, LPBYTE pbMACSaltKey, DWORD dwMACSaltKey, LPBYTE pbSignature, BOOL fIncludeEncryptionCount, DWORD dwEncryptionCount ) /*++ Routine Description: This function generates a message authentication signature. Arguments: pbData - pointer to a data buffer. dwDataLen - length of the above data. pbMACSaltKey - pointer to a MAC salt key. pbSignature - pointer a signature buffer. fIncludeEncryptionCount - TRUE to salt in the encryption count dwEncryptionCount - total encryption count Return Value: None. --*/ { A_SHA_CTX SHAHash; MD5_CTX MD5Hash; BYTE abSHADigest[A_SHA_DIGEST_LEN]; // // make a SHA(MACSalt + g_abPad1 + Length + Content) hash. // A_SHAInit(&SHAHash); A_SHAUpdate(&SHAHash, pbMACSaltKey, dwMACSaltKey); A_SHAUpdate(&SHAHash, (unsigned char *)g_abPad1, 40); A_SHAUpdate(&SHAHash, (LPBYTE)&dwDataLen, sizeof(DWORD)); A_SHAUpdate(&SHAHash, pbData, dwDataLen); if (fIncludeEncryptionCount) { A_SHAUpdate(&SHAHash, (LPBYTE)&dwEncryptionCount, sizeof(DWORD)); } A_SHAFinal(&SHAHash, abSHADigest); // // make a MD5(MACSalt + g_abPad2 + SHAHash) hash. // MD5Init(&MD5Hash); MD5Update(&MD5Hash, pbMACSaltKey, dwMACSaltKey); MD5Update(&MD5Hash, g_abPad2, 48); MD5Update(&MD5Hash, abSHADigest, A_SHA_DIGEST_LEN); MD5Final(&MD5Hash); ASSERT( DATA_SIGNATURE_SIZE <= MD5DIGESTLEN ); memcpy(pbSignature, MD5Hash.digest, DATA_SIGNATURE_SIZE); return; } BOOL EncryptData( DWORD dwEncryptionLevel, LPBYTE pSessionKey, struct RC4_KEYSTRUCT FAR *prc4EncryptKey, DWORD dwKeyLength, LPBYTE pbData, DWORD dwDataLen, LPBYTE pbMACSaltKey, LPBYTE pbSignature, BOOL fSecureChecksum, DWORD dwEncryptionCount ) /*++ Routine Description: Encrypt the given data buffer in place. Arguments: dwEncryptionLevel - encryption level, used to select the encryption algorithm. pSessionKey - pointer to the session key. prc4EncryptKey - pointer to a RC4 key. dwKeyLength - length of the session key. pbData - pointer to the data buffer being encrypted, encrypted data is returned in the same buffer. dwDataLen - length of the data buffer. pbMACSaltKey - pointer to a message authentication key buffer. pbSignature - pointer to a signature buffer where the data signature is returned. fSecureChecksum - TRUE if the checksum is to be salted with the encryption count dwDecryptionCount - running counter of all encryptions Return Value: TRUE - if successfully encrypted the data. FALSE - otherwise. --*/ { // // generate the MAC signature first. // GenerateMACSignature ( pbData, dwDataLen, pbMACSaltKey, dwKeyLength, pbSignature, fSecureChecksum, dwEncryptionCount ); // // encrypt data. // // // use microsoft version of rc4 algorithm (super fast!) for level 1 and // level 2 encryption, for level 3 use RSA rc4 algorithm. // if( dwEncryptionLevel <= 2 ) { msrc4(prc4EncryptKey, (UINT)dwDataLen, pbData ); } else { rc4(prc4EncryptKey, (UINT)dwDataLen, pbData ); } return( TRUE ); } BOOL DecryptData( DWORD dwEncryptionLevel, LPBYTE pSessionKey, struct RC4_KEYSTRUCT FAR *prc4DecryptKey, DWORD dwKeyLength, LPBYTE pbData, DWORD dwDataLen, LPBYTE pbMACSaltKey, LPBYTE pbSignature, BOOL fSecureChecksum, DWORD dwDecryptionCount ) /*++ Routine Description: Decrypt the given data buffer in place. Arguments: dwEncryptionLevel - encryption level, used to select the encryption algorithm. pSessionKey - pointer to the session key. prc4DecryptKey - pointer to a RC4 key. dwKeyLength - length of the session key. pbData - pointer to the data buffer being decrypted, decrypted data is returned in the same buffer. dwDataLen - length of the data buffer. pbMACSaltKey - pointer to a message authentication key buffer. pbSignature - pointer to a signature buffer where the data signature is returned. fSecureChecksum - TRUE if the checksum is to be salted with the encryption count dwDecryptionCount - running counter of all encryptions Return Value: TRUE - if successfully encrypted the data. FALSE - otherwise. --*/ { BYTE abSignature[DATA_SIGNATURE_SIZE]; // // decrypt data. // // // use microsoft version of rc4 algorithm (super fast!) for level 1 and // level 2 encryption, for level 3 use RSA rc4 algorithm. // if( dwEncryptionLevel <= 2 ) { msrc4(prc4DecryptKey, (UINT)dwDataLen, pbData ); } else { rc4(prc4DecryptKey, (UINT)dwDataLen, pbData ); } GenerateMACSignature ( pbData, dwDataLen, pbMACSaltKey, dwKeyLength, (LPBYTE)abSignature, fSecureChecksum, dwDecryptionCount ); // // check to see the sigature match. // if( memcmp( (LPBYTE)abSignature, pbSignature, sizeof(abSignature) ) ) { return( FALSE ); } return( TRUE ); } #ifdef USE_MSRC4 VOID msrc4_key( struct RC4_KEYSTRUCT FAR *pKS, DWORD dwLen, LPBYTE pbKey ) /*++ Routine Description: Generate the key control structure. Key can be any size. Assumes pKS is locked against simultaneous use. Arguments: pKS - pointer to a KEYSTRUCT structure that will be initialized. dwLen - Size of the key, in bytes. pbKey - Pointer to the key. Return Value: NONE. --*/ { #define SWAP(_x_, _y_) { BYTE _t_; _t_ = (_x_); (_x_) = (_y_); (_y_) = _t_; } BYTE index1; BYTE index2; UINT counter; BYTE bLen; ASSERT( dwLen < 256 ); bLen = ( dwLen >= 256 ) ? 255 : (BYTE)dwLen; for (counter = 0; counter < 256; counter++) { pKS->S[counter] = (BYTE) counter; } pKS->i = 0; pKS->j = 0; index1 = 0; index2 = 0; for (counter = 0; counter < 256; counter++) { index2 = (pbKey[index1] + pKS->S[counter] + index2); SWAP(pKS->S[counter], pKS->S[index2]); index1 = (index1 + 1) % bLen; } } VOID msrc4( struct RC4_KEYSTRUCT FAR *pKS, DWORD dwLen, LPBYTE pbuf ) /*++ Routine Description: Performs the actual encryption or decryption. Assumes pKS is locked against simultaneous use. Arguments: pKS - Pointer to the KEYSTRUCT created using msrc4_key(). dwLen - Size of buffer, in bytes. pbuf - Buffer to be encrypted. Return Value: NONE. --*/ { BYTE FAR *const s = pKS->S; BYTE a, b; while(dwLen--) { a = s[++(pKS->i)]; pKS->j += a; b = s[pKS->j]; s[pKS->j] = a; a += b; s[pKS->i] = b; *pbuf++ ^= s[a]; } } #endif // USE_MSRC4 /****************************************************************************/ /* PortableEncode and PortableEncode50 are functions used to */ /* encrypt/decrypt data on different machines. */ /****************************************************************************/ #define PE_RANDOM_CONSTANT "d72775a4-c832-11d1-9685-00c04fb15601" void PortableEncode(LPBYTE pbData, DWORD dwDataLen) { A_SHA_CTX SHAHash; BYTE abSHADigest[A_SHA_DIGEST_LEN]; struct RC4_KEYSTRUCT rc4Key; A_SHAInit(&SHAHash); A_SHAUpdate(&SHAHash, (LPBYTE)PE_RANDOM_CONSTANT, sizeof(PE_RANDOM_CONSTANT)); A_SHAFinal(&SHAHash, abSHADigest); msrc4_key(&rc4Key, MAX_SESSION_KEY_SIZE, abSHADigest); msrc4(&rc4Key, (UINT)dwDataLen, pbData); } void PortableEncode50(LPBYTE pbData, DWORD dwDataLen, LPBYTE pbSalt, DWORD dwSaltLength) { A_SHA_CTX SHAHash; BYTE abSHADigest[A_SHA_DIGEST_LEN]; DWORD dw; struct RC4_KEYSTRUCT rc4Key; A_SHAInit(&SHAHash); A_SHAUpdate(&SHAHash, (LPBYTE)PE_RANDOM_CONSTANT, sizeof(PE_RANDOM_CONSTANT)); A_SHAFinal(&SHAHash, abSHADigest); for (dw = 0; dw < 256; dw++) { A_SHAInit(&SHAHash); A_SHAUpdate(&SHAHash, pbSalt, dwSaltLength); A_SHAUpdate(&SHAHash, abSHADigest, A_SHA_DIGEST_LEN); A_SHAFinal(&SHAHash, abSHADigest); } msrc4_key(&rc4Key, MAX_SESSION_KEY_SIZE, abSHADigest); msrc4(&rc4Key, (UINT)dwDataLen, pbData); } #undef PE_RANDOM_CONSTANT