繁体   English   中英

C 中的 sha1 示例使用 openssl 库

[英]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 * ,它们可能不一定相同。
  • 在顶部添加了对两个OpenSSL初始化函数的调用

你可以这样做: -

#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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM