You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用WinApi(C/C++)生成兼容OpenSSL的AES-256-CBC安全随机密钥与IV

在C/C++中生成可用于OpenSSL的AES-256-CBC安全密钥与IV

核心需求

需要生成:

  • 32字节的安全随机密钥(对应AES-256),转换为64字符的十六进制ASCII字符串,供OpenSSL的-K参数使用
  • 16字节的安全随机IV,转换为32字符的十六进制ASCII字符串,供OpenSSL的-iv参数使用
    生成的字符串需保存到文本文件,用于终端手动测试解密。同时需要替代CryptGenRandom的安全随机生成方案,解决原始随机字节无法直接作为OpenSSL输入的问题。

替代CryptGenRandom的安全随机生成方法

1. BCryptGenRandom(推荐,现代Windows API)

这是微软官方推荐的新一代密码学随机数生成接口,替代老旧的CryptGenRandom,支持Windows Vista及以上系统,安全性更高,属于CNG(Cryptography Next Generation)框架的标准组件。

2. CNG框架下的其他实现

本质与BCryptGenRandom同源,是现代Windows系统提供的标准安全随机数生成体系,避免了旧API的兼容性与安全性问题。

关键注意点

OpenSSL的-K和-iv参数要求输入十六进制编码的ASCII字符串,而非原始随机字节。因此生成流程应为:

  1. 生成指定长度的原始随机字节数组(32字节密钥/16字节IV)
  2. 将字节数组转换为十六进制ASCII字符串(每个字节对应两个十六进制字符)
  3. 将十六进制字符串保存到文件,供OpenSSL使用
  4. 加密时仍使用原始字节数组(而非十六进制字符串)传递给WinAPI的加密接口

修改后的完整代码示例

#include <windows.h>
#include <bcrypt.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#pragma comment(lib, "bcrypt.lib")

#define DEFAULT_AES_KEY_SIZE 32
#define DEFAULT_IV_SIZE 16
#define BUFFER_FOR_PLAINTEXT 1024

// 字节数组转十六进制字符串
BOOL BytesToHexString(const BYTE* pBytes, DWORD dwLength, char** ppHexStr)
{
    if (pBytes == NULL || dwLength == 0 || ppHexStr == NULL)
        return FALSE;

    // 每个字节占2个十六进制字符,加1存终止符
    DWORD dwHexStrLen = dwLength * 2 + 1;
    *ppHexStr = (char*)calloc(dwHexStrLen, sizeof(char));
    if (*ppHexStr == NULL)
        return FALSE;

    const char* szHexChars = "0123456789ABCDEF";
    for (DWORD i = 0; i < dwLength; i++)
    {
        (*ppHexStr)[i * 2] = szHexChars[(pBytes[i] >> 4) & 0x0F];
        (*ppHexStr)[i * 2 + 1] = szHexChars[pBytes[i] & 0x0F];
    }
    return TRUE;
}

// 保存字符串到文件
BOOL SaveStringToFile(const char* szStr, const char* szFilePath)
{
    FILE* pFile = fopen(szFilePath, "w");
    if (pFile == NULL)
        return FALSE;

    fprintf(pFile, "%s", szStr);
    fclose(pFile);
    return TRUE;
}

