如何在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 *SHA1
或SHA1_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);