2014-12-02 12 views
6

Quindi sto cercando di utilizzare PBKDF2 per derivare una chiave con una stringa base64 di 256 bit. Sono in grado di utilizzare Rfc2898DeriveBytes di C# e pbkdf2 di node-crypto per derivare la stessa chiave, tuttavia, non posso dire lo stesso per C++. Non sono sicuro se sto eseguendo conversioni errate o utilizzando le funzioni in modo improprio, ma ti lascio guardare da loro.L'output di Crypto ++ pbkdf2 è diverso da Rfc2898DeriveBytes (C#) e 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= 
*/ 

bene le questioni principali è, che cosa sto sbagliando su cryptopp libreria C++ 's che non è derivando lo stesso valore.

SOLUZIONE: Ero essere muto ... ho capito dopo la revisione mia implementazione originale su JavaScript e C# ho perso un passo cruciale che per qualche motivo non ho avuto un lamentano dal compilatore. In sostanza il problema era che non mi converto la chiave utilizzata in byte di dati prima che l'algoritmo sul mio C# e implementazione JS ...

In ogni modo, la soluzione proposta è: non il codice alle 4 del mattino e assicurarsi di essere coerente sulla conversione dei dati ...

Immagino che il TL; DR di questo è che C# e JS stava convertendo la mia chiave a 256 bit in dati byte come ASCII invece di conversione base64.

+0

Hai dichiarato un'osservazione, ma si deve non ha fatto una domanda Qual è la tua domanda? A proposito, hai lanciato vettori di test/test di risposta noti contro le implementazioni per vedere quali risposte giuste e sbagliate? – jww

+0

Beh, le domande principali sono, cosa sto facendo male sulla libreria CryptoPP di C++ che non sta ottenendo lo stesso valore. Non ho installato un ambiente per testare individualmente la libreria. Tuttavia su ogni lingua ho anche il metodo di decrittazione equivalente che prenderà quei valori di byte e decodificherà un messaggio. L'unico che non restituisce il valore corretto è in C++, ma se passo la derivata da uno degli altri linguaggi e continuo la mia decifratura, l'output è corretto. In questo momento la libreria di cryptopp viene utilizzata in combinazione con Cocos2dx C++ sulla piattaforma Android, così fastidiosa da eseguire il debug di – Chebn

risposta

2

bene le principali domande a dire, quello che sto facendo di sbagliato in libreria C++ s 'cryptopp che non fa derivare lo stesso valore.

Bene, non penso che stiate facendo qualcosa di sbagliato in C++ con Crypto ++ e PBKDF2. Penso che le altre librerie stiano configurando i parametri in modo diverso, oppure sono un po 'meno standard.

sono stato in grado di arrivare alla IETF test vectors for PBKDF2 utilizzando 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; 
} 

E una corsa del programma:

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

Penso che la prima cosa da fare è verificare le implementazioni C# e Javascript utilizzano la stessa codifica di caratteri di Crypto ++ e IETF.

Se non è così, quindi controllare se C# e Javascript utilizzano il byte di scopo. Crypto ++ non lo fa, e puoi vedere l'implementazione allo pwdbased.h.


Purtroppo, ho ottenere qualcosa di un po 'diverso quando compongo nei tuoi parametri:

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

una corsa risultati in:

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

Grazie per l'aiuto. Se non avessi suggerito di testare il mio codice con i vettori di test di IETF, non avrei guardato nelle mie implementazioni originali e avrei continuato a pensare che CryptPP stesse impazzendo per me. Sono comunque sorpreso che il compilatore e il nodo C# non si siano lamentati come ha fatto il C++. Grazie ancora! – Chebn

+0

@Jww: stai sprecando piccole perdite di memoria quando stai usando l'operatore 'new' nel tuo esempio senza' eliminarlo? – ahmd0

+0

@ ahmd0 - No. Vedi [Pipelining | Proprietà] (https://www.cryptopp.com/wiki/Pipelining#Ownership) sul wiki Crypto ++. – jww

Problemi correlati