如何导出使用 CryptoAPI 派生的 AES 密钥

rou*_*bic 5 c encryption cryptography aes cryptoapi

我想使用 Windows CryptoAPI 函数进行 AES 加密。

众所周知,API有很多功能可以创建、散列和更改输入的密钥;它派生出密钥,您就可以处理它。

我的问题是我想知道派生密钥是什么?

#include <Windows.h>
#include <stdio.h>

int main()
{
    HCRYPTPROV hProv = 0;
    HCRYPTKEY hKey = 0;
    HCRYPTHASH hHash = 0;
    DWORD dwCount = 5;
    BYTE  rgData[512] = {0x01, 0x02, 0x03, 0x04, 0x05};
    LPWSTR wszPassword = L"pass";
    DWORD cbPassword = (wcslen(wszPassword)+1)*sizeof(WCHAR);

    if(!CryptAcquireContext(
        &hProv, 
        NULL,  
        MS_ENH_RSA_AES_PROV, 
        PROV_RSA_AES, 
        CRYPT_VERIFYCONTEXT))
    {
        printf("Error %x during CryptAcquireContext!\n", GetLastError());
        goto Cleanup;
    }

    if(!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) 
    { 
        printf("Error %x during CryptCreateHash!\n", GetLastError());
        goto Cleanup;
    } 

    if(!CryptHashData(hHash, (PBYTE)wszPassword, cbPassword, 0)) 
    { 
        printf("Error %x during CryptHashData!\n", GetLastError());
        goto Cleanup;
    } 

    if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, CRYPT_EXPORTABLE, &hKey)) 
    { 
        printf("Error %x during CryptDeriveKey!\n", GetLastError());
        goto Cleanup;
    }

    for(DWORD i = 0; i < dwCount; i++)
    {
        printf("%d ",rgData[i]);
    }
    printf("\n");

    if (!CryptEncrypt(
        hKey,
        0,
        TRUE,
        0,
        rgData,
        &dwCount,
        sizeof(rgData))) 
    {
        printf("Error %x during CryptEncrypt!\n", GetLastError());
        goto Cleanup;
    }

    for(DWORD i = 0; i < dwCount; i++)
    {
        printf("%d ",rgData[i]);
    }
    printf("\n");

Cleanup:
    if(hKey) 
    {
        CryptDestroyKey(hKey);
    }
    if(hHash) 
    {
        CryptDestroyHash(hHash);
    }
    if(hProv) 
    {
        CryptReleaseContext(hProv, 0);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Maa*_*wes 2

编辑:如果密钥派生在软件中,那么软件性的答案可能会更好。所以这是一个更通用的答案,应该是首选。如果软件方法失败,您可以使用此重放方法。如果令牌不允许明文导出,则可能会出现这种情况。

一般来说,这些方法的创建方式使得检索结果秘密即使不是不可能,也是很困难的。不过,密钥的导出方法在API文档的备注部分CryptDeriveKey有描述。这样您就可以重播基础数据的创建过程。

该 API 没有描述使用 SHA-2 时会发生什么,但我认为它只是使用 SHA-256 结果的最左边位作为密钥。

推导后,您当然可以通过加密/解密或一些数据进行测试。

n为所需的派生密钥长度(以字节为单位)。派生密钥是完成哈希计算后哈希值的前n 个CryptDeriveKey字节。如果哈希值不是 SHA-2 系列的成员,并且所需密钥适用于 3DES 或 AES,则密钥的推导如下:

  1. 通过重复常量 64 次形成 64 字节缓冲区0x36。令k为输入参数 表示的哈希值的长度hBaseData。将缓冲区的前k字节设置为缓冲区的前k字节与输入参数表示的哈希值进行异或运算的结果hBaseData
  2. 通过重复常量 64 次形成 64 字节缓冲区0x5C。将缓冲区的前k字节设置为缓冲区的前k字节与输入参数表示的哈希值进行异或运算的结果。hBaseData
  3. 使用与计算参数表示的哈希值相同的哈希算法对步骤 1 的结果进行哈希处理hBaseData
  4. 使用与计算参数表示的哈希值相同的哈希算法对步骤 2 的结果进行哈希处理hBaseData
  5. 将步骤 3 的结果与步骤 4 的结果连接起来。
  6. 使用步骤 5 结果的前n 个字节作为派生密钥。