用CryptoAPI实现DES加密解密

#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


你可能感兴趣的:(加解密)