如何在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); }
关键说明
- 句柄存储修正:原代码用
malloc存储句柄完全没必要,直接用栈变量存储即可,避免不必要的内存操作。 - 导出公钥而非私钥:如果只需要公钥的模数和指数,使用
BCRYPT_RSAPUBLIC_BLOB比BCRYPT_RSAFULLPRIVATE_BLOB更高效,数据量更小。 - 内存分配与解析:先获取总大小再分配内存,确保能容纳完整的密钥数据;通过结构体字段计算模数和指数的偏移位置,即可拿到实际数值。
- 资源释放:必须调用
BCryptDestroyKey和BCryptCloseAlgorithmProvider关闭句柄,否则会造成系统资源泄漏。
内容的提问来源于stack exchange,提问作者Pierre
相关产品推荐
相关产品推荐

