摘要算法:使用 openssl 实现 md5、sha256 等

摘要算法:使用 openssl 实现 md5、sha256 等

相关链接:

摘要算法:MD5 及 Java实现样例

摘要算法:SHA 及 Java 实现样例

本文主要介绍如何使用 openssl 库实现 md5、sha256 摘要算法。

Case 1:md5

#include 
#include 
#include 

int main(int argc, char *argv[])
{
    EVP_MD_CTX mdctx;
    const EVP_MD *md;
    unsigned char md_value[EVP_MAX_MD_SIZE];
    int md_len, i;

    OpenSSL_add_all_digests();

/*********************************************************************/
    char *algorithm = "md5";
    char *msg = "0123456789abcdef";
    md = EVP_get_digestbyname(algorithm);
    if(!md) {
        fprintf(stderr, "Unknown message digest %s\n", algorithm);
        exit(1);
    }

    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, md, NULL);
    EVP_DigestUpdate(&mdctx, msg, strlen(msg));
    EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
    EVP_MD_CTX_cleanup(&mdctx);

    for(i = 0; i < md_len; i++) {
        fprintf(stdout, "%02x", md_value[i]);
    }
    fprintf(stdout, "\n");

    return 0;
}

编译 && 执行:

$ gcc -o main main.c -lssl
$ ./main
4032af8d61035123906e58e067140cc5

PS:摘要散列值以十六进制小写字符串表示。

可以将 algorithm 改为sha256、sha224、sha512 等值以实现不同摘要算法。

Case 2:sha224

更新:

char *algorithm = "sha224";

编译 && 执行:

$ gcc -o main main.c -lssl
$ ./main
7330215f6741fd2bacbd3658681a70f65e2e90a02887989018974ce8

关于 openssl 的两个函数:

int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt);
    EVP_DigestUpdate() hashes cnt bytes of data at d into the digest context ctx.
    This function can be called several times on the same ctx to hash additional data.

int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s);
    EVP_DigestFinal_ex() retrieves the digest value from ctx and places it in md.
    If the s parameter is not NULL then the number of bytes of data written (i.e. the length of the digest) will be written to the integer at s, at most EVP_MAX_MD_SIZE bytes will be written.
    After calling EVP_DigestFinal_ex() no additional calls to EVP_DigestUpdate() can be made, but EVP_DigestInit_ex() can be called to initialize a new digest operation.

我们可以多次调用 EVP_DigestUpdate() 来 append 待摘要的数据到末尾,并通过调用 EVP_DigestFinal_ex 获取最后结果。

例如:

#include 
#include 
#include 

int main(int argc, char *argv[])
{
    EVP_MD_CTX mdctx;
    const EVP_MD *md;
    unsigned char md_value[EVP_MAX_MD_SIZE];
    int md_len, i;

    OpenSSL_add_all_digests();

/*********************************************************************/
    char *algorithm = "md5";
    char *msg1 = "0123";
    char *msg2 = "4567";
    char *msg3 = "89ab";
    char *msg4 = "cdef";
    md = EVP_get_digestbyname(algorithm);
    if(!md) {
        fprintf(stderr, "Unknown message digest %s\n", algorithm);
        exit(1);
    }

    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, md, NULL);
    EVP_DigestUpdate(&mdctx, msg1, strlen(msg1));
    EVP_DigestUpdate(&mdctx, msg2, strlen(msg2));
    EVP_DigestUpdate(&mdctx, msg3, strlen(msg3));
    EVP_DigestUpdate(&mdctx, msg4, strlen(msg4));
    EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
    EVP_MD_CTX_cleanup(&mdctx);

    for(i = 0; i < md_len; i++) {
        fprintf(stdout, "%02x", md_value[i]);
    }
    fprintf(stdout, "\n");

    return 0;
}

等价于上面的一次性传入完成的待摘要的数据。

编译 && 执行:

$ gcc -o main main.c -lssl
$ ./main
4032af8d61035123906e58e067140cc5

注意:

上面的示例代码其实并不严谨,使用了 strlen 去对待摘要数据计算长度,这里限制了待摘要数据一定不能包含 0x00 字节。

实际上,待摘要数据并无此限制,待摘要数据可以包含任意数据(包括 0x00),并由最后的长度参数指明数据长度。

待摘要数据是任意的二进制数据,可读的字符串只是其中一种,还有不可读的图片、音频、文件等形式。使用 strlen 将有问题。


参考链接:https://linux.die.net/man/3/evp_get_digestbyname

你可能感兴趣的:(C-C++,Linux,其他分类,编解码,加解密,摘要,openssl,md5,sha256,sha,hash)