#include
#include
#include
BOOL DES(__in const BYTE* pbKey,
__in DWORD cbKeyLen,
__in const BYTE* pbData,
__in DWORD cbDataLen,
__out BYTE* pbBuf,
__inout DWORD* pcbBufLen,
__in BOOL bIsDecrypt = FALSE
)
/*
DES加密、解密函数,使用PKCS 5 padding,CBC模式
参数:
pbKey DES密钥
cbKeyLen pbKey字节长度
pbData 要加密、解密的数据
cbDataLen pbData字节长度
pbBuf 输出缓冲区,输出加密后、解密后的数据,可以为NULL
pcbBufLen pbBuf字节长度
当pbBuf不为NULL时,返回实际复制到pbBuf的字节长度
当pbBuf为NULL时,返回需要的pbBuf字节长度
bIsDecrypt 为TRUE时执行解密操作,否则执行加密操作
返回:
成功返回TRUE,否则返回FALSE
*/
{
struct
{
BLOBHEADER hdr;
DWORD cbKeySize;
BYTE rgbKeyData[8];
} keyBlob; //结构参考MSDN - CryptImportKey
keyBlob.hdr.bType = PLAINTEXTKEYBLOB;
keyBlob.hdr.bVersion = CUR_BLOB_VERSION;
keyBlob.hdr.reserved = 0;
keyBlob.hdr.aiKeyAlg = CALG_DES;
keyBlob.cbKeySize = 8;
ZeroMemory(keyBlob.rgbKeyData, 8);
CopyMemory(keyBlob.rgbKeyData, pbKey, cbKeyLen > 8 ? 8 : cbKeyLen);
HCRYPTPROV hProv;
if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, 0))
return FALSE;
HCRYPTKEY hKey;
if (!CryptImportKey(hProv, (BYTE*)&keyBlob, sizeof(keyBlob), 0, 0, &hKey))
{
CryptReleaseContext(hProv, 0);
return FALSE;
}
BOOL bRet;
BYTE pbBlock[16];
DWORD dwBlock, dwOut = 0;
BOOL bEOF;
for (DWORD i = 0; i < cbDataLen; i += 8)
{
bEOF = cbDataLen - i <= 8; //是否为最后一组
dwBlock = bEOF ? cbDataLen - i : 8;
CopyMemory(pbBlock, pbData + i, dwBlock); //分组加密、解密,每组8字节
if (bIsDecrypt)
bRet = CryptDecrypt(hKey, NULL, bEOF, 0, pbBlock, &dwBlock);
else
bRet = CryptEncrypt(hKey, NULL, bEOF, 0, pbBlock, &dwBlock, sizeof(pbBlock));
if (!bRet)
break;
if (pbBuf)
{
if (dwOut + dwBlock > *pcbBufLen)
{
bRet = FALSE;
break;
}
else
{
CopyMemory(pbBuf + dwOut, pbBlock, dwBlock);
dwOut += dwBlock;
}
}
else //当pbBuf为NULL时,仅计算需要多大的pbBuf
dwOut += dwBlock;
}
*pcbBufLen = dwOut;
CryptDestroyKey(hKey);
CryptReleaseContext(hProv, 0);
return bRet;
}
int _tmain()
{
BYTE pbKey[] = "1204",
pbPlain[] = "StarsunYzL";
DWORD dwLen;
DES(pbKey, 4, pbPlain, 10, NULL, &dwLen); //计算需要多大的输出缓冲区
BYTE* pbCipher = new BYTE[dwLen];
DES(pbKey, 4, pbPlain, 10, pbCipher, &dwLen); //加密
for (size_t i = 0; i != dwLen; ++i)
_tprintf(_T("%02X"), pbCipher[i]);
_tprintf(_T("\r\n"));
ZeroMemory(pbPlain, sizeof(pbPlain));
DES(pbKey, 4, pbCipher, dwLen, pbPlain, &dwLen, TRUE); //解密
delete [] pbCipher;
for (size_t i = 0; i != dwLen; ++i)
_tprintf(_T("%c"), pbPlain[i]);
_tprintf(_T("\r\n"));
return 0;
}
测试:
密钥:1204
数据:StarsunYzL
加密结果:CA3C24E48DD8AA551E98F3A989D38A49
注意这段代码使用的是PKCS 5 padding,而网上的一些算法测试工具使用的是ZERO padding,所以得到的结果不一定一样,微软提供的CSPs不支持ZERO padding,要使用ZERO padding的话必须自己填0把最后一组数据补齐8字节后再加密,并且仅取加密结果的前8字节数据,因为后8字节是多出来的padding