2011-10-21 14 views
8

Próbuję napisać funkcję C za pomocą OpenSSL/libcrypto, aby obliczyć sumę SHA256 pliku. Opieram swój kod na przykładzie C++ Adama Lamera: here.Oblicz i wydrukuj skrót SHA256 pliku za pomocą OpenSSL

Oto mój kod:

int main (int argc, char** argv) 
{ 
    char calc_hash[65]; 

    calc_sha256("file.txt", calc_hash); 
} 

int calc_sha256 (char* path, char output[65]) 
{ 
    FILE* file = fopen(path, "rb"); 
    if(!file) return -1; 

    char hash[SHA256_DIGEST_LENGTH]; 
    SHA256_CTX sha256; 
    SHA256_Init(&sha256); 
    const int bufSize = 32768; 
    char* buffer = malloc(bufSize); 
    int bytesRead = 0; 
    if(!buffer) return -1; 
    while((bytesRead = fread(buffer, 1, bufSize, file))) 
    { 
     SHA256_Update(&sha256, buffer, bytesRead); 
    } 
    SHA256_Final(hash, &sha256); 

    sha256_hash_string(hash, output); 
    fclose(file); 
    free(buffer); 
    return 0; 
}  

void sha256_hash_string (char hash[SHA256_DIGEST_LENGTH], char outputBuffer[65]) 
{ 
    int i = 0; 

    for(i = 0; i < SHA256_DIGEST_LENGTH; i++) 
    { 
     sprintf(outputBuffer + (i * 2), "%02x", hash[i]); 
    } 

    outputBuffer[64] = 0; 
} 

Problemem jest to .... przyjrzeć poniżej kwot obliczonych dla pliku Przykład:

Known good SHA256: 6da032d0f859191f3ec46a89860694c61e65460d54f2f6760b033fa416b73866 
Calc. by my code: 6dff32ffff59191f3eff6affff06ffff1e65460d54ffff760b033fff16ff3866 

ja również uzyskać * rozbijając wykryte stos * po zakończeniu wykonywania kodu.

Czy ktoś widzi, co robię źle?

Dzięki!

+0

Mam zgłoszone prototypy. – dan6470

+0

dlaczego const int bufSize jest naprawione o rozmiarze 32768? może to być mniej więcej –

Odpowiedz

12

Wygląda na to, że w twoim pliku wyjściowym znajduje się dużo bloków "0xff", a odpowiednie bloki w dobrym łańcuchu mają ustawiony wysoki bit ... może gdzieś problem z rozszerzeniem znaku.

Czy nawiązanie:

char hash[SHA256_DIGEST_LENGTH]; 

niepodpisany, jak:

unsigned char hash[SHA256_DIGEST_LENGTH]; 

pomoc? (Zwłaszcza w podpisaniu sha256_hash_string.)

+0

To naprawiło to! Dziękuję Ci! Używam gcc w systemie Ubuntu. – dan6470

+1

Moja wypowiedź na temat małej-endianess była zła, więc ją usunąłem ... Adam miał odpowiednie wyjaśnienie, że 8 bajtów jest drukowanych za każdym razem, gdy dane wejściowe były ujemne. Jest to dobry przykład na to, że w przypadku "bajtów", a nie "ciągów znaków", należy użyć "unsigned char" (lub uint8 lub jednego z jego wariantów). Nagie "znaki" powinny być zarezerwowane dla znaków ASCII. –

11

Ty wypisanie podpisałchar jako liczba całkowita. Jeśli bajt jest ujemny, zostaje przekonwertowany na signed int (domyślne promocje w wywołaniu sprintf), a następnie zostaje przekonwertowany na unsigned int (przez specyfikator formatu %x) i wydrukowany.

Tak więc bajt jest -96 jako bajt z podpisem, który zostaje przekonwertowany na -96 jako signed int, który jest 0xFFFFFFA0 w hex, więc zostanie wydrukowany jako FFFFFFA0.

Aby rozwiązać ten problem, sprawa każdy bajt do unsigned char przed wydrukowaniem:

sprintf(..., (unsigned char)hash[i]); 

dostajesz ostrzeżenie o stos rozbijając ponieważ istnieje podpisane bajt pod koniec mieszania, tak piszesz 8 bajtów FFFFFFB7 przy przesunięciu 58, gdy zamierzano zapisać tylko 2 bajty. Powoduje to, że zostanie wykryty tutaj buffer overflow, ponieważ prawdopodobnie kompilator umieścił w stosie obszar ochronny lub plik cookie bezpieczeństwa przed wartością zwracaną, i wykrył, że ten obszar ochronny został nieumyślnie zmodyfikowany.

+0

To wszystko! Dzięki za wyjaśnienie !! – dan6470

Powiązane problemy