Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

328 lines
7.3 KiB

// CoCrypt.cpp: implementation of the CCoCrypt class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CoCrypt.h"
#include "hmac.h"
#include "BstrDebug.h"
#include <winsock2.h> // ntohl, htonl
#include <time.h>
#include <crypt.h>
#define PASSPORT_MAC_LEN 10
BOOL
GenTextIV(unsigned char *pIV) // makes the assumption that IV is 8 bytes long
// since the below code uses 3DES this is OK for now
{
int i;
BOOL fResult;
// generate a random IV
fResult = RtlGenRandom(pIV, 8);
if (!fResult)
return FALSE;
// castrate the random IV into base 64 characters (makes the IV only have
// ~48 bits of entropy instead of 64 but that should be fine
for (i = 0; i < 8; i++)
{
// mod the character to make sure its less than 62
pIV[i] = pIV[i] % 62;
// add the appropriate character value to make it a base 64 character
if (pIV[i] <= 9)
pIV[i] = pIV[i] + '0';
else if (pIV[i] <= 35)
pIV[i] = pIV[i] + 'a' - 10 ;
else
pIV[i] = pIV[i] + 'A' - 36 ;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CBinHex CCoCrypt::m_binhex;
CCoCrypt::CCoCrypt() : m_ok(FALSE)
{
}
CCoCrypt::~CCoCrypt()
{
}
BOOL CCoCrypt::Decrypt(LPWSTR rawData,
UINT dataSize,
BSTR *ppUnencrypted)
{
unsigned char *pb = NULL;
unsigned char ivec[9];
ULONG lSize, i;
unsigned char pad;
unsigned char hmac[10];
HRESULT hr;
BOOL fResult = FALSE;
*ppUnencrypted = NULL;
// must be kv + ivec + bh(hmac) long at LEAST
if (sizeof(hmac) + sizeof(ivec) + 4 > dataSize)
{
goto Cleanup;
}
lSize = dataSize - sizeof(WCHAR);
// allocate a buffer for the resulting data
pb = new unsigned char[lSize];
if (NULL == pb)
{
goto Cleanup;
}
// decode from base 64
hr = m_binhex.PartFromWideBase64(rawData + 1 + 9, pb, &lSize);
if (S_OK != hr)
{
goto Cleanup;
}
for (i = 0; i < 9; i++)
ivec[i] = (unsigned char) rawData[i + 1];
pad = ivec[8];
// Now lsize holds the # of bytes outputted, which after hmac should be %8=0
if ((lSize - sizeof(hmac)) % 8 || lSize <= sizeof(hmac))
{
goto Cleanup;
}
for (i = 0; i < lSize - sizeof(hmac); i+=8)
{
CBC(tripledes,
DES_BLOCKLEN,
pb + sizeof(hmac) + i,
pb + sizeof(hmac) + i,
&ks,
DECRYPT,
(BYTE*)ivec);
}
// Padding must be >0 and <8
//if (rawData[8]-65 > 7 || rawData[8] < 65)
if((pad - 65) > 7 || pad < 65)
{
goto Cleanup;
}
// Now check hmac
hmac_sha(m_keyMaterial,
DES3_KEYSIZE,
pb + sizeof(hmac),
lSize - sizeof(hmac),
hmac, sizeof(hmac));
if (memcmp(hmac, pb, sizeof(hmac)) != 0)
{
goto Cleanup;
}
// do a BSTR type allocation to accomodate calling code
*ppUnencrypted = ALLOC_AND_GIVEAWAY_BSTR_BYTE_LEN((char*)(pb+sizeof(hmac)), lSize - sizeof(hmac) - (pad - 65));
if (NULL == *ppUnencrypted)
{
goto Cleanup;
}
fResult = TRUE;
Cleanup:
if (pb)
{
delete[] pb;
}
return fResult;
}
BOOL CCoCrypt::Encrypt(int keyVersion,
LPSTR rawData,
UINT dataSize,
BSTR *ppEncrypted)
{
int cbPadding = 0;
char ivec[9];
BOOL fResult;
*ppEncrypted = NULL;
// Find out how big the encrypted blob needs to be:
// The final pack is:
// <KeyVersion><IVEC><PADCOUNT>BINHEX(HMAC+3DES(DATA+PAD))
//
// So, we're concerned with the size of HMAC+3DES(DATA+PAD)
// because BinHex will handle the rest
if (dataSize % DES_BLOCKLEN)
{
cbPadding = (DES_BLOCKLEN - (dataSize % DES_BLOCKLEN)); // + PAD, if necessary
}
// gen the IV
fResult = GenTextIV((unsigned char*)ivec);
if (!fResult)
{
goto Cleanup;
}
encrypt(ivec, cbPadding, keyVersion, rawData, dataSize, ppEncrypted);
fResult = TRUE;
Cleanup:
return fResult;
}
BOOL CCoCrypt::encrypt(char ivec[9],
int cbPadding,
int keyVersion,
LPSTR rawData,
UINT cbData,
BSTR *ppEncrypted)
{
unsigned char *pb = NULL;
char ivec2[8];
HRESULT hr;
BOOL fResult = FALSE;
// Compute HMAC+3DES(DATA+PAD)
ivec[8] = (char) cbPadding + 65;
// allocate a buffer for the resulting data
// length of data + length of padding + size of HMAC + size of IV
pb = new unsigned char[cbData + cbPadding + 10 + 8];
if (NULL == pb)
{
goto Cleanup;
}
memcpy(ivec2, ivec, DES_BLOCKLEN);
memcpy(pb + PASSPORT_MAC_LEN, rawData, cbData); // copy data after the HMAC
//randomize padding
fResult = RtlGenRandom(pb + PASSPORT_MAC_LEN + cbData, cbPadding);
if (!fResult)
{
fResult = FALSE;
goto Cleanup;
}
// Compute HMAC
hmac_sha(m_keyMaterial, DES3_KEYSIZE, pb + PASSPORT_MAC_LEN, cbData + cbPadding, pb, PASSPORT_MAC_LEN);
for (int i = 0; i < (int)cbData + cbPadding; i+=8)
{
CBC(tripledes, DES_BLOCKLEN, pb + PASSPORT_MAC_LEN + i, pb + PASSPORT_MAC_LEN + i, &ks, ENCRYPT, (BYTE*)ivec2);
}
// Now we've got a buffer of blockSize ready to be binhexed, and have the key
// version prepended
keyVersion = keyVersion % 36; // 0 - 9 & A - Z
char v = (char) ((keyVersion > 9) ? (55+keyVersion) : (48+keyVersion));
hr = m_binhex.ToBase64(pb, cbData + cbPadding + PASSPORT_MAC_LEN, v, ivec, ppEncrypted);
if (S_OK != hr)
{
fResult = FALSE;
goto Cleanup;
}
fResult = TRUE;
Cleanup:
if (NULL != pb)
{
delete[] pb;
}
return fResult;
}
void CCoCrypt::setKeyMaterial(BSTR newVal)
{
if (SysStringByteLen(newVal) != 24)
{
m_ok = FALSE;
return;
}
memcpy(m_keyMaterial, (LPSTR)newVal, 24);
tripledes3key(&ks, (BYTE*) m_keyMaterial);
m_ok = TRUE;
}
unsigned char *CCoCrypt::getKeyMaterial(DWORD *pdwLen)
{
if (pdwLen)
*pdwLen = 24;
return m_keyMaterial;
}
int CCoCrypt::getKeyVersion(BSTR encrypted)
{
char c = (char) encrypted[0];
if (isdigit(c))
return (c-48);
if(isalpha(c)) // Key version can be 0 - 9 & A - Z (36)
{
if(c > 'Z') //convert to uppert case w/o using rt lib.
c -= ('a' - 'A');
return c - 65 + 10;
//return (toupper(c)-65+10);
}
return -1;
}
int CCoCrypt::getKeyVersion(BYTE *encrypted)
{
char c = (char) encrypted[0];
if (isdigit(c))
return (c-48);
if(isalpha(c)) // Key version can be 0 - 9 & A - Z (36)
{
if(c > 'Z') //convert to uppert case w/o using rt lib.
c -= ('a' - 'A');
return c - 65 + 10;
//return (toupper(c)-65+10);
}
return -1;
}
void CCoCrypt::setWideMaterial(BSTR kvalue)
{
m_bstrWideMaterial = kvalue;
}
BSTR CCoCrypt::getWideMaterial()
{
return m_bstrWideMaterial;
}