3

C で openssl を使用して簡単な例を作成しました。メッセージから MD4 ハッシュを計算したかったのですが、結果を 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

1 に答える 1

5

まず、 への呼び出しで、および配列MD4()に誤ったアドレスが提供されます。 を使用すると、最初の文字のアドレスではなく、配列のアドレス ( ) が取得されます。とを明示的にキャストしているため、コンパイラは警告しません。キャストを削除すると、次の警告が表示されます。stringdigest&char **&string&digestunsigned char*

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

したがって、代わりに次のように呼び出しますMD4()

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

個人的には、本当に必要な場合を除き、ポインタを明示的にキャストすることは避けたいと考えています。そうすれば、間違った型キャストをはるかに簡単に見つけることができます。

次に、 を使用して 16 進数の整数sprintf()に変換しようとします: . ここで 2 つの問題があります: (a)は本質的に文字ポインタ、つまりメモリ アドレスであるため、このアドレスを符号なし整数に変換してから、その整数を 16 進数に変換しています。(b) の要素をループして、それぞれを文字に変換する必要がありますが、これは行いません!digestsprintf(test, "%02x", (unsigned int)digest);digestdigestsnprintf

間違いを犯したことを考えると、あなたは C に比較的慣れていないかもしれませんが、落胆しないでください。間違いを犯すことは学ぶ方法です。:)

本を買う余裕があれば、Stephen Prata の「C Primer Plus」を強くお勧めします。これは、プログラミングを始める人にとって素晴らしい入門書であり、言語に慣れてきた後で使用するための非常に完全なリファレンスです。それ以外の場合は、オンラインで多くの資料があり、「C ポインター チュートリアル」をグーグルで検索すると、いくつかの有用な結果が返されます。

お役に立てれば!


編集:

機能するコードの他のスニペットについてコメントするのを忘れましたが、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);

openssl のマンページにMD4() 、ハッシュの長さが 16 バイトであると記載されています。これと、各 unsigned char が 0 ~ 255 の値を保持できるという事実を知っていると、個々の要素の最大 16 進表現digestは 0xFF、つまり、unsigned char ごとに 2 つの ASCII 文字になります。

msString(33)のサイズが不可解に見える理由MD4_DIGEST_LENGTHは、配列のサイズを計算するために使用する必要があるためですdigest。文字列を終了するために + 1 つの null ターミネータ ('\0')内の各要素を表すために 2 文字が必要です。 :

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

sprintfmdStringから 1 バイトが供給されるたびに2 文字を配列に出力するため、 の位置ごとdigestに 2 つのインデックス位置を進める必要があるため、 を使用します。以下は、 を使用した場合と同じ結果になります。mdStringdigesti * 2i * 2

for(int i = 0, j = 0; i < MD4_DIGEST_LENGTH; i++, j += 2)
     sprintf(&mdString[j], "%02x", (unsigned int)digest[i]);
于 2013-07-13T18:34:43.880 に答える