使用libgcrypt计算摘要
libgcrypt编程计算摘要的方式有2种,一种可用来计算小数据的摘要,如字符串; 一种可用来计算大数据的摘要,如文件、网络字节流等
下面的代码示例中用到了 cppcodec 工具库,用于将计算的摘要结果转换成hex十六进制字符串或者base64字符串
使用 libgcrypt 库有一个方便之处就是它已经支持国密算法 sm2、sm3、sm4,不过按照国密标准带公钥计算sm3摘要这种可能没支持,我暂时没找到官网源代码中有这样的示例或说明,这个就得自己封装了
一、计算少量数据摘要
计算少量数据摘要步骤较为简单,一般直接调用 gcry_md_hash_buffer
API就行,参数中有一个指针参数作为输出参数。API gcry_md_get_algo_dlen
用于获取指定摘要算法的摘要长度,一般使用枚举 gcry_md_algos
作为摘要算法名,如
GCRY_MD_SHA1
GCRY_MD_SHA256
GCRY_MD_SM3
等
void calcWay1(const char* buffer) {
int msg_len = strlen(buffer);
int mdLen = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
uint8_t* hash = new uint8_t[mdLen];
gcry_md_hash_buffer(GCRY_MD_SHA1, hash, buffer, msg_len);
std::cout << "十六进制输出: " << hex::encode(hash, mdLen) << std::endl;
std::cout << "base64输出: " << base64::encode(hash, mdLen) << std::endl;
delete[] hash;
}
二、计算大量数据摘要
与 OpenSSL 库作类比,计算大量数据摘要步骤一般固定如下
gcry_md_open
创建摘要计算处理器(上下文),这一点跟 OpenSSL 类似gcry_md_write
多次调用传入数据,如读取文件时,循环读取数据到缓存中,将缓存作为参数循环传入该函数gcry_md_read
获取计算的摘要值gcry_md_close
关闭摘要计算处理器
void calcWay2(const char *buffer) {
gcry_md_algos md_algos = GCRY_MD_SHA1;
int mdLen = gcry_md_get_algo_dlen(md_algos);
gcry_md_hd_t hd = nullptr;
gcry_error_t error = gcry_md_open(&hd, md_algos, 0);
if (error != GPG_ERR_NO_ERROR) {
fprintf(stderr, "gcry_md_open error\n");
exit(1);
}
// 多次调用 gcry_md_write 函数,适用于大数据摘要计算
size_t length = strlen(buffer);
gcry_md_write(hd, buffer, length);
gcry_md_write(hd, buffer, length);
uint8_t* hash = gcry_md_read(hd, md_algos);
std::cout << "十六进制输出: " << hex::encode(hash, mdLen) << std::endl;
std::cout << "base64输出: " << base64::encode(hash, mdLen) << std::endl;
gcry_md_close(hd);
}
在main函数中调用
cppcodec 见文章开头说明,是 github 上一个基于C++的 hex、base32、base64 转换工具
#include <gcrypt.h>
#include <iostream>
#include "cppcodec/base64_rfc4648.hpp"
#include "cppcodec/hex_upper.hpp"
using base64 = cppcodec::base64_rfc4648;
using hex = cppcodec::hex_upper;
void calcWay1(const char *buffer);
void calcWay2(const char *buffer);
int main(int argc, char** argv){
if (argc < 3) {
fprintf(stderr, "Usage: %s arg1 arg2\n", argv[0]);
exit(1);
}
int way = atoi(argv[1]);
if (way == 1) {
calcWay1(argv[2]);
} else if (way == 2) {
calcWay2(argv[2]);
}
return 0;
}