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

如何在C/C++中通过BCrypt获取RSA公钥的模数与指数?

问题分析

你的问题出在BCryptExportKey的调用方式:BCRYPT_RSAKEY_BLOB只是密钥数据的头部结构,实际的模数、指数等字节数据紧跟在结构体之后。你只分配了结构体大小的缓冲区,自然只能拿到头部的长度信息,取不到实际的密钥数值。

解决方案步骤
  • 第一步:先调用BCryptExportKey获取完整密钥Blob的总大小(传入NULL作为输出缓冲区)
  • 第二步:根据返回的总大小分配足够的内存缓冲区
  • 第三步:再次调用BCryptExportKey导出完整的密钥数据
  • 第四步:从缓冲区中解析出模数和指数(注意字节序为大端)
修改后的代码示例
BOOL RSA_New(RSA_CTX_ST* rsa_ctx, const BYTE key_data[256], DWORD key_len, BOOL cipher)
{
    if (rsa_ctx == NULL || key_len != RSA_2048_BLOCK_SIZE)
    {
        return FALSE;
    }

    NTSTATUS status = STATUS_UNSUCCESSFUL;
    BCRYPT_ALG_HANDLE algo_handle = NULL;
    BCRYPT_KEY_HANDLE key_handle = NULL;

    // 创建算法句柄
    status = BCryptOpenAlgorithmProvider(&algo_handle, BCRYPT_RSA_ALGORITHM, NULL, 0);
    if (!NT_SUCCESS(status))
    {
        UTL_Trace("SEC", VRB_MAJOR, "RSA:Algorithm handle opening error");
        goto END;
    }

    // 生成密钥对
    status = BCryptGenerateKeyPair(algo_handle, &key_handle, 2048, 0);
    if (!NT_SUCCESS(status))
    {
        UTL_Trace("SEC", VRB_MAJOR, "RSA:Key pair generating error");
        goto END;
    }

    ULONG blob_size = 0;
    // 第一步:获取完整Blob的大小
    status = BCryptExportKey(key_handle, NULL, BCRYPT_RSAPUBLIC_BLOB, NULL, 0, &blob_size, 0);
    if (!NT_SUCCESS(status))
    {
        UTL_Trace("SEC", VRB_MAJOR, "RSA:Get blob size error");
        goto END;
    }

    // 分配足够的内存存储完整Blob
    BYTE* p_blob_buffer = malloc(blob_size);
    if (p_blob_buffer == NULL)
    {
        UTL_Trace("SEC", VRB_INFO, "Allocating RSA blob buffer error");
        goto END;
    }

    // 第二步:导出完整的公钥Blob
    status = BCryptExportKey(key_handle, NULL, BCRYPT_RSAPUBLIC_BLOB, p_blob_buffer, blob_size, &blob_size, 0);
    if (!NT_SUCCESS(status))
    {
        UTL_Trace("SEC", VRB_MAJOR, "RSA:Export public key error");
        goto FREE_BLOB;
    }

    // 解析Blob中的模数和指数
    BCRYPT_RSAKEY_BLOB* p_rsa_blob = (BCRYPT_RSAKEY_BLOB*)p_blob_buffer;
    // 模数的起始位置:结构体大小之后
    BYTE* modulus = p_blob_buffer + sizeof(BCRYPT_RSAKEY_BLOB);
    // 指数的起始位置:模数起始 + 模数长度
    BYTE* public_exponent = modulus + p_rsa_blob->ModulusSize;

    // 将modulus和public_exponent复制到你的rsa_ctx中
    // 注意:BCrypt的RSA Blob中,模数和指数都是大端字节序
    if (rsa_ctx->modulus != NULL)
    {
        memcpy(rsa_ctx->modulus, modulus, p_rsa_blob->ModulusSize);
        rsa_ctx->modulus_len = p_rsa_blob->ModulusSize;
    }
    if (rsa_ctx->public_exponent != NULL)
    {
        memcpy(rsa_ctx->public_exponent, public_exponent, p_rsa_blob->PublicExponentSize);
        rsa_ctx->exponent_len = p_rsa_blob->PublicExponentSize;
    }

    status = STATUS_SUCCESS;

FREE_BLOB:
    free(p_blob_buffer);
END:
    // 关闭句柄,避免资源泄漏
    if (key_handle != NULL)
    {
        BCryptDestroyKey(key_handle);
    }
    if (algo_handle != NULL)
    {
        BCryptCloseAlgorithmProvider(algo_handle, 0);
    }

    return NT_SUCCESS(status);
}
关键说明
  1. 句柄存储修正:原代码用malloc存储句柄完全没必要,直接用栈变量存储即可,避免不必要的内存操作。
  2. 导出公钥而非私钥:如果只需要公钥的模数和指数,使用BCRYPT_RSAPUBLIC_BLOB比BCRYPT_RSAFULLPRIVATE_BLOB更高效,数据量更小。
  3. 内存分配与解析:先获取总大小再分配内存,确保能容纳完整的密钥数据;通过结构体字段计算模数和指数的偏移位置,即可拿到实际数值。
  4. 资源释放:必须调用BCryptDestroyKey和BCryptCloseAlgorithmProvider关闭句柄,否则会造成系统资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 20:15:46