int main()
{
    HCRYPTPROV hProv = NULL;
    HCRYPTKEY hKey = NULL;
    BYTE* szKeyBytes = (BYTE*)calloc(DEFAULT_AES_KEY_SIZE, sizeof(BYTE));
    BYTE* szIVBytes = (BYTE*)calloc(DEFAULT_IV_SIZE, sizeof(BYTE));
    char* szKeyHex = NULL;
    char* szIVHex = NULL;
    char* ciphertext = 0;
    const char* plaintext = "测试明文内容"; // 示例明文
    DWORD dwPlainSize = lstrlenA(plaintext), dwBufSize = 0;
    AES256KEYBLOB AESBlob;
    memset(&AESBlob, 0, sizeof(AESBlob));
    NTSTATUS status;

    // --------------------------
    // 1. 用BCryptGenRandom生成安全随机字节
    // --------------------------
    BCRYPT_ALG_HANDLE hAlg = NULL;
    // 打开随机数生成算法
    status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0);
    if (!BCRYPT_SUCCESS(status))
        goto error;

    // 生成密钥字节
    status = BCryptGenRandom(hAlg, szKeyBytes, DEFAULT_AES_KEY_SIZE, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
    if (!BCRYPT_SUCCESS(status))
        goto error;

    // 生成IV字节
    status = BCryptGenRandom(hAlg, szIVBytes, DEFAULT_IV_SIZE, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
    if (!BCRYPT_SUCCESS(status))
        goto error;

    BCryptCloseAlgorithmProvider(hAlg, 0);

    // --------------------------
    // 2. 转换为十六进制字符串并保存到文件
    // --------------------------
    if (!BytesToHexString(szKeyBytes, DEFAULT_AES_KEY_SIZE, &szKeyHex))
        goto error;
    if (!BytesToHexString(szIVBytes, DEFAULT_IV_SIZE, &szIVHex))
        goto error;

    printf("生成的密钥十六进制字符串:%s\n", szKeyHex);
    printf("生成的IV十六进制字符串:%s\n", szIVHex);

    // 保存到文件
    if (!SaveStringToFile(szKeyHex, "aes_key.txt"))
        goto error;
    if (!SaveStringToFile(szIVHex, "aes_iv.txt"))
        goto error;

    // --------------------------
    // 3. 执行AES-256-CBC加密(沿用原有逻辑,使用原始字节)
    // --------------------------
    // 填充AES Blob结构
    AESBlob.bhHdr.bType = PLAINTEXTKEYBLOB;
    AESBlob.bhHdr.bVersion = CUR_BLOB_VERSION;
    AESBlob.bhHdr.reserved = 0;
    AESBlob.bhHdr.aiKeyAlg = CALG_AES_256;
    AESBlob.dwKeySize = DEFAULT_AES_KEY_SIZE;
    memcpy(AESBlob.szBytes, szKeyBytes, DEFAULT_AES_KEY_SIZE); // 使用原始密钥字节

    // 创建CSP
    if (!CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV_A, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
        goto error;

    // 导入密钥
    if (!CryptImportKey(hProv, (BYTE*)&AESBlob, sizeof(AES256KEYBLOB), NULL, CRYPT_EXPORTABLE, &hKey))
        goto error;

    // 设置IV
    if (!CryptSetKeyParam(hKey, KP_IV, szIVBytes, 0)) // 使用原始IV字节
        goto error;

    // 分配密文缓冲区
    dwBufSize = BUFFER_FOR_PLAINTEXT + dwPlainSize;
    ciphertext = (char*)calloc(dwBufSize, sizeof(char));
    if (ciphertext == NULL)
        goto error;
    memcpy_s(ciphertext, dwBufSize, plaintext, dwPlainSize);

    // 执行加密
    if (!CryptEncrypt(hKey, NULL, TRUE, 0, (BYTE*)ciphertext, &dwPlainSize, dwBufSize))
        goto error;

    printf("加密成功,密文长度:%u字节\n", dwPlainSize);

    // 清理资源
error:
    if (szKeyBytes) free(szKeyBytes);
    if (szIVBytes) free(szIVBytes);
    if (szKeyHex) free(szKeyHex);
    if (szIVHex) free(szIVHex);
    if (ciphertext) free(ciphertext);
    if (hKey) CryptDestroyKey(hKey);
    if (hProv) CryptReleaseContext(hProv, 0);
    return 0;
}

OpenSSL解密命令示例

假设加密后的文件为encrypted.bin,使用生成的密钥和IV文件解密:

# 从文件读取密钥和IV,执行解密
openssl aes-256-cbc -d -K $(cat aes_key.txt) -iv $(cat aes_iv.txt) -in encrypted.bin -out decrypted.txt

内容的提问来源于stack exchange,提问作者rmroot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 13:33:06