MD5 Hash erzeugen



  • Ich habe mir eine string Funktion geschrieben die einen MD5 Hash zurückgeben soll.
    In dieser string Funktion ist der Wert szRandomString schon vorgegeben und daraus möchte ich gerne den Hash erzeugen.
    Das Snippet in der Funktion sieht wie folgt aus:

    HCRYPTPROV hCryptProv;
    HCRYPTHASH hHash;
    LPCSTR cKeyContainer = "KeyContainer";
    BYTE *pbBuffer = (BYTE *)szRandomString.c_str();
    DWORD dwBufferLen = strlen((char *)pbBuffer)+1;
    
    CryptAcquireContext(&hCryptProv, cKeyContainer, NULL, PROV_RSA_FULL, 0);
    CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash);
    CryptHashData(hHash, pbBuffer, dwBufferLen, 0);
    
    return string(reinterpret_cast<char *>(pbBuffer));
    

    Allerdings bekomme ich keinen MD5 hash zurück,
    sondern den ganz normalen Wert von szRandomString. Was mache ich da falsch?



  • Jede der Funktionen gibt einen Rückgabewert zurück. Den solltest du dir als Erstes anschauen. Bin mir zu 80% sicher, dass du danach auch den Fehler entdeckst.

    Edit: Ich tippe mal auf einen Fehler beim Öffnen/Lesen des Keyset:
    CryptAcquireContext(&hCryptProv, cKeyContainer, NULL, PROV_RSA_FULL, 0);
    Sollte das wirklich so sein, gib CRYPT_NEWKEYSET anstatt 0 an.



  • Habe von allen 3 Funktionen den Rückgabewert überprüft, war immer TRUE.
    CRYPT_NEWKEYSET habe ich auch mal mit der 0 ausgewechselt, aber ich bekomme immer noch den ganz normalen Wert von szRandomString.



  • CryptHashData() schreibt den Hash-Wert auch nur in das Hash-"Objekt" rein, ohne die übergebenen Daten zu verändern. Um dein Ergebnis abzuholen, brauchst du CryptGetHashParam()





  • Hab mir das Beispeil auch mal angeguckt. Aber habe immer noch Probleme.
    Das hab ich bis jetzt:

    #include <iostream>
    #include <Windows.h>
    #include <Wincrypt.h>
    #include <string>
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
    	HCRYPTPROV hCryptProv = NULL;
        HCRYPTHASH hOriginalHash;
    	HCRYPTHASH hHash;
        DWORD dwHashLen;
        DWORD dwHashLenSize = sizeof(DWORD);
    	BYTE *pbHash;
    	std::string szString = "TestString";
    
    	if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0))
    	{
    		cout << GetLastError() << endl;
    	}
    	if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hOriginalHash))
    	{
    		cout << GetLastError() << endl;
    	}
    	if(!CryptHashData(hOriginalHash, (BYTE*)szString.c_str(), sizeof(szString.c_str()), 0))
    	{
    		cout << GetLastError() << endl;
    	}
    	if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0))
    	{
            cout << GetLastError() << endl;
        }
    
    	//Speicher allokieren
    	pbHash = new BYTE* [sizeof(dwHashLen)];
    
    	if(!CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &dwHashLen, 0))
    	{
            cout << GetLastError() << endl;
        }
    
    	system("PAUSE");
    	return 0;
    }
    

    Probleme habe ich beim Speicher allokieren und ich weiß kein bisschen wie ich pbHash(also meinen erzeugten MD5 hash) hinterher ausgeben kann.



  • In Zeile 36 ist ein Stern zu viel.

    Zum Ausgeben des Hash-Wertes kannst du eine Schleife verwenden (und die richtigen Format-Flags auf dem Stream:

    cout<<hex<<setfill('0');
    for(int i=0;i<dwHashLen;++i)
      cout<<setw(2)<<(int)pbHash[i];
    


  • Danke, sieht nun so aus:

    #include <iostream>
    #include <Windows.h>
    #include <Wincrypt.h>
    #include <string>
    #include <iomanip>
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
        HCRYPTPROV hCryptProv = NULL;
        HCRYPTHASH hOriginalHash;
        HCRYPTHASH hHash;
        DWORD dwHashLen;
        DWORD dwHashLenSize = sizeof(DWORD);
        BYTE *pbHash;
        std::string szString = "TestString";
    
        if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0))
        {
            cout << GetLastError() << endl;
        }
        if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hOriginalHash))
        {
            cout << GetLastError() << endl;
        }
        if(!CryptHashData(hOriginalHash, (BYTE*)szString.c_str(), sizeof(szString.c_str()), 0))
        {
            cout << GetLastError() << endl;
        }
        if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0))
        {
            cout << GetLastError() << endl;
        }
    
        //Speicher allokieren
        pbHash = new BYTE [sizeof(dwHashLen)];
    
        if(!CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &dwHashLen, 0))
        {
            cout << GetLastError() << endl;
        }
    
    	cout << hex << setfill('0');
    	for(unsigned int i = 0; i < dwHashLen; ++i)
    	{
    		cout << setw(2) << (int)pbHash[i];
    	}
        system("PAUSE");
        return 0;
    }
    

    Aber es wird mir alles andere als ein MD5 hash ausgegeben, das Programm spinnt bei der Ausgabe total, unbeschreiblich. 😕
    Vielleicht kann es ja mal jemand testen und mir wäre es lieber den kompletten hash nochmals in eine char Variable zu speicher, so das ich nicht immer die for schleife zum ausgeben benutzen muss.



  • Wie äußert sich denn dieses "spinnt total"? Und hast du das Verhalten mal im Debugger verfolgt?

    (außerdem: Wenn einer der vorigen Aufrufe schiefgegangen ist, solltest du besser komplett abbrechen)

    Was ich vorhin noch übersehen habe: Die benötigte Größe des Hash-Wertes steht in deinem dwHashLen und nicht in sizeof(dwHashLen) (letzteres ist eine Konstante, die der Compiler bereits beim Übersetzen kennt und ersetzt).



  • Das spuckt der Debugger aus:

    "MD5.exe": "G:\C++\MD5\Debug\MD5.exe" geladen, Symbole wurden geladen.
    "MD5.exe": "C:\Windows\System32\ntdll.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\kernel32.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\KernelBase.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\advapi32.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\msvcrt.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\sechost.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\rpcrt4.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Program Files\CheckPoint\ZAForceField\Plugins\ISWSHEX.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\winsxs\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.5592_none_d09196c24426e2d4\msvcr80.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\user32.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\gdi32.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\lpk.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\usp10.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\wintrust.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\crypt32.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\msasn1.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\winsxs\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.5592_none_d09196c24426e2d4\msvcp80.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\ole32.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\imm32.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\msctf.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\ntmarta.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\Wldap32.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\cryptsp.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\rsaenh.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\sspicli.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\userenv.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\profapi.dll" geladen, Cannot find or open the PDB file
    "MD5.exe": "C:\Windows\System32\cryptbase.dll" geladen, Cannot find or open the PDB file
    Eine Ausnahme (erste Chance) bei 0x74fa35b6 in MD5.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x0000002c.
    Eine Ausnahme (erste Chance) bei 0x757d9617 in MD5.exe: Microsoft C++-Ausnahme: std::bad_alloc an Speicherposition 0x0037fca0..
    Unbehandelte Ausnahme bei 0x757d9617 in MD5.exe: Microsoft C++-Ausnahme: std::bad_alloc an Speicherposition 0x0037fca0..
    

    Kann damit recht wenig anfangen. 😕



  • Kannst du denn zurückverfolgen, welcher Aufruf den Fehler

    Eine Ausnahme (erste Chance) bei 0x74fa35b6 in MD5.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x0000002c.

    auslöst? (zur Not setzt du einen Breakpoint auf den Anfang und gehst im Einzelschritt-Verfahren durch)

    PS: sizeof(szString.c_str()) ist Nonsens - dort benötigst du szString.size() , beim Revervieren von pbHash ist das sizeof() ebenfalls überflüssig.



  • Habs nun mal angepasst doch es kommt immer noch der fehler... die Aufrufliste gibt mir das aus:

    KernelBase.dll!757d9617() 	
    [Unten angegebene Rahmen sind möglicherweise nicht korrekt und/oder fehlen, keine Symbole geladen für KernelBase.dll]	
    KernelBase.dll!757d9617() 	
    MD5.exe!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo)  Zeile 157	C++
    MD5.exe!operator new(unsigned int size)  Zeile 64	C++
    MD5.exe!operator new[](unsigned int count)  Zeile 6 + 0x9 Bytes	C++
    MD5.exe!main(int argc, char * * argv)  Zeile 37 + 0x9 Bytes	C++
    MD5.exe!__tmainCRTStartup()  Zeile 278 + 0x19 Bytes	C
    MD5.exe!mainCRTStartup()  Zeile 189	C
    kernel32.dll!76e81194() 	
    ntdll.dll!7742b429() 	
    ntdll.dll!7742b3fc()
    

    Ausserdem wird die new.cpp geöffnet und dieser Ausschnitt gezeigt:

    #else  /* _SYSCRT */
    
    #include <cstdlib>
    #include <new>
    
    _C_LIB_DECL
    int __cdecl _callnewh(size_t size) _THROW1(_STD bad_alloc);
    _END_C_LIB_DECL
    
    void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
            {       // try to allocate size bytes
            void *p;
            while ((p = malloc(size)) == 0)
                    if (_callnewh(size) == 0)
                    {       // report no memory
                    static const std::bad_alloc nomem;
                    _RAISE(nomem);
                    }
    
            return (p);
            }
    
    /*
     * Copyright (c) 1992-2002 by P.J. Plauger.  ALL RIGHTS RESERVED.
     * Consult your license regarding permissions and restrictions.
     V3.13:0009 */
    #endif  /* _SYSCRT */
    ]
    


  • Keiner ne Idee? Ich komm echt nicht weiter.
    Syntaktisch ist der Quelltext doch eigendlich in Ordnung?

    #include <iostream>
    #include <Windows.h>
    #include <Wincrypt.h>
    #include <string>
    #include <iomanip>
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
    	HCRYPTPROV hCryptProv = NULL;
        HCRYPTHASH hOriginalHash;
    	HCRYPTHASH hHash = NULL;
        DWORD dwHashLen;
        DWORD dwHashLenSize = sizeof(DWORD);
    	BYTE *pbHash;
    	std::string szString = "TestString";
    
    	if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0))
    	{
    		cout << GetLastError() << endl;
    	}
    	if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hOriginalHash))
    	{
    		cout << GetLastError() << endl;
    	}
    	if(!CryptHashData(hOriginalHash, (BYTE*)szString.c_str(), szString.size(), 0))
    	{
    		cout << GetLastError() << endl;
    	}
    	if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0))
    	{
            cout << GetLastError() << endl;
        }
    
    	//Speicher allokieren
    	pbHash = new BYTE [dwHashLen];
    
    	if(!CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &dwHashLen,0))
    	{
            cout << GetLastError() << endl;
        }
    
    	cout << hex << setfill('0');
    	for(unsigned int i = 0; i < dwHashLen; ++i)
    	{
    		cout << setw(2) << (int)pbHash[i];
    	}
    	system("PAUSE");
    	return 0;
    }
    


  • In Zeile 31 verwendest den Input-Parameter hHash , der nicht initialisiert ist. Das zieht eine Reihe von fehlerhaften Prozeduren nach sich:
    - keine gültige Hash-Größe in dwHashLen (dieselbe Zeile)
    - fehlerhaft bzw. nicht allokierter Speicher in Zeile 37
    - keine gültige Ausgabe in pbHash (Zeile 39)
    Daraus resultiert Speicherzugriffsverletzung in der letzten for-Schleife.
    mal abgesehen davon, dass du durch deine Fehlerausgaben gar nicht erfahren würdest, in welcher der Funktionen der Fehler aufgetaucht ist, musst du diesen Parameter initialisieren. In der ersten Version hattest du es schon fast teilweise richtig. Die Lösung also: hOriginalHash durch hHash ersetzen. (Wozu hast du eigentlich das Erstere überhaupt genommen?) Folgendes sollte auch bei dir funktionieren:

    #include <iostream>
    #include <Windows.h>
    #include <Wincrypt.h>
    #include <string>
    #include <iomanip>
    
    using namespace std;
    
    int main(int argc, char *argv[])
    {
        HCRYPTPROV hCryptProv = NULL;
        HCRYPTHASH hHash = 0;
        DWORD dwHashLen;
        DWORD dwHashLenSize = sizeof(DWORD);
        BYTE *pbHash;
        string szString = "TestString";
    
        if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0))
    		cout << "1: " << GetLastError() << endl;
    
        if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash))
            cout << "2: " << GetLastError() << endl;
    
        if(!CryptHashData(hHash, (BYTE*)szString.c_str(), sizeof(szString.c_str()), 0))
            cout << "3: " << GetLastError() << endl;
    
        if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0))
            cout << "4: " << GetLastError() << endl;
    
        //Speicher allokieren
        pbHash = new BYTE [sizeof(dwHashLen)];
    
        if(!CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &dwHashLen, 0))
            cout << GetLastError() << endl;
    
        cout << hex << setfill('0');
        for(unsigned int i = 0; i < dwHashLen; i++)
            cout << setw(2) << (int)pbHash[i];
    
        system("PAUSE");
        return 0;
    }
    

    Grüße,
    Rewind.


  • Mod



  • Danke an alle die sich die Mühe gemacht haben um mir zu helfen.
    Es klappt nun perfekt, doch eine Frage habe ich noch.
    Wie kann ich den MD5 Hash einmalig in einen string abspeichern und dann z.B in einer Funktion als Rückgabewert zurückgeben lassen? Ich hatte nicht vor ihn ausgeben zu lassen mit einer Forschleife.
    Finde keinen Ansatz wie ich es realisieren könnte.



  • Du hast den Hash doch nach dem CryptGetHashValue()-Aufruf in einem Array vorliegen - damit kannst du natürlich machen, was immer du für richtig hältst.
    Wenn du die Hex-Darstellung in einem String haben willst, kannst du cout einfach durch einen std::ostringstream ersetzen und am Ende die Ausgaben dort rausziehen. Wenn du ihn in binärer Form haben willst, kannst du ihn direkt an den Konstruktor eines std::string übergeben (oder auch std::vector<BYTE>).



  • Danke, habs nun so:

    std::ostringstream osHash;
    std::string szHash;
    for(unsigned int i = 0; i < dwHashLen; i++)
    {
    	osHash << (int)pbHash[i];
    }
    szHash = osHash.str();
    return std::string(szHash);
    

    Läuft auch so weit so gut, ein string wird zurück gegeben, jedoch nicht der MD5 hash. 😕 😕 😕 😕 😕
    Der string ist immer etwas länger als ein MD5 hash.



  • Jetzt müsstest du nur doch die Formatierungen übernehmen, die du oben auf cout angewendet hast (hex, setfill() und setw()) - momentan schreibst du die Bytes dezimal und ohne Lücke hintereinander weg.


Anmelden zum Antworten