2014-12-02 16 views
6

Próbuję użyć PBKDF2 do wyprowadzenia klucza z łańcuchem o długości 256 bitów. Jestem w stanie użyć C# 's Rfc2898DeriveBytes i pbkdf2 węzła-crypto, aby wyprowadzić ten sam klucz, jednak nie mogę powiedzieć tego samego dla C++. Nie jestem pewien, czy robię niewłaściwe konwersje lub niewłaściwie wykorzystuję funkcje, ale pozwolę wam na to spojrzeć.Wyjście Crypto ++ pbkdf2 różni się od Rfc2898DeriveBytes (C#) i 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= 
*/ 

dobrze główne pytania o to, co robię źle na C++ 's CryptoPP biblioteki, która nie jest uzyskując tę ​​samą wartość.

ROZWIĄZANIE: Byłem głupi ... I jest realizowany po przeglądzie moje oryginalne wykonanie na JavaScript i C# Tęskniłem za ważny krok, który z jakiegoś powodu nie dostał skarżą się od kompilatora. Zasadniczo problemem było to, że nie konwertować klucz używany do danych bajtowych przed algorytmu na moim C# i wdrożenia JS ...

Anyways, proponowane rozwiązanie jest: nie kod o 4 rano i upewnij się Konsekwentnie na konwersję danych ...

Chyba TL; DR to, że C# i JS konwertowały mój klucz 256-bitowy do danych bajtowych jako ASCII zamiast do konwersji base64.

+0

pan stwierdził obserwacji, ale trzeba nie zadał pytania. Jakie jest Twoje pytanie? A tak przy okazji, czy uruchomiłeś testowe wektory/znane testy odpowiedzi przeciwko implementacjom, aby zobaczyć, które dają prawidłowe i błędne odpowiedzi? – jww

+0

Cóż, główne pytania brzmią: co robię źle w CryptoPP C++, że nie wywodzi się z tej samej wartości. Nie skonfigurowałem środowiska, aby przetestować bibliotekę indywidualnie. Jednak w każdym języku mam również równoważną metodę deszyfrowania, która pobiera te wartości bajtów i odszyfrowuje wiadomość. Jedynym, który nie zwraca właściwej wartości jest C++, ale jeśli przekażę pochodnąKey z dowolnego z innych języków i kontynuuję mój deszyfrowanie, wynik jest poprawny. W tej chwili biblioteka cryptopp jest używana w połączeniu z Cocos2dx C++ na platformie Android, więc denerwujące do debugowania – Chebn

Odpowiedz

2

dobrze główne pytania o to, co robię źle na C++ 's CryptoPP biblioteki, że nie uzyskuje taką samą wartość.

Cóż, nie sądzę, że robisz coś złego w C++ z Crypto ++ i PBKDF2. Sądzę, że inne biblioteki inaczej konfigurują parametry lub są troszkę niestandardowe.

udało mi się przybyć IETF test vectors for PBKDF2 wykorzystaniem 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; 
} 

oraz przebiegu programu:

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

Myślę, że pierwszą rzeczą, którą należy zrobić, to sprawdzić implementacje C# i Javascript używają tego samego kodowania znaków co Crypto ++ i IETF.

Jeśli to nie wszystko, sprawdź, czy C# i JavaScript używają bajtu celu. Crypto ++ nie ma, a implementację można zobaczyć pod numerem pwdbased.h.


Niestety, mam coś innego, kiedy wybrać się swoimi parametrami:

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

A wyniki uruchamiane w:

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

Dzięki za pomoc. Jeśli nie sugerowałbyś przetestowania mojego kodu względem wektorów testowych IETF, nie zajrzałbym do moich oryginalnych implementacji i zakładałbym, że CryptPP szaleje za mną. Nadal jestem zaskoczony, że kompilator C# i węzeł nie narzekali tak, jak robił to C++. Jeszcze raz dziękuję! – Chebn

+0

@Jww: Czy zraszanie w małych wyciekach pamięci, gdy używasz operatora 'new' w twoim przykładzie bez' delete'-inging? – ahmd0

+0

@ ahmd0 - No. Zobacz [Pipelining | Własność] (https://www.cryptopp.com/wiki/Pipelining#Ownership) na wiki Crypto ++. – jww