2014-12-02 28 views
6

所以我試圖用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轉換。

+0

你說的觀察,但你必須沒有問一個問題。你的問題是什麼?順便說一下,你是否針對實現運行測試向量/已知答案測試,以查看哪些答案是正確的和錯誤的? – jww 2014-12-02 20:41:43

+0

那麼主要的問題是,我在C++的CryptoPP庫中做了什麼錯誤,它不是得到相同的值。我沒有設置一個環境來單獨測試這個庫。然而,在每種語言中,我也有相應的解密方法,它們將採用這些字節值並解密消息。唯一沒有返回正確值的是C++,但如果我從其他任何語言中傳遞derivedKey並繼續解密,那麼輸出是正確的。現在,cryptopp庫正在與android平臺上的Cocos2dx C++結合使用,所以很難調試 – Chebn 2014-12-02 23:35:24

回答

2

那麼主要的問題是,我在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 
+0

感謝您的幫助。如果你不建議用IETF的測試向量來測試我的代碼,我就不會查看我的原始實現,並且會一直假設CryptPP對我來說很瘋狂。我仍然感到驚訝的是C#編譯器和節點沒有像C++那樣抱怨。 再次感謝! – Chebn 2014-12-03 06:53:45

+0

@Jww:當你在整個示例中使用'new'運算符而不刪除''時,你是否在小內存泄漏? – ahmd0 2018-03-02 01:46:12

+0

@ ahmd0 - 否請參閱[流水線|所有權](https://www.cryptopp.com/wiki/Pipelining#Ownership)在Crypto ++ wiki上。 – jww 2018-03-02 01:50:07

相關問題