The output of Crypto ++ pbkdf2 is different from Rfc2898DeriveBytes (C #) and crypto.pbkdf2 (JavaScript)

So, I'm trying to use PBKDF2 to get the key given by a base64 string of 256 bits. I can use C # Rfc2898DeriveBytes and node -crypto pbkdf2 to get the same key, however I cannot say the same for C ++. I'm not sure if I am doing the wrong conversions incorrectly or using functions incorrectly, but I will let you guys look at it.

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= */ 

WITH#

 // 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= */ 

Well, the main questions: what am I doing wrong in the C ++ CryptoPP library, that it does not output the same value.

SOLUTION: I was stupid ... I realized that after reviewing my initial implementation in JavaScript and C #, I missed an important step, for some reason I did not receive a complaint from the compiler. Basically the problem was that I did not convert the key used in byte data before the algorithm of my C # and JS implementation ...

In any case, the proposed solution: do not enter the code at 4 a.m. and make sure that it is consistent with your data conversion ...

I think TL, DR is that C # and JS converted my 256-bit key to byte data as ASCII instead of base64 conversion.

+6
source share
2 answers

Well, the main questions: what am I doing wrong in the CryptoPP C ++ library, that it does not get the same value.

Well, I donโ€™t think you are doing something wrong in C ++ with Crypto ++ and PBKDF2. I think other libraries configure the settings differently, or they are a few non-standard.

I managed to get IATF test vectors for PBKDF2 using 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; } 

And starting the program:

 $ ./cryptopp-test.exe Derived: 0C60C80F961F0E71F3A9B524AF6012062FE037A6 

I think the first thing you need to do is verify that the C # and Javascript implementations use the same character encoding as Crypto ++ and IETF.

If not, then check if C # and Javascript use the target byte. Crypto ++ does not, and you can see the implementation on pwdbased.h .


Unfortunately, something is slightly different for me when I type in the parameters:

 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; } 

Execution Result:

 $ ./cryptopp-test.exe pw size: 32 iv size: 16 Derived: F6D4725C2A102D36D438BAA6DCCE0E3C64FA376E60FA8D0AD3DD1F569FE17E59 
+3
source

Sorry, but what does the โ€œ0โ€ parameter mean in your example? This seems to be a โ€œtarget byte,โ€ but what are its meanings?

 pbkdf2.DeriveKey(derived, sizeof(derived), 0, password, plen, salt, slen, c); 

Today, the parameter "c" (please give a better name to some of your variables, especially in encryption, where it is obvious that you need to do everything so as not to do anything bad), what is the number of iterations of the function, should be more than 10000, preferably about 30000.

0
source

Source: https://habr.com/ru/post/978980/


All Articles