2015-04-20 9 views
5

Ich studiere C++ unabhängig und ich habe ein Problem, das ich mehr als Woche nicht lösen kann. Ich hoffe ihr könnt mir helfen.Erhalten SHA1 der Unicode-Zeichenfolge in Crypto ++

Ich brauche eine SHA1 Digest einer Unicode-Zeichenfolge (wie Привет), aber ich weiß nicht, wie das geht.

Ich habe versucht, es so zu machen, aber es gibt einen falschen Digest zurück!

Für wstring('Ы') Es gibt - A469A61DF29A7568A6CC63318EA8741FA1CF2A7
Ich brauche - 8dbe718ab1e0c4d75f7ab50fc9a53ec4f0528373

Grüße und sorry für mein Englisch :).

CryptoPP 5.6.2 MVC++ 2013

#include <iostream> 
#include "cryptopp562\cryptlib.h" 
#include "cryptopp562\sha.h" 
#include "cryptopp562\hex.h" 

int main() { 

    std::wstring string(L"Ы"); 
    int bs_size = (int)string.length() * sizeof(wchar_t); 

    byte* bytes_string = new byte[bs_size]; 

    int n = 0; //real bytes count 
    for (int i = 0; i < string.length(); i++) { 
     wchar_t wcharacter = string[i]; 

     int high_byte = wcharacter & 0xFF00; 

     high_byte = high_byte >> 8; 

     int low_byte = wcharacter & 0xFF; 

     if (high_byte != 0) { 
      bytes_string[n++] = (byte)high_byte; 
     } 

     bytes_string[n++] = (byte)low_byte; 
    } 

    CryptoPP::SHA1 sha1; 
    std::string hash; 

    CryptoPP::StringSource ss(bytes_string, n, true, 
     new CryptoPP::HashFilter(sha1, 
      new CryptoPP::HexEncoder(
       new CryptoPP::StringSink(hash) 
      ) 
     ) 
    ); 

    std::cout << hash << std::endl; 

    return 0; 
} 
+1

* "Ich habe versucht, es so zu machen, aber es liefert einen falschen Digest!" * - Der Crypto ++ Code sieht gut aus, also liegt das Problem wahrscheinlich woanders.Welchen Digest produziert er und welche Digest erwarten Sie? Ich * vermute * Sie benötigen einen Auszug der breiten Zeichenfolge in UTF-8 konvertiert. UTF-8 ist am interoperabelsten. Fügen Sie den erwarteten und tatsächlichen Digest zu Ihrer Frage hinzu, indem Sie auf * Bearbeiten * klicken (und nicht als Kommentar veröffentlichen). – jww

Antwort

3

Ich brauche einen SHA1 digest einer Unicode-Zeichenfolge (wie Привет) zu bekommen, aber ich weiß nicht, wie geht das.

Der Trick hier ist, Sie müssen wissen, wie die Unicode-Zeichenfolge zu codieren. Unter Windows ist ein wchar_t 2 Oktetts; während auf Linux ein wchar_t ist 4 otects. Es gibt eine Crypto ++ Wiki-Seite unter Character Set Considerations, aber es ist nicht so gut.

Um am effektivsten zusammenzuarbeiten, verwenden Sie immer UTF-8. Das bedeutet, dass Sie UTF-16 oder UTF-32 in UTF-8 konvertieren. Da Sie Windows verwenden, sollten Sie WideCharToMultiByte function aufrufen, um es mit CP_UTF8 zu konvertieren. Wenn Sie unter Linux wären, würden Sie libiconv verwenden.

Crypto ++ hat eine integrierte Funktion namens StringNarrow, die C++ verwendet. Es ist in der Datei misc.h. Rufen Sie unbedingt setlocale an, bevor Sie es verwenden.

Stack Overflow hat ein paar Fragen zur Verwendung der Windows-Funktion. Siehe beispielsweise How do you properly use WideCharToMultiByte.


Ich brauche - 8dbe718ab1e0c4d75f7ab50fc9a53ec4f0528373

Was die Hash (SHA-1, SHA-256, ...)? Ist es ein HMAC (Keyed Hash)? Sind die Informationen gesalzen (wie ein Passwort im Speicher)? Wie ist es codiert? Ich habe zu fragen, weil ich nicht die gewünschten Ergebnisse reproduzieren:

SHA-1: 2805AE8E7E12F182135F92FB90843BB1080D3BE8 
SHA-224: 891CFB544EB6F3C212190705F7229D91DB6CECD4718EA65E0FA1B112 
SHA-256: DD679C0B9FD408A04148AA7D30C9DF393F67B7227F65693FFFE0ED6D0F0ADE59 
SHA-384: 0D83489095F455E4EF5186F2B071AB28E0D06132ABC9050B683DA28A463697AD 
     1195FF77F050F20AFBD3D5101DF18C0D 
SHA-512: 0F9F88EE4FA40D2135F98B839F601F227B4710F00C8BC48FDE78FF3333BD17E4 
     1D80AF9FE6FD68515A5F5F91E83E87DE3C33F899661066B638DB505C9CC0153D 

