C# Rfc2898DeriveBytes与C++ Crypto++ PKCS5_PBKDF2_HMAC结果不一致问题
C# Rfc2898DeriveBytes与C++ Crypto++ PKCS5_PBKDF2_HMAC派生密钥不一致问题
我需要实现C#加密数据、C++ Crypto库读取的流程,计划采用带密钥(Key)和初始化向量(IV)的AES加密,第一步通过HMAC生成Key和IV。但C#的Rfc2898DeriveBytes与C的PKCS5_PBKDF2_HMAC生成的32字节派生密钥结果始终不一致。已核对函数签名、参数,测试过移除C++字符数组的换行符,也尝试过相关代码方案,仍未解决。
两端生成的派生密钥示例:
- C#生成结果:237, 130, 48, 114 ......
- C++生成结果:118, 142, 106, 94 ......
原代码
C#代码
using System; using System.Security.Cryptography; namespace DeriveKeyCSharp { class Program { static void Main(string[] args) { string password = "sdHBDHC^BGGijvn"; int niter = 1000; Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(password, new byte[13] { (byte)73, (byte)118, (byte)97, (byte)110, (byte)32, (byte)77, (byte)101, (byte)100, (byte)118, (byte)101, (byte)100, (byte)101, (byte)118 }, niter, HashAlgorithmName.SHA1); byte[] derivedKey = rfc.GetBytes(32); } } }
C++代码
#include <cryptopp/hmac.h> #include <cryptopp/sha.h> #include <cryptopp/pwdbased.h> using namespace std; using namespace CryptoPP; int main() { byte password[] = "sdHBDHC^BGGijvnH"; size_t plen = strlen((const char*)password); byte salt[] = { 73, 118, 97, 110, 32, 77, 101, 100, 118, 101, 100, 101, 118 }; size_t slen = sizeof(salt); byte keyByte[] = "sdHBDHC^BGGijvnH"; int lenKey = sizeof(keyByte) - 1; // remove \n byte derivedKey[32]; PKCS5_PBKDF2_HMAC<SHA1> pbkdf2; pbkdf2.DeriveKey(derivedKey, sizeof(derivedKey), 0, keyByte, lenKey, salt, sizeof(salt), 1000); }
问题原因与修正
核心错误点
- 密码内容不一致:C#中密码是
"sdHBDHC^BGGijvn",但C++中写成了"sdHBDHC^BGGijvnH",多了末尾的H字符,直接导致输入的原始密码不同,派生结果必然不一致。 - 参数冗余与误用:C++代码中定义了
password变量但未使用,反而用了重复定义的keyByte,属于代码冗余,容易引发错误。
修正后的C++代码
#include <cryptopp/hmac.h> #include <cryptopp/sha.h> #include <cryptopp/pwdbased.h> #include <iostream> using namespace CryptoPP; int main() { // 与C#一致的密码 const byte password[] = "sdHBDHC^BGGijvn"; size_t passwordLen = strlen((const char*)password); // 与C#完全一致的盐值 const byte salt[] = { 73, 118, 97, 110, 32, 77, 101, 100, 118, 101, 100, 101, 118 }; size_t saltLen = sizeof(salt); byte derivedKey[32]; PKCS5_PBKDF2_HMAC<SHA1> pbkdf2; // 参数与C#完全对齐:派生密钥、密钥长度、用途字节(C#默认0)、密码、密码长度、盐、盐长度、迭代次数 pbkdf2.DeriveKey(derivedKey, sizeof(derivedKey), 0, password, passwordLen, salt, saltLen, 1000); // 输出验证(可选) for (size_t i = 0; i < sizeof(derivedKey); ++i) { std::cout << static_cast<int>(derivedKey[i]) << ", "; } std::cout << std::endl; return 0; }
额外验证点
- 编码一致性:C#的
Rfc2898DeriveBytes构造函数接收string类型密码时,内部默认使用UTF-8编码将字符串转换为字节数组。C中直接使用ASCII字符数组时,若密码仅包含ASCII字符,编码是一致的;若密码包含非ASCII字符,需确保C端也用UTF-8编码转换为字节数组。 - 迭代次数与哈希算法:两端均使用1000次迭代和SHA1哈希算法,参数已对齐,无需修改。
内容的提问来源于stack exchange,提问作者logit
相关产品推荐
相关产品推荐

