如题,用Windows的CryptoAPI计算MD5我会,但是怎样用CryptoAPI实现DES加密?
自己搞了半天,程序编译没问题,加密得的结果虽然是8字节,但是不对。
对照了MSDN也没看出哪不对,百度、谷歌更是搜不到,有搞过的人能不能指点一下,谢谢!#include <iostream>
#include <Windows.h>
#include <tchar.h>#pragma comment(lib, "Crypt32.lib")int _tmain(int argc, _TCHAR* argv[])
{
BYTE pKey[] = "123";
//BYTE pIV[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
BYTE pData[256] = "abc";
DWORD dwDataLen = 3; HCRYPTPROV hProv;
if (CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
{
HCRYPTHASH hHash;
if (CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
{
CryptHashData(hHash, pKey, sizeof(pKey), 0);
HCRYPTKEY hKey;
if (CryptDeriveKey(hProv, CALG_DES, hHash, 0x00380000, &hKey))
{
//CryptSetKeyParam(hKey, KP_IV, pIV, 0);
CryptEncrypt(hKey, 0, TRUE, 0, pData, &dwDataLen, _countof(pData));
TCHAR szBase64[256];
DWORD dwBase64Len = sizeof(szBase64) / sizeof(szBase64[0]);
CryptBinaryToString(pData, dwDataLen, CRYPT_STRING_BASE64, szBase64, &dwBase64Len);
_tprintf(szBase64);
CryptDestroyKey(hKey);
}
CryptDestroyHash(hHash);
}
CryptReleaseContext(hProv, 0);
}
return 0;
}

解决方案 »

  1.   


    GBool KeyEncryptionAlgorithm::encrypt( Guchar *pdata, Gulong *dataLen, Gulong bufLen, Guchar* key, Gulong keyLen )
    {
    #ifdef _WIN32
    HCRYPTPROV hCryptProv = NULL;
    HCRYPTKEY hKey = NULL;
    GBool ok = gFalse;
    Gulong errcode; if(!CryptAcquireContext(&hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
    {
    return gFalse;
    }
    if (Algid == CALG_RSA_KEYX)
    {
    struct {
    PUBLICKEYSTRUC hdr;
    RSAPUBKEY rsapubkey;
    Guchar modulus[130];
    } key_blob; key_blob.hdr.bType = PUBLICKEYBLOB;
    key_blob.hdr.bVersion = CUR_BLOB_VERSION;
    key_blob.hdr.aiKeyAlg = Algid;
    key_blob.hdr.reserved = 0;
    key_blob.rsapubkey.bitlen = 1024;
    key_blob.rsapubkey.magic = 0x31415352;
    Guchar *pubkey = key;
    if (!IsSequence(*pubkey++))
    goto err;
    Gulong len1;
    pubkey = getLength(pubkey, &len1);
    pubkey = getLittleEndianOctetInteger(pubkey, key_blob.modulus, &len1);
    getInteger(pubkey, &key_blob.rsapubkey.pubexp);

    if (!CryptImportKey(hCryptProv, (Guchar*)&key_blob, sizeof(key_blob), NULL, 0, &hKey))
    {
    errcode = GetLastError();
    goto err;
    }
    }
    else
    {
    struct {
    BLOBHEADER hdr;
    Gulong len;
    BYTE key[32];
    } key_blob; key_blob.hdr.bType = PLAINTEXTKEYBLOB;
    key_blob.hdr.bVersion = CUR_BLOB_VERSION;
    key_blob.hdr.aiKeyAlg = Algid;
    key_blob.hdr.reserved = 0;
    key_blob.len = keyLen;
    memcpy(key_blob.key, key, keyLen); if (!CryptImportKey(hCryptProv, (BYTE*)&key_blob, sizeof(key_blob), NULL, 0, &hKey))
    {
    errcode = GetLastError();
    goto err;
    }
    } if (Params)
    {
    if (Algid == CALG_3DES)
    {
    if (!CryptSetKeyParam(hKey, KP_IV, Params, 0))
    {
    errcode = GetLastError();
    }
    }
    }
    if(!CryptEncrypt(hKey, NULL, gTrue, 0, pdata, dataLen, bufLen))

    errcode = GetLastError();
    goto err;
    }
    ok = gTrue;
    err:
    if(hKey)
    CryptDestroyKey(hKey);
    if(hCryptProv)
    CryptReleaseContext(hCryptProv, 0);
    return ok;
    #else
    return gFalse;
    #endif
    }
      

  2.   

    其中,Params可以是个固定值"\x0d\x3a\x62\xdd\xfe\xcb\x2b\xba"
      

  3.   


    GBool KeyEncryptionAlgorithm::decrypt( Guchar *pdata, Gulong *dataLen, Guchar* key, Gulong keyLen)
    {
    GBool ok = gFalse;
    #ifdef _WIN32
    HCRYPTPROV hCryptProv = NULL;
    HCRYPTKEY hKey = NULL;

    Gulong errcode; struct {
    BLOBHEADER hdr;
    Gulong len;
    BYTE key[32];
    } key_blob; if(!CryptAcquireContext(&hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
    {
    return gFalse;
    }

    key_blob.hdr.bType = PLAINTEXTKEYBLOB;
    key_blob.hdr.bVersion = CUR_BLOB_VERSION;
    key_blob.hdr.aiKeyAlg = Algid;
    key_blob.hdr.reserved = 0;
    key_blob.len = keyLen;
    memcpy(key_blob.key, key, keyLen);
    if (!CryptImportKey(hCryptProv, (BYTE*)&key_blob, sizeof(key_blob), NULL, 0, &hKey))
    {
    errcode = GetLastError();
    goto err;
    } if (Params)
    {
    if (Algid == CALG_3DES)
    {
    if (!CryptSetKeyParam(hKey, KP_IV, Params, 0))
    {
    errcode = GetLastError();
    }
    }
    }
    // Decrypt data. 
    if(!CryptDecrypt(hKey, NULL, gTrue, 0, pdata, dataLen))

    errcode = GetLastError();
    goto err;
    }
    ok = gTrue;
    err:
    if(hKey)
    CryptDestroyKey(hKey);
    if(hCryptProv)
    CryptReleaseContext(hCryptProv, 0);

    #else

    #endif
    return ok;
    }
      

  4.   

    先谢谢提示,原来plain text key用的是CryptImportKey
    但是我的代码好像还是得不到正确的结果,能否麻烦帮忙调试一下是哪的问题,再次谢谢
    #include <iostream>
    #include <Windows.h>
    #include <tchar.h>#pragma comment(lib, "Crypt32.lib")int _tmain(int argc, _TCHAR* argv[])
    {
    struct keyBlob
    {
    BLOBHEADER hdr;
    DWORD cbKeySize;
    BYTE rgbKeyData[8];
    } keyBlob; keyBlob.hdr.bType = PLAINTEXTKEYBLOB;
    keyBlob.hdr.bVersion = CUR_BLOB_VERSION;
    keyBlob.hdr.reserved = 0;
    keyBlob.hdr.aiKeyAlg = CALG_DES;
    keyBlob.cbKeySize = 8;
    BYTE Key[8] = {0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31};
    CopyMemory(keyBlob.rgbKeyData, Key, keyBlob.cbKeySize); //BYTE pIV[8] = {0x0d, 0x3a, 0x62, 0xdd, 0xfe, 0xcb, 0x2b, 0xba}; BYTE pData[256] = {0x31};
    DWORD dwDataLen = 1; HCRYPTPROV hProv;
    if (CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
    {
    HCRYPTKEY hKey;
    if (CryptImportKey(hProv, (BYTE*)(&keyBlob), sizeof(keyBlob), 0, CRYPT_EXPORTABLE, &hKey))
    {
    //CryptSetKeyParam(hKey, KP_IV, pIV, 0);
    CryptEncrypt(hKey, 0, TRUE, 0, pData, &dwDataLen, _countof(pData));
    for (int i = 0; i != dwDataLen; ++i)
    _tprintf(_T("%02x "), pData[i]);
    _tprintf(_T("\r\n"));
    CryptDestroyKey(hKey);
    }
    CryptReleaseContext(hProv, 0);
    }
    return 0;
    }
      

  5.   

    意思是我想用密钥"11111111"来加密数据"1"(这里的1都是字符串,也就是0x31),我用其它两个工具算得出的正确结果是cf 60 cf ac ab 67 bb a8,
    但是我4楼帖的程序运行输出的结果却是5c a2 98 19 f0 28 89 40,当然我也试过用密钥11111111来加密数据1(这里的1都直接是数字,也就是0x01,和前面举例的字符串不一样),结果一样不正确。
    我的代码哪里有问题?或者能否帖个完整的用CryptoAPI实现DES加密的代码。谢谢了!
      

  6.   

    其它两个工具是什么,有可能是KP_IV不一样引起的吧。
      

  7.   


    一个是PYG密码学综合工具,另一个是Win-Tool之编码转换工具
    这两个工具都只用填写密钥和要加密的数据,并不用填写IV向量,但加密出来的结果却是一样的,难道这两个工具里IV是一样的?
    是不是标准的DES规定有一个固定的IV值?但是我查了些DES的算法描述,并没有看到有关IV的说明
      

  8.   

    这两个工具应该是对数据按8字节补齐了,而且结果只是8字节长的话,说明不是cbc模式
      

  9.   


    原来是这样,我以为CryptoAPI会自动补齐后再计算。我对算法不甚了解,感谢你的帮助,差不多可以结贴了,还有最后一个问题,
    就是你说的加密结果的长度问题,用密钥“11111111”加密数据“11111111”,上面两个程序得到的结果是8字节的65 5e a6 28 cf 62 58 5f,
    但是CryptoAPI得到的却是16字节的65 5e a6 28 cf 62 58 5f 04 5b e2 ac fe 00 f0 c1,前8字节是一样的,但是多出了8字节,尝试了所有加密模式,都是16字节,
    这是为何呢?那我该怎么确定最终的加密结果是多少字节?
    int _tmain(int argc, _TCHAR* argv[])
    {
    struct
    {
    BLOBHEADER hdr;
    DWORD cbKeySize;
    BYTE rgbKeyData[8];
    } keyBlob; keyBlob.hdr.bType = PLAINTEXTKEYBLOB;
    keyBlob.hdr.bVersion = CUR_BLOB_VERSION;
    keyBlob.hdr.reserved = 0;
    keyBlob.hdr.aiKeyAlg = CALG_DES;
    keyBlob.cbKeySize = 8;
    BYTE Key[8] = {0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31};
    CopyMemory(keyBlob.rgbKeyData, Key, keyBlob.cbKeySize); BYTE pData[256] = {0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31};
    DWORD dwDataLen = 8; HCRYPTPROV hProv;
    if (CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
    {
    HCRYPTKEY hKey;
    if (CryptImportKey(hProv, (BYTE*)(&keyBlob), sizeof(keyBlob), 0, 0, &hKey))
    {
    DWORD dwMode = CRYPT_MODE_CBC;
    CryptSetKeyParam(hKey, KP_MODE, (BYTE*)(&dwMode), 0);
    CryptEncrypt(hKey, 0, TRUE, 0, pData, &dwDataLen, _countof(pData));
    for (int i = 0; i != dwDataLen; ++i)
    _tprintf(_T("%02x "), pData[i]);
    _tprintf(_T("\r\n"));
    CryptDestroyKey(hKey);
    }
    CryptReleaseContext(hProv, 0);
    }
    return 0;
    }
      

  10.   

    cbc模式最后一个字节是padding的长度,如果数据刚好是完整的分组,则需要一个额外的分组来表示padding。
      

  11.   

    OK,问题完美解决,再次感谢cofanz!