Поэтому я пытаюсь использовать PBKDF2 для получения ключа с заданной строкой base64 256 бит. Я могу использовать Rfc2898DeriveBytes в C # и pbkdf2 для узла-криптоза для получения одного и того же ключа, однако я не могу сказать то же самое для C ++. Я не уверен, что делаю неправильные преобразования или неправильно использую функции, но я позволю вам, ребята, взглянуть на это.
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
библиотека, которая не получает то же значение.
РЕШЕНИЕ: я был тупым … Я понял, после проверки моей первоначальной реализации на JavaScript и C #, я пропустил важный шаг, который по какой-то причине не получил претензии от компилятора. В основном проблема заключалась в том, что я не преобразовывал используемый ключ в байтовые данные до алгоритма в моей реализации на C # и JS …
В любом случае, предлагаемое решение: не кодируйте в 4 часа утра и следите за тем, чтобы ваши преобразования данных были последовательными …
Я предполагаю, что TL; DR этого заключается в том, что C # и JS преобразовывали мой 256-битный ключ в байтовые данные как ASCII вместо преобразования base64.
Ну, главный вопрос в том, что я делаю неправильно в библиотеке CryptoPP C ++, что она не выводит одно и то же значение.
Ну, я не думаю, что вы делаете что-то не так в C ++ с Crypto ++ и PBKDF2. Я думаю, что другие библиотеки настраивают параметры по-другому, или они немного нестандартны.
Я смог прибыть в IETF тестовые векторы для PBKDF2 используя Crypto ++:
// 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