2013-07-13 4 views
3

Я написал простой пример с openssl в C. Я хотел вычислить хэш MD4 из моего сообщения, но я хочу сохранить результат в массив символов. Heres мой код с комментариями, которые помогут вам понять, что я хочу добиться:MD4 хэш с openssl, сохранить результат в char char

#include <string.h> 
#include <openssl/md4.h> 
#include <stdio.h> 

int main() 
{ 
    unsigned char digest[MD4_DIGEST_LENGTH]; 
    char string[] = "hello world"; 

    // run md4 for my msg 
    MD4((unsigned char*)&string, strlen(string), (unsigned char*)&digest); 

    // save md4 result into char array - doesnt work 
    char test[MD4_DIGEST_LENGTH]; 
    sprintf(test, "%02x", (unsigned int)digest); 
    for(int i = 0; i < MD4_DIGEST_LENGTH; i++) 
     printf("%02x", test[i]); 
    printf("\n\n"); 

    // print out md4 result - works, but its not intochar array as I wanted it to be 
    for(int i = 0; i < MD4_DIGEST_LENGTH; i++) 
     printf("%02x", digest[i]); 
    printf("\n\n"); 

    // works but i dont understand why 'mdString' is 33 size 
    char mdString[33]; 
    for(int i = 0; i < MD4_DIGEST_LENGTH; i++) 
    // and I also dont get i*2 in this loop 
     sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]); 
    printf("md4 digest: %s\n", mdString); 

    return 0; 
} 

Вопрос в том, почему этот код ниже не работает, он показывает другое значение MD4, чем она должна быть:

char test[MD4_DIGEST_LENGTH]; 
     sprintf(test, "%02x", (unsigned int)digest); 
     for(int i = 0; i < MD4_DIGEST_LENGTH; i++) 
      printf("%02x", test[i]); 
     printf("\n\n"); 

и как я могу узнать, какой размер должен быть mdString и почему i*2 в последнем цикле? Может ли кто-нибудь объяснить это?

ответ

4

Во-первых, ваш вызов MD4() дает неправильный адрес для string и digest массивов: с помощью &, вы получаете адрес массива (char **), а не адрес первого символа. Поскольку вы явно лидируете &string и &digest - unsigned char*, компилятор вас не предупредит. Удалить слепки, и вы получите это предупреждение:

warning: passing argument 1 of 'MD4' from incompatible pointer type

Таким образом, вместо вызова MD4() этот путь:

MD4(string, strlen(string), digest);

Я лично предпочитаю, чтобы избежать явного литья указатели, если только это не является действительно необходимым, таким образом вы поймете неправильное литье типов намного легче.

Затем вы пытаетесь использовать sprintf() для преобразования digest в шестнадцатеричное целое число: sprintf(test, "%02x", (unsigned int)digest);. Здесь нет двух вещей: (a) поскольку digest по существу является указателем на символ, то есть адресом памяти, вы превращаете этот адрес в целое число без знака, а затем поворачиваете , чтобы целое число в hex; (b) вам нужно зациклиться на элементах digest и преобразовать их в символ, snprintf не сделает это за вас!

Я вижу, что вы, возможно, относительно новичок в C, учитывая допущенные ошибки, но не делайте ошибок, делая ошибки - это способ узнать! :)

Если вы можете позволить себе книгу, я настоятельно рекомендую Стивен Прата «C Primer Plus». Это отличное введение для тех, кто начинает программирование, и это очень полная справочная информация для последующего использования, когда вы уже довольны языком. В противном случае, есть много материала в Интернете, а googling «C pointer tutorial» вернет несколько полезных результатов.

Надеюсь, это поможет!


EDIT:

Забыл комментировать другой фрагмент кода, который делает работу, но использует 33 байт для хранения строковой роскопии MD4 хэша:

// works but i dont understand why 'mdString' is 33 size 
char mdString[33]; 
for(int i = 0; i < MD4_DIGEST_LENGTH; i++) 
// and I also dont get i*2 in this loop 
    sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]); 
printf("md4 digest: %s\n", mdString); 

The OpenSSL страница руководство для MD4()states, что хэш имеет длину 16 байт. Зная это, и тот факт, что каждый символ без знака может содержать значение от 0 до 255, то максимальное шестнадцатеричное представление для любого отдельного элемента в digest равно 0xFF, другими словами, 2 символа ASCII для беззнакового символа.

Причина размер msString (33) появляется загадочная, потому что MD4_DIGEST_LENGTH должны были использоваться для вычисления размера массива: вам нужно 2 символов для представления каждого из элементов в digest + 1 нулевой терминатор ('\ 0'), чтобы закончить строку:

char mdString[(MD4_DIGEST_LENGTH * 2) + 1]; 

sprintf напечатает 2 символа в mdString массив всякий раз, когда она подается 1 байт из digest, так что вам нужно заранее 2 позиции индекса в mdString для каждой позиции в digest, следовательно, использование i * 2. Ниже приводится тот же результат, что и при использовании i * 2:

for(int i = 0, j = 0; i < MD4_DIGEST_LENGTH; i++, j += 2) 
    sprintf(&mdString[j], "%02x", (unsigned int)digest[i]); 
+0

спасибо! Но не могли бы вы объяснить, что немного преобразует 'unsigned char digest' в' шестнадцатеричное целое число'? Я не знаю, почему я должен использовать 'i * 2' в моем цикле' sprintf', и как я могу узнать, что результат 'mdString' должен иметь размер 33? – yak

+3

@yak, извините за это, обновил свой первоначальный ответ с объяснением размера критического массива. – easuter

+0

еще раз спасибо! :) У меня только последний вопрос (надеюсь, так;): когда я хочу измерить производительность md5 для сообщения с размером входного файла 512, должен ли я сделать это следующим образом: '// Предположим, что 'txt' имеет длину 64, // поэтому для char его 8 (размер char) * 64 (длина текста) = 512 размер блока char txt = "..."; MD5 (txt, strlen (txt), digest); 'или вот так: ' char txt = "..."; // предположим, что имеет длину 512 MD5 (txt, strlen (txt), digest); '. На вопрос об этом также: http://security.stackexchange.com/questions/38903/openssl-speed-block-size?lq=1, но все отвечают. Спасибо :) – yak

Смежные вопросы