sha-3 Referenz-Implementierung (Keccak)



  • Ich versuche Hashwerte mit Hilfe der sha-3 Referenz-Implementierung zu erzeugen.
    Allerdings sehen die erzeugten Hashwerte falsch aus, da

    • die Erzeugten Hashwerte stimmen nicht mit Referenzwerten überein
    • die Erzeugten Hashwerte enthalten auffällig viel Werte 0x00 und 0xff unabhängig vom zu hashenden Wert

    Die Referenz-Implementierung habe ich mir von http://keccak.noekeon.org/files.html (Version 3.2) heruntergeladen.

    Referenzwerte: http://www.di-mgt.com.au/sha_testvectors.html und https://en.wikipedia.org/wiki/SHA-3.

    Mein Programm sieht wie folgt aus:

    extern "C"
    {
    #include "Keccak/KeccakNISTInterface.h"
    }
    
    #include <string>
    #include <sstream>
    #include <iomanip>
    #include <vector>
    #include <cassert>
    
    void TestSha224(const string& s)
    {
    	const int hashBitLength  = 224;
    	const int hashByteLength = 224/8;
    	const int bitLength      = static_cast<int>(s.length()*8);
    
    	vector<unsigned char> hash(hashByteLength,0xcd);
    	const HashReturn hasReturn = Hash(hashBitLength,reinterpret_cast<const unsigned char*>(s.data()),bitLength,hash.data());
    
    	ostringstream stream;
    	for(vector<unsigned char>::size_type i=0;i<hash.size();++i)
    		stream << hex << (int)hash[i];
    
    	const string sha = stream.str();
    }
    
    int main(int argc,const char* argv[])
    {
    	const string s = "";
    	TestSha224(s);
    
    	return 0;
    }
    

    Als Hashwert für "" (Leer-String) erhalte ich so "c81e9024ffffff7f74320f1ffffffff7dfc5d2000000a075".

    Ich denke ich habe irgendwo einen recht einfachen Fehler; sehe ihn aber nicht 😎

    Vielleicht kennt sich ja jemand mit Keccak aus und kann mir weiterhelfen.



  • Erstmal... wo gibst du den Hash aus?

    Dann änder mal:

    HashTest schrieb:

    for(vector<unsigned char>::size_type i=0;i<hash.size();++i)
    		stream << " " << hex << (int)hash[i];
    

    Das dürfte dir helfen... 😉
    (du musst für jedes Byte 2 Hex-Stellen ausgeben)

    PS: Und die Implementierung berechnet keccak... nicht sha3! (Das Padding unterscheidet sich bei den beiden.)
    Wenn ich mich nicht täusche sollte keccak-224("") == "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd" sein.

    EDIT: Hab gerade mal die Ref-Impl und deine main genommen... alles so angepasst das es kompiliert und dann kommt (bis auf die fehlerhafte "Aus"-gabe) das richtige Ergebnis.
    Hast du irgendetwas in der Implementierung geändert? Welche hast du ausgewählt?



  • Danke für den Hinweis. Ich hatte als Grundlage die "...-opt-64" Implementierungen genommen. Mit der Referenz Implementierung erhalte ich einen für mich erstmal gut aussehenden Hash der mit den Keccak Haswerten übereinstimmt.
    Den Hashwert hatte ich mir nicht ausgegeben, sondern nur im Debugger angesehen.

    Hast du für mich ein Beispiel für das Padding?

    Ich habe versucht aus dem Test-Programm (https://github.com/gvanas/KeccakCodePackage/blob/master/Tests/main.c) die Padding Berechnung (Methode "appendSuffixToMessage()") zu übernehmen. Ich bekomme auch einen anderen Hashwert. Dieser stimmt allerdings nicht mit den sha-3 Hashwerten überein.

    Das sieht jetzt so aus:

    extern "C"
    {
    #include "Keccak/KeccakSponge.h"
    #include "Keccak/KeccakNISTInterface.h"
    }
    //#include <iostream>
    #include <string>
    #include <memory>
    #include <sstream>
    #include <iomanip>
    #include <vector>
    #include <cassert>
    
    using namespace std
    
    // Methode aus https://github.com/gvanas/KeccakCodePackage/blob/master/Tests/main.c
    unsigned int appendSuffixToMessage(unsigned char *out, const unsigned char *in, unsigned int inputLengthInBits, unsigned char delimitedSuffix)
    {
        memcpy(out, in, (inputLengthInBits+7)/8);
        if (delimitedSuffix == 0x00)
            abort();
        while(delimitedSuffix != 0x01) {
            unsigned char bit = delimitedSuffix & 0x01;
            out[inputLengthInBits/8] |= (bit << (inputLengthInBits%8));
            inputLengthInBits++;
            delimitedSuffix >>= 1;
        }
        return inputLengthInBits;
    }
    
    void TestSha3_Suffix(const string& s)
    {
    	const int hashBitLength     = 512;
    	const int hashByteLength    = hashBitLength/8;
    	const int bitLength         = s.length()*8;
    	const int messageByteLength = (bitLength+15)/8; // Berechnung aus https://github.com/gvanas/KeccakCodePackage/blob/master/Tests/main.c, displaySpongeIntermediateValuesOne(), Zeile 132
    	const int messageBitLength  = static_cast<int>(messageByteLength*8);
    
    	//vector<unsigned char> message(messageByteLength,0x06);
    	//memcpy(message.data(),s.data(),s.length());
    	unique_ptr<unsigned char> message(new unsigned char[messageByteLength]);
    	memset(message.get(),0,messageByteLength);
    	const unsigned int ms = appendSuffixToMessage(message.get(),reinterpret_cast<const unsigned char*>(s.data()),bitLength,0x06);
    
    	vector<unsigned char> hash(hashByteLength,0xcd);
    	const HashReturn hasReturn = Hash(hashBitLength,message.get(),ms,hash.data());
    
    	ostringstream stream;
    	for(vector<unsigned char>::size_type i=0;i<hash.size();++i)
    		stream << hex << (int)hash[i];
    
    	const string& sha = stream.str();
    }
    
    int main(int argc,const char* argv[])
    {
    	const string s = "";
    	TestSha3_Suffix(s);
    
    	return 0;
    }
    


  • In Hash wird es ja finalisiert. Da kommt das Padding schon dran.
    Das Padding sieht byteweise bei keccak so aus, dass ein Byte 0x01 angehängt wird, dann wird der Block mit 0x00 gefüllt und beim letzten Byte wird das MSB gesetzt.
    Für SHA3 wird nicht 0x01 angehängt, sondern 0x06. (Du musst also in der Referenzimplementierung diesen Wert ändern. Wenn mich nicht alles täuscht PadAndSwitchToSqueezingPhase Zeile 198 und 204.)



  • Ja stimmt. Ich habe es allerdings nicht hinbekommen das Padding so zu verändern, dass ein sha3 Hashwert entsteht.
    Ich habe mir jetzt das aktuelle Quellcode-Paket (statt der Version 3.2) heruntergeladen. Hier hat sich einiges verändert. Es scheint dort auch bereits vorkonfigurierte Aufrufe für sha3 zu geben. Ich habe alles nur überflogen und denke ich schau es mir am Wochenende genauer an.

    Auf jeden Fall Danke für die Hilfe 🙂


Log in to reply