434 lines
9 KiB
C
434 lines
9 KiB
C
/*++
|
|
|
|
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 <seccom.h>
|
|
|
|
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
|
|
|