C#与C中BCrypt的RSA跨语言加解密兼容性问题排查
RSA 2048跨C#/C加密通信解密失败问题排查与解决
问题描述
我正在实现C#与C程序间的RSA 2048加密通信:C程序嵌入私钥,C#程序嵌入公钥,由C#加密字符串后发送给C端解密。但遇到以下问题:
- 当C端调用
BCryptDecrypt时,指定BCRYPT_PAD_PKCS1或BCRYPT_PAD_OAEP填充模式,返回0xc000000d(INVALID_PARAMETER)错误 - 使用
BCRYPT_PAD_NONE填充模式时无错误,但解密结果为乱码
已尝试操作
- 最初在C#生成密钥对,复制到两端使用,问题未解决
- 改为在C程序中生成密钥对,导出十六进制格式:私钥存入C的
unsigned char数组,公钥转为C#字符串处理;尝试枚举所有字节序组合适配公钥,问题依旧 - 明确
BCRYPT_RSAPUBLIC_BLOB结构(头部4个小端ULONG,随后是公钥指数、模数),修正C#中提取指数和模数的逻辑(确认指数3字节、模数256字节,处理了多余的8字节填充),但仍出现相同解密错误
可能原因分析
密钥格式不匹配
- C端导入私钥时,可能未正确构造
BCRYPT_RSAPRIVATE_BLOB结构,比如头部Magic值、密钥长度、指数/模数长度等参数设置错误,导致BCryptDecrypt无法识别密钥 - C#导入公钥时,虽修正了指数和模数提取,但可能未正确处理
BCRYPT_RSAPUBLIC_BLOB的字节序(如头部ULONG为小端,但指数/模数是否需要大端转小端)
- C端导入私钥时,可能未正确构造
填充模式参数不兼容
- C#加密与C端解密的填充模式细节不匹配:比如OAEP填充的哈希算法不一致(C#默认SHA-1,C端若未显式指定哈希算法,可能默认值不匹配)
- PKCS#1 v1.5填充时,C#加密的是字符串UTF-8字节,C端解密后未正确处理编码,或加密时明文长度超过RSA 2048的最大限制(PKCS#1 v1.5为245字节)
BCrypt API调用参数错误
BCryptDecrypt的输入参数存在问题:比如OAEP填充时未传入正确的BCRYPT_OAEP_PADDING_INFO结构体(哈希算法名称未指定),或cbInput未设置为正确的密文长度(256字节)
解决建议
1. 验证密钥结构正确性
- 在C端生成密钥对后,直接导出
BCRYPT_RSAPRIVATE_BLOB和BCRYPT_RSAPUBLIC_BLOB的原始字节,对比C#导入的公钥字节是否与导出的公钥blob完全一致(排除十六进制转换错误) - 检查C端私钥blob的头部参数:
- Magic值必须为小端
BCRYPT_RSA_PRIVATE_MAGIC(0x31415352) - 密钥长度为2048(小端0x0800)
- 指数长度、模数长度需与实际值匹配(指数通常3字节,模数256字节)
- Magic值必须为小端
2. 统一填充模式与哈希算法
- PKCS#1 v1.5方案:
- C#加密时使用
RSAEncryptionPadding.Pkcs1,确保明文长度≤245字节 - C端解密时指定
BCRYPT_PAD_PKCS1,无需额外填充参数
- C#加密时使用
- OAEP方案:
- C#加密时显式指定哈希算法,比如
RSAEncryptionPadding.OaepSHA256 - C端解密时构造
BCRYPT_OAEP_PADDING_INFO结构体,设置pszAlgId为BCRYPT_SHA256_ALGORITHM,并将该结构体指针传入BCryptDecrypt的pPaddingInfo参数
- C#加密时显式指定哈希算法,比如
3. 确保加密数据完整性
- C#加密后将密文转为Base64或十六进制字符串传输,C端接收后还原为原始字节,避免传输过程中字节丢失或篡改
- 验证C#加密后的密文长度是否为256字节(RSA 2048密文固定长度),若长度不符,说明加密过程存在错误
4. 调试BCrypt API调用
- 调用
BCryptDecrypt前,检查所有参数有效性:hKey是否为有效句柄,pbInput指向的数组长度是否为256,cbInput是否设为256 - 使用
BCryptGetProperty获取密钥属性(如BCRYPT_KEY_LENGTH、BCRYPT_RSA_EXPONENT),确认密钥导入正确
内容的提问来源于stack exchange,提问作者UnSure
相关产品推荐
相关产品推荐