Hier ist das Programm, das ich verwenden. Achten Sie darauf, geben Sie die Länge der breiten Zeichenfolge. Wenn Sie dies nicht tun (und -1 für die Länge verwenden), dann enthält WideCharToMultiByte das abschließende ASCII-Z in seinen Berechnungen. Da wir einen std::string verwenden, brauchen wir die Funktion nicht, um den ASCII-Z-Terminator einzuschließen.

2

Dies scheint gut für mich zu arbeiten.

Anstatt zu versuchen, die Stücke zu extrahieren, gieße ich einfach den breiten Zeichenpuffer auf eine const byte* und übergebe diese (und die angepasste Größe) an die Hash-Funktion.

int main() { 

    std::wstring string(L"Привет"); 

    CryptoPP::SHA1 sha1; 
    std::string hash; 

    CryptoPP::StringSource ss(
     reinterpret_cast<const byte*>(string.c_str()), // cast to const byte* 
     string.size() * sizeof(std::wstring::value_type), // adjust for size 
     true, 
     new CryptoPP::HashFilter(sha1, 
      new CryptoPP::HexEncoder(
       new CryptoPP::StringSink(hash) 
      ) 
     ) 
    ); 

    std::cout << hash << std::endl; 

    return 0; 
} 

Ausgang:

C6F8291E68E478DD5BD1BC2EC2A7B7FC0CEE1420 

EDIT: hinzuzufügen.

Das Ergebnis wird encoding abhängig sein. Zum Beispiel lief ich diese auf Linux, wo wchar_t 4 Bytes ist. Auf Windows glaube ich wchar_t kann nur 2 Bytes sein.

Aus Gründen der Konsistenz kann es besser sein, UTF8 a zu verwenden, speichern Sie den Text in einem normalen std::string. Dies macht auch die API einfacher Aufruf:

int main() { 

    std::string string("Привет"); // UTF-8 encoded 

    CryptoPP::SHA1 sha1; 
    std::string hash; 

    CryptoPP::StringSource ss(
     string, 
     true, 
     new CryptoPP::HashFilter(sha1, 
      new CryptoPP::HexEncoder(
       new CryptoPP::StringSink(hash) 
      ) 
     ) 
    ); 

    std::cout << hash << std::endl; 

    return 0; 
} 

Ausgang:

2805AE8E7E12F182135F92FB90843BB1080D3BE8 
+0

Für mich produziert es Digest 'AD5EF6AFD4BADE078F3E19FAE5E45A43635A18CB'. Kann ein Problem mit meinen IDE- oder Projekteinstellungen auftreten? Sag mir bitte, welche Ide- und Projekteinstellungen hast du? –

+1

@DmitryAurokk Ich benutze 'eclipse.com' IDE auf' Linux'. Ich denke, das Problem dürfte die Kodierung sein. Auf 'Linux' 'wchar_t' sind 4 Bytes (UTF32-kompatibel). Ich denke an 'Windows'' wchar_t' ist 2 Bytes? (UTF16 ish). Was ich gemacht habe, wurde getestet die Programmausgabe gegen das Kommandozeilenprogramm 'sha1sum' und es gibt das gleiche Ergebnis. Wenn Sie konsistente Ergebnisse über Plattformen wollen, dann ist es besser, 'UTF8' zu verwenden und große Strings zu vergessen. – Galik

+1

@DmitryAurokk Ich habe ein neues Beispiel mit 'UTF-8'-Codierung hinzugefügt (benötigen einen UTF-8-kompatiblen Texteditor) – Galik

3

Sie sagen, ‚aber es gibt falsche verdauen‘ - was Sie es vergleichen mit?

Schlüssel: Digests wie SHA-1 funktionieren nicht mit Sequenzen von Zeichen, aber mit Sequenzen von Bytes.

Was Sie in diesem Codeschnipsel machen, erzeugt eine Ad-hoc-Codierung der Unicode-Zeichen in der Zeichenfolge "Ы". Diese Codierung entspricht (wie sich herausstellt) der UTF-16-Kodierung , wenn die Zeichen in der Zeichenfolge alle in der BMP sind ('grundlegende mehrsprachige Ebene', die in diesem Fall wahr ist) und wenn die Zahlen, die enden in wcharacter sind Ganzzahlen Unicode-Codepoints (die Art von wahrscheinlich ist richtig, aber nicht, denke ich, garantiert).

Wenn der Digest, mit dem Sie ihn vergleichen, eine Eingabezeichenfolge in eine Sequenz von Bytes unter Verwendung der UTF-8-Codierung umwandelt (was ziemlich wahrscheinlich ist), erzeugt das eine andere Byte-Sequenz als die Ihre, so dass die SHA -1 Digest dieser Sequenz unterscheidet sich von dem Digest, den Sie hier berechnen.

So:

  • prüfen, was die Kodierung der Testzeichenfolge ist.

  • Am besten verwenden Sie einige Bibliotheksfunktionen, um speziell eine UTF-16- oder UTF-8-Codierung der Zeichenfolge zu generieren, die Sie verarbeiten möchten, um sicherzustellen, dass die Bytefolge, mit der Sie arbeiten ist das, was du denkst.

Es gibt eine ausgezeichnete Einführung in Unicode und Kodierungen in dem treffend bezeichneten Dokument The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)