[英]sha1 example in C using openssl library
我有一个用 C 编写的最简单的sha256
示例,使用 openSSL 库。
// compile with: gcc -o sha256 sha256.c -lcrypto
#include <openssl/sha.h>
#include <stdio.h>
int main(int argc, char **argv)
{
unsigned char buffer[BUFSIZ];
FILE *f;
SHA256_CTX ctx;
size_t len;
if (argc < 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
f = fopen(argv[1], "r");
if (!f) {
fprintf(stderr, "couldn't open %s\n", argv[1]);
return 1;
}
SHA256_Init(&ctx);
do {
len = fread(buffer, 1, BUFSIZ, f);
SHA256_Update(&ctx, buffer, len);
} while (len == BUFSIZ);
SHA256_Final(buffer, &ctx);
fclose(f);
for (len = 0; len < SHA256_DIGEST_LENGTH; ++len)
printf("%02x", buffer[len]);
putchar('\n');
return 0;
}
我需要相同的sha1
,但我找不到实际有效的类似简单示例。 将上述代码中出现的SHA256
替换为SHA1
的天真方法不起作用(显然)。
如何针对SHA1
修改我的程序?
正如@dbush 所建议的,我使用了他的EVP
代码,并将其集成到我的程序中。 我的程序现在看起来像这样:
#include <stdio.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/err.h>
int main(int argc, char **argv)
{
FILE *f;
size_t len;
unsigned char buffer[BUFSIZ];
if (argc < 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
f = fopen(argv[1], "r");
if (!f) {
fprintf(stderr, "couldn't open %s\n", argv[1]);
return 1;
}
EVP_MD_CTX hashctx;
//EVP_MD *hashptr = EVP_get_digestbyname("SHA256");
EVP_MD *hashptr = EVP_get_digestbyname("SHA1");
EVP_MD_CTX_init(&hashctx);
EVP_DigestInit_ex(&hashctx, hashptr, NULL));
do {
len = fread(buffer, 1, BUFSIZ, f);
EVP_DigestUpdate(&hashctx, buffer, len);
} while (len == BUFSIZ);
EVP_DigestFinal_ex(&hashctx, buffer, &len);
EVP_MD_CTX_cleanup(&hashctx);
fclose(f);
int i;
for (i = 0; i < len; ++i)
printf("%02x", buffer[i]);
return 0;
}
当我使用gcc -o evp evp.c -lcrypto
编译它时,出现了几个错误,例如:
evp.c: In function ‘main’:
evp.c:29:19: warning: initialization discards ‘const’ qualifier from pointer target type [enabled by default]
evp.c:32:43: error: expected ‘;’ before ‘)’ token
evp.c:32:43: error: expected statement before ‘)’ token
evp.c:39:1: warning: passing argument 3 of ‘EVP_DigestFinal_ex’ from incompatible pointer type [enabled by default]
In file included from evp.c:4:0:
/usr/include/openssl/evp.h:574:5: note: expected ‘unsigned int *’ but argument is of type ‘size_t *’
不使用SHA1或SHA256特定函数,而是使用EVP_Digest*
函数系列,它们可以处理任何散列。
...
// makes all algorithms available to the EVP* routines
OpenSSL_add_all_algorithms();
// load the error strings for ERR_error_string
ERR_load_crypto_strings();
EVP_MD_CTX hashctx;
//const EVP_MD *hashptr = EVP_get_digestbyname("SHA256");
const EVP_MD *hashptr = EVP_get_digestbyname("SHA1");
EVP_MD_CTX_init(&hashctx);
EVP_DigestInit_ex(&hashctx, hashptr, NULL);
do {
len = fread(buffer, 1, BUFSIZ, f);
EVP_DigestUpdate(&hashctx, buffer, len);
} while (len == BUFSIZ);
unsigned int outlen;
EVP_DigestFinal_ex(&hashctx, buffer, &outlen);
EVP_MD_CTX_cleanup(&hashctx);
fclose(f);
int i;
for (i = 0; i < outlen; ++i)
printf("%02x", buffer[i]);
为简洁起见,我省略了错误检查。 要检查错误,请执行以下操作:
if (function_to_check() == 0) {
char errstr[1000];
ERR_error_string(ERR_get_error(), errstr);
printf("error: %s\n", errstr;
}
编辑:
上面的代码中有一些错误已得到纠正:
hashptr
被声明为EVP_MD *
,现在是const EVP_MD *
。 EVP_DigestInit_ex
的调用EVP_DigestInit_ex
有一个额外的括号 EVP_DigestFinal_ex
的第三个参数专门给出了unsigned int *
而不是size_t *
,它们可能不一定相同。 你可以这样做: -
#include <openssl/sha.h>
#include <stdio.h>
int main(int argc, char **argv)
{
unsigned char buffer[BUFSIZ];
FILE *f;
SHA_CTX ctx;
size_t len;
if (argc < 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
f = fopen(argv[1], "r");
if (!f) {
fprintf(stderr, "couldn't open %s\n", argv[1]);
return 1;
}
SHA1_Init(&ctx);
do {
len = fread(buffer, 1, BUFSIZ, f);
SHA1_Update(&ctx, buffer, len);
} while (len == BUFSIZ);
SHA1_Final(buffer, &ctx);
fclose(f);
for (len = 0; len < SHA_DIGEST_LENGTH; ++len)
printf("%02x", buffer[len]);
putchar('\n');
return 0;
}
随着 OpenSSL 更新到 3.0,大多数解决方案将无法使用(因为 API 已弃用),建议使用EVP
函数。 下面的代码显示了我根据OpenSSL 的官方文档对EVP的看法
此实现使用纯C
并在Ubuntu 22.04
上验证
/**
* Simple program to calculate message digest using openssl'l new EVP method
*
* Verified on Ubuntu 22.04 on Jan 29, 2023
*
* Install dependency:
* sudo apt install make gcc libssl-dev -y
*
* To compile:
* gcc sha256sum.c -o shasum.out -lcrypto
*
* To cross verify:
* echo -n "Hello world" | sha256sum
*
* Author: Daniel Selvan D. <danilselvan@gmail.com>
*/
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
// OpenSSL engine implementation
#define OPENSSL_ENGINE NULL
/**
* Returns the SHA256 value of the input string
*
* @param string input string for which the hash to be calculated
* @returns string (32 bytes) - SHA256 hash
*/
static const unsigned char *getShaSum(const unsigned char *string)
{
EVP_MD_CTX *mdCtx = EVP_MD_CTX_new();
unsigned char mdVal[EVP_MAX_MD_SIZE], *md;
unsigned int mdLen, i;
if (!EVP_DigestInit_ex(mdCtx, EVP_sha256(), OPENSSL_ENGINE))
{
printf("Message digest initialization failed.\n");
EVP_MD_CTX_free(mdCtx);
exit(EXIT_FAILURE);
}
// Hashes cnt bytes of data at d into the digest context mdCtx
if (!EVP_DigestUpdate(mdCtx, string, strlen((const char *)string)))
{
printf("Message digest update failed.\n");
EVP_MD_CTX_free(mdCtx);
exit(EXIT_FAILURE);
}
if (!EVP_DigestFinal_ex(mdCtx, mdVal, &mdLen))
{
printf("Message digest finalization failed.\n");
EVP_MD_CTX_free(mdCtx);
exit(EXIT_FAILURE);
}
EVP_MD_CTX_free(mdCtx);
printf("DEBUG: Digest is: ");
for (i = 0; i < mdLen; i++)
printf("%02x", mdVal[i]);
printf("\n");
md = mdVal;
return md;
}
int main()
{
// To calculate the hash of a file, read it and pass the pointer
getShaSum("Hello world");
exit(EXIT_SUCCESS);
}
这个更高级别接口的优点是您只需将EVP_sha256()
调用换成另一个摘要的 function,例如EVP_sha1()
,即可使用不同的摘要。
参考官方文档 - https://www.openssl.org/docs/man1.0.2/man3/EVP_sha512.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.