web-dev-qa-db-ja.com

CプログラミングでSHA1ハッシュを使用する方法

SHA1がほぼコリジョンフリーであることを証明するCプログラムを作成しようとしていますが、入力値のハッシュを実際に作成する方法を理解できません。ハッシュを作成し、16進値を配列に保存するだけです。 Googleでいくつか検索した後、これを使用するように指示するOpenSSLのドキュメントを見つけました。

 #include <openssl/sha.h>

 unsigned char *SHA1(const unsigned char *d, unsigned long n,
                  unsigned char *md);

 int SHA1_Init(SHA_CTX *c);
 int SHA1_Update(SHA_CTX *c, const void *data,
                  unsigned long len);
 int SHA1_Final(unsigned char *md, SHA_CTX *c);

Unsigned char * SHA1またはSHA1_Initのいずれかを使用する必要があると思いますが、xがハッシュされる入力であるため、引数がどうなるかはわかりません。誰かが私のためにこれをクリアしてくれませんか?ありがとう。

27
spassen

すべてのデータが一度にある場合は、SHA1 関数:

// The data to be hashed
char data[] = "Hello, world!";
size_t length = strlen(data);

unsigned char hash[SHA_DIGEST_LENGTH];
SHA1(data, length, hash);
// hash now contains the 20-byte SHA-1 hash

一方、データを一度に1つずつしか取得せず、そのデータを受け取ったときにハッシュを計算する場合は、他の関数を使用します。

// Error checking omitted for expository purposes

// Object to hold the current state of the hash
SHA_CTX ctx;
SHA1_Init(&ctx);

// Hash each piece of data as it comes in:
SHA1_Update(&ctx, "Hello, ", 7);
...
SHA1_Update(&ctx, "world!", 6);
// etc.
...
// When you're done with the data, finalize it:
unsigned char hash[SHA_DIGEST_LENGTH];
SHA1_Final(hash, &ctx);
48
Adam Rosenfield

同じことを達成するための2つの異なる方法です。

具体的には、either use SHA_Init、次にSHA_Updateデータを通過させるのに必要な回数だけSHA_Finalダイジェストを取得するには、または you SHA1

2つのモードの理由は、大きなファイルをハッシュするときは、多くのメモリを使用するため、ファイルをチャンクで読み取ることが一般的だからです。したがって、SHA_CTX-SHAコンテキスト-これを回避できます。アルゴリズムは内部的にこのモデルにも適合します-つまり、データは一度にブロックで渡されます。

SHAメソッドは非常に簡単です。その他は次のように機能します。

unsigned char md[SHA_DIGEST_LENGTH];
SHA_CTX context;
int SHA1_Init(&context);

for ( i = 0; i < numblocks; i++ )
{
    int SHA1_Update(&context, pointer_to_data, data_length);
}
int SHA1_Final(md, &context);

重要なのは、最後にmdには16進表現ではなくバイナリダイジェストが含まれることです。これは文字列ではなく、1つとして使用しないでください。

12
user257111

最初の関数(SHA1())は上位レベルの関数であり、おそらく必要な関数です。ドキュメントの使用法はかなり明確です-dが入力、nがそのサイズ、mdが結果の配置場所です(割り当てます)。

他の3つの関数については-これらは低レベルであり、最初の関数によって内部的に使用されると確信しています。これらは、ブロックごとに処理する必要がある大きな入力に適しています。

3
kralyk

このようにハッシュを計算する

// Object to hold the current state of the hash
SHA_CTX ctx;
SHA1_Init(&ctx);

// Hash each piece of data as it comes in:
SHA1_Update(&ctx, "Hello, ", 7);
...
SHA1_Update(&ctx, "world!", 6);
// etc.
...
// When you're done with the data, finalize it:
unsigned char tmphash[SHA_DIGEST_LENGTH];
SHA1_Final(tmphash, &ctx);

最後に、このようなコードでハッシュを人間が読める形式にデコードできます。

unsigned char hash[SHA_DIGEST_LENGTH*2];

int i = 0;
for (i=0; i < SHA_DIGEST_LENGTH; i++) {
    sprintf((char*)&(hash[i*2]), "%02x", tmphash[i]);
}
// And print to stdout
printf("Hash: %s\n", hash);
2
linux_art

unsigned char *SHA1またはSHA1_Init ...

1.0.2や1.1.0などのOpenSSLライブラリの以降のバージョンでは、プロジェクトはEVPインターフェイスの使用を推奨しています。 SHA-256で EVP Message Digests を使用する例は、OpenSSL wikiで入手できます。

#define handleErrors abort

EVP_MD_CTX *ctx;

if((ctx = EVP_MD_CTX_create()) == NULL)
    handleErrors();

if(1 != EVP_DigestInit_ex(ctx, EVP_sha256(), NULL))
    handleErrors();

unsigned char message[] = "abcd .... wxyz";
unsinged int message_len = sizeof(message);

if(1 != EVP_DigestUpdate(ctx, message, message_len))
    handleErrors();

unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int digest_len = sizeof(digest);

if(1 != EVP_DigestFinal_ex(ctx, digest, &digest_len))
    handleErrors();

EVP_MD_CTX_destroy(ctx);
2
jww

Adam Rosenfieldの答えは問題ありませんが、sizeofではなくstrlenを使用してください。そうしないと、nullターミネータを含めてハッシュが計算されます。この場合はおそらく問題ありませんが、ハッシュを他のツールで生成されたハッシュと比較する必要がある場合はそうではありません。

// The data to be hashed
char data[] = "Hello, world!";
size_t length = strlen(data);

unsigned char hash[SHA_DIGEST_LENGTH];
SHA1(data, length, hash);
// hash now contains the 20-byte SHA-1 hash
1
Shadowchaser