Crypto ++ pbkdf2输出不同于Rfc2898DeriveBytes(C#)和crypto.pbkdf2(JavaScript)
所以我试图用PBKDF2派生一个给定base64的256位字符串的密钥。我能够使用C#的Rfc2898DeriveBytes和node-crypto的pbkdf2来派生相同的密钥,但是,我不能说C++是一样的。我不确定我是否进行了错误的转换或使用不当的功能,但我会让你们看看它。Crypto ++ pbkdf2输出不同于Rfc2898DeriveBytes(C#)和crypto.pbkdf2(JavaScript)
C++
/* 256bit key */
string key = "Y1Mjycd0+O+AendY5pB58JMlmS0EmBWgjdj2r2KW6qQ=";
string decodedKey;
StringSource(key, true, new Base64Decoder(new StringSink(decodedKey)));
const byte* keyByte = (const byte*) decodedKey.data();
/* Generate IV */
/*
AutoSeededRandomPool prng;
byte iv[AES::BLOCKSIZE];
prng.GenerateBlock(iv, sizeof(iv));
*/
/* FOR TESTING PURPOSES, HARDCODE IV */
string iv = "5iFv54dCRq5icQbD7QHQzg==";
string decodedIv;
StringSource(iv, true, new Base64Decoder(new StringSink(decodedIv)));
const byte* ivByte = (const byte *) decodedIv.data();
byte derivedKey[32];
PKCS5_PBKDF2_HMAC<CryptoPP::SHA1> pbkdf2;
pbkdf2.DeriveKey(derivedKey, 32, 0, keyByte, 32, ivByte, 16, 100);
/*
* derivedKey: 9tRyXCoQLTbUOLqm3M4OPGT6N25g+o0K090fVp/hflk=
*/
C#
// string key = "Y1Mjycd0+O+AendY5pB58JMlmS0EmBWgjdj2r2KW6qQ="; // need to convert it to byte data
string key = Convert.FromBase64String("Y1Mjycd0+O+AendY5pB58JMlmS0EmBWgjdj2r2KW6qQ="); // change above to this
RijndaelManaged symKey = new RijndaelManaged();
symKey.GenerateIV(); /* Assume hardcoded IV same as above */
Rfc2898DeriveBytes derivedKey = new Rfc2898DeriveBytes (key, symKey.IV, 100);
/*
* derivedKey: dZqBpZKyUPKn8pU4pyyeAw7Rg8uYd6yyj3WI1MIJSyc=
*/
JS
// var key = "Y1Mjycd0+O+AendY5pB58JMlmS0EmBWgjdj2r2KW6qQ="; // need to convert it to byte data
var key = new Buffer("Y1Mjycd0+O+AendY5pB58JMlmS0EmBWgjdj2r2KW6qQ=", "base64"); // changed above to this
var iv = crypto.randomBytes(16);
iv = "5iFv54dCRq5icQbD7QHQzg=="; /* HARDCODE IV */
crypto.pbkdf2(key, iv, 100, 32, function(err, derivedKey) { }
/*
* derivedKey: dZqBpZKyUPKn8pU4pyyeAw7Rg8uYd6yyj3WI1MIJSyc=
*/
那么主要问题是,我在做什么错了C++的CryptoPP 库,这是不得出相同的价值。
SOLUTION:我是哑巴......我的评论后意识到我对JavaScript和C#最初实现我错过了关键的一步,由于某种原因,我没有得到来自编译器抱怨。基本上,问题是,我并没有转换我的C#和JS实现算法之前使用的成字节数据的密钥...
不管怎么说,提出的解决方案是:凌晨4点不代码,并确保将一致的你的数据转换...
我想TL; DR的这是C#和JS正在转换我的256位密钥字节数据为ASCII而不是base64转换。
那么主要的问题是,我在C++的CryptoPP库上做了什么错误,它没有得到相同的值。
嗯,我不认为你在Crypto ++和PBKDF2的C++中做了什么错误。我认为其他库正在设置不同的参数,或者它们是非标准的。
我能够在IETF的test vectors for PBKDF2使用加密+到达:
// From https://www.ietf.org/rfc/rfc6070.txt
// PKCS #5: Password-Based Key Derivation Function 2 (PBKDF2) Test Vectors
//
// Input:
// P = "password" (8 octets)
// S = "salt" (4 octets)
// c = 1
// dkLen = 20
//
// Output:
// DK = 0c 60 c8 0f 96 1f 0e 71
// f3 a9 b5 24 af 60 12 06
// 2f e0 37 a6 (20 octets)
int main(int argc, char* argv[])
{
byte password[] ="password";
size_t plen = strlen((const char*)password);
byte salt[] = "salt";
size_t slen = strlen((const char*)salt);
int c = 1;
byte derived[20];
PKCS5_PBKDF2_HMAC<CryptoPP::SHA1> pbkdf2;
pbkdf2.DeriveKey(derived, sizeof(derived), 0, password, plen, salt, slen, c);
string result;
HexEncoder encoder(new StringSink(result));
encoder.Put(derived, sizeof(derived));
encoder.MessageEnd();
cout << "Derived: " << result << endl;
return 0;
}
而且程序的运行:
$ ./cryptopp-test.exe
Derived: 0C60C80F961F0E71F3A9B524AF6012062FE037A6
我认为你应该做的第一件事就是验证C#和Javascript实现使用与Crypto ++和IETF相同的字符编码。
如果不是这样,那么检查C#和Javascript是否使用目的字节。 Crypto ++没有,你可以在pwdbased.h看到实现。
不幸的是,我得到的东西有点不同,当我在你的拨号参数:
int main(int argc, char* argv[])
{
string t1 = "Y1Mjycd0+O+AendY5pB58JMlmS0EmBWgjdj2r2KW6qQ=";
string t2 = "5iFv54dCRq5icQbD7QHQzg==";
string pw, iv;
Base64Decoder b1(new StringSink(pw));
b1.Put((const byte*)t1.data(), t1.size());
b1.MessageEnd();
Base64Decoder b2(new StringSink(iv));
b2.Put((const byte*)t2.data(), t2.size());
b2.MessageEnd();
int c = 100;
byte derived[32];
cout << "pw size: " << pw.size() << endl;
cout << "iv size: " << iv.size() << endl;
PKCS5_PBKDF2_HMAC<CryptoPP::SHA1> pbkdf2;
pbkdf2.DeriveKey(derived, sizeof(derived), 0, (byte*)pw.data(), pw.size(), (byte*)iv.data(), iv.size(), c);
string result;
HexEncoder encoder(new StringSink(result));
encoder.Put(derived, sizeof(derived));
encoder.MessageEnd();
cout << "Derived: " << result << endl;
return 0;
}
一个运行结果:
$ ./cryptopp-test.exe
pw size: 32
iv size: 16
Derived: F6D4725C2A102D36D438BAA6DCCE0E3C64FA376E60FA8D0AD3DD1F569FE17E59
感谢您的帮助。如果你不建议用IETF的测试向量来测试我的代码,我就不会查看我的原始实现,并且会一直假设CryptPP对我来说很疯狂。我仍然感到惊讶的是C#编译器和节点没有像C++那样抱怨。 再次感谢! – Chebn 2014-12-03 06:53:45
@Jww:当你在整个示例中使用'new'运算符而不删除''时,你是否在小内存泄漏? – ahmd0 2018-03-02 01:46:12
@ ahmd0 - 否请参阅[流水线|所有权](https://www.cryptopp.com/wiki/Pipelining#Ownership)在Crypto ++ wiki上。 – jww 2018-03-02 01:50:07
你说的观察,但你必须没有问一个问题。你的问题是什么?顺便说一下,你是否针对实现运行测试向量/已知答案测试,以查看哪些答案是正确的和错误的? – jww 2014-12-02 20:41:43
那么主要的问题是,我在C++的CryptoPP库中做了什么错误,它不是得到相同的值。我没有设置一个环境来单独测试这个库。然而,在每种语言中,我也有相应的解密方法,它们将采用这些字节值并解密消息。唯一没有返回正确值的是C++,但如果我从其他任何语言中传递derivedKey并继续解密,那么输出是正确的。现在,cryptopp库正在与android平台上的Cocos2dx C++结合使用,所以很难调试 – Chebn 2014-12-02 23:35:24