如何在C编程中使用SHA1散列

我正在尝试编写一个certificateSHA1几乎无冲突的C程序,但我无法弄清楚如何为我的输入值实际创建哈希。 我只需要创建哈希值,并将hex值存储到一个数组中。 经过一些Google搜索,我发现OpenSSL文档指示我使用它:

#include  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是我要输入的输入。 有人请为我清楚这个吗? 谢谢。

如果您同时拥有所有数据,只需使用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 

另一方面,如果您一次仅获取一个数据,并且希望在接收数据时计算哈希值,则使用其他函数:

 // 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); 

他们是实现同样目标的两种不同方式。

具体来说,您可以使用SHA_Init ,然后根据需要多次使用SHA_Init传递数据,然后使用SHA_Final获取摘要, 或者使用SHA1

两种模式的原因是,当对大文件进行散列时,通常以块的forms读取文件,因为替代方案会占用大量内存。 因此,随时跟踪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将包含二进制摘要,而不是hex表示 - 它不是字符串,不应该用作一个字符串。

第一个函数( SHA1() )是更高级别的函数,它可能是您想要的函数。 文档在用法上非常清楚 – d是输入, n是它的大小, md是放置结果的位置(你分配它)。

至于其他3个function – 这些是较低级别的,我很确定它们在内部被第一个使用。 它们更适合需要以逐块方式处理的较大输入。

我相信我应该使用unsigned char *SHA1SHA1_Init

对于OpenSSL库的更高版本,如1.0.2和1.1.0,项目建议使用EVP接口。 OpenSSL wiki上提供了使用SHA256的EVP消息摘要的示例:

 #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); 

Adam Rosenfield的答案很好,但是使用strlen而不是sizeof,否则将计算hash,包括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 

像这样计算哈希

 // 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); 

最后,您可以通过这样的代码将哈希解码为人类可读的forms。

 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);