首页 > 编程语言 >openssl做HMAC实例(C++)原文

openssl做HMAC实例(C++)原文

时间:2023-11-20 11:45:31浏览次数:47  
标签:CTX openssl C++ 算法 algo 哈希 include HMAC

摘自:https://blog.csdn.net/mijichui2153/article/details/104741460

1、HMAC简介
(1)MAC(Message Authentication Code,消息认证码算法),可以将其认为是含有秘钥的散列(Hash)函数算法;即兼容了MD和SHA算法,并在此基础上加上了秘钥。因此MAC算法也经常被称作HMAC算法。当然HMAC就是“基于Hash的消息认证码”英文(Hash-based Message Authentication Code)的缩写。我个人理解它主要包括两块:一个是信息摘要算法(MD/SHA等);另外就是秘钥。

1)HMAC基于的信息摘要算法。目前主要集合了MD和SHA两大系列消息摘要算法。其中MD系列的算法有HmacMD2、HmacMD4、HmacMD5三种算法;SHA系列的算法有HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512五种算法。

2)秘钥。理论上密钥可以是任何长度,但是一般出于安全强度的考量不建议使用太短的秘钥。也就是说一般情况下要使用摘要算法计算密钥的摘要作为新的密钥。

(2)使用流程。你和对方共享了一个密钥K,你要发消息给对方;这个过程即要保证消息没有被篡改还要能够证明信息确实是你本人发送的。所以处理的方式是:在发送数据以前,HMAC算法对“数据块”+“约定的公钥”进行散列操作并将所生成的“摘要”附加在待发送的数据块中。当原数据块和摘要到达其目的地时,目的端也会使用HMAC算法对原数据块和公钥来生成本地摘要,如果两个摘要相匹配,那么就认为数据未被做任何篡改且消息为约定的对方本人发送。

(3)加深理解。

1)其实通过MD5、SHA1等哈希算法我们可以验证一段数据是否有效,方法就是对比该数据的哈希值。例如判断用户的口令(密码)是否正确我们用保存在数据库中的password_md5对比计算得到的md5(password),如果一致就认为用户输入的密码是正确的。

2)由于用户密码通常会设置的比较简单而且具有普遍性,如果黑客做了足够大的对照表实际上就很有可能反推出真实密码。为了防止黑客通过对照表反推到原始密码,通常在计算哈希的时候会增加一个salt以使得相同的输入(这里指不同用户的相同密码)也能达到不同的哈希(例如将每个用户的唯一id作为salt的一部分),这样就大大的增加了破解难度。

3)实际上我们可以把上面说的salt看做是一个“口令”,所以加salt的哈希就是:计算一段message的哈希时,根据不同的口令计算出不同的哈希。即,要验证哈希值必须同时提供口令。上面的这个思路实际上就是Hmac算法了,它通过一个标准算法,在计算哈希的过程中把key混入计算过程。和我们自定义的加salt算法不同,Hmac算法针对所有的哈希算法都通用,无论是MD5还是SHA-1。其实可以认为Hmac算法和我们自定义的加salt的哈希算法本质上就是一个东西。但是使用Hmac替代我们自己的salt算法可以使程序算法更标准话,也更安全。

2、实例程序(打包代码 这里 )
(1)algo_hmac.h

#ifndef _ALGO_HMAC_H_
#define _ALGO_HMAC_H_

int HmacEncode(const char * algo,
const char * key, unsigned int key_length,
const char * input, unsigned int input_length,
unsigned char * &output, unsigned int &output_length);

#endif

 


(2)algo_hmac.cpp

#include "algo_hmac.h"
#include <openssl/hmac.h>
#include <string.h>
#include <iostream>
using namespace std;

int HmacEncode(const char * algo,
const char * key, unsigned int key_length,
const char * input, unsigned int input_length,
unsigned char * &output, unsigned int &output_length) {
const EVP_MD * engine = NULL;
if(strcasecmp("sha512", algo) == 0) {
engine = EVP_sha512();
}
else if(strcasecmp("sha256", algo) == 0) {
engine = EVP_sha256();
}
else if(strcasecmp("sha1", algo) == 0) {
engine = EVP_sha1();
}
else if(strcasecmp("md5", algo) == 0) {
engine = EVP_md5();
}
else if(strcasecmp("sha224", algo) == 0) {
engine = EVP_sha224();
}
else if(strcasecmp("sha384", algo) == 0) {
engine = EVP_sha384();
}
else if(strcasecmp("sha", algo) == 0) {
engine = EVP_sha();
}
else if(strcasecmp("md2", algo) == 0) {
engine = EVP_md2();
}
else {
cout << "Algorithm " << algo << " is not supported by this program!" << endl;
return -1;
}

output = (unsigned char*)malloc(EVP_MAX_MD_SIZE);
/*---------------------------------
这块应该是相对通用的计算流程了
--------------------------------*/
HMAC_CTX ctx;

 

HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, key, strlen(key), engine, NULL);
HMAC_Update(&ctx, (unsigned char*)input, strlen(input)); // input is OK; &input is WRONG !!!

HMAC_Final(&ctx, output, &output_length);
HMAC_CTX_cleanup(&ctx);

return 0;
}

(3)main.cpp

#include "algo_hmac.h"
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

int main(int argc, char * argv[])
{
if(argc < 2) {
//参数指定hash算法,支持HmacEncode列举的那些
cout << "Please specify a hash algorithm!" << endl;
return -1;
}

char key[] = "fasdkgjl;asdfjg;dsfjgasdsr";//secret key
string data = "/pic/small/3007024147/8ba5a744-f48d-4ba2-b93f-da17e7f52dff";//要加密传输的数据

unsigned char * mac = NULL;
unsigned int mac_length = 0;

int ret = HmacEncode(argv[1], key, strlen(key), data.c_str(), data.length(), mac, mac_length);

if(0 == ret) {
cout << "Algorithm HMAC encode succeeded!" << endl;
}
else {
cout << "Algorithm HMAC encode failed!" << endl;
return -1;
}

cout << "mac length: " << mac_length << endl;
cout << "mac:";
for(int i = 0; i < mac_length; i++) {
printf("%-03x", (unsigned int)mac[i]);
}
cout << endl;

if(mac) {
free(mac);
cout << "mac is freed!" << endl;
}

return 0;
}

 


(4)Makefile

LNK_OPT = -g -L/usr/lib64/ -lssl -L/lib64/ -lcrypto

all:
rm -f *.o
rm -f test
g++ -g -c algo_hmac.cpp
g++ -g main.cpp -o test algo_hmac.o $(LNK_OPT)

clean:
rm -f *.o
rm -f test

 


3、执行效果
执行效果如下:

 

各种算法得到的摘要长度如下:

算法 摘要长度(字节)
MD2 16
MD5 16
SHA 20
SHA1 20
SHA224 28
SHA256 32
SHA384 48
SHA512 64
参考:用OpenSSL 做HMAC(C++)_yasi_xi的博客-CSDN博客_openssl/hmac.h

4、HMAC相关函数
官网 /docs/man1.0.2/man3/HMAC_CTX_cleanup.html

主要涉及如下函数:

HMAC, HMAC_CTX_init, HMAC_Init, HMAC_Init_ex, HMAC_Update, HMAC_Final, HMAC_CTX_cleanup, HMAC_cleanup - HMAC message authentication code

注:其中 HMAC_CTX_cleanup 作用如下。如果结尾处不调用此函数的话会导致内存泄漏。

HMAC_CTX_cleanup() erases the key and other data from the HMAC_CTX and releases any associated resources. It must be called when an HMAC_CTX is no longer required.
关于遗漏 HMAC_CTX_cleanup 引发的内存泄漏的实际测试可以参照这篇文章。

https://blog.csdn.net/mijichui2153/article/details/126412532?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22126412532%22%2C%22source%22%3A%22mijichui2153%22%7D

标签:CTX,openssl,C++,算法,algo,哈希,include,HMAC
From: https://www.cnblogs.com/LiuYanYGZ/p/17843600.html

相关文章

  • 一万五千字C++STL【容器】详解(转载)
    一、什么是容器?所谓容器,就是可以承载,包含元素的一个器件,它是STL六大组件之一,是容器、算法、迭代器中最重要也是最核心的一部分。二、STL中各大容器的结构与分类2.1顺序性容器2.1.1什么是顺序性容器?顺序性容器就是将一组具有相同类型的元素以严格的线性形式组织起来2.1.2......
  • [实验任务一]:JAVA和C++常见数据结构迭代器的使用
    信1305班共44名同学,每名同学都有姓名,学号和年龄等属性,分别使用JAVA内置迭代器和C++中标准模板库(STL)实现对同学信息的遍历,要求按照学号从小到大和从大到小两种次序输出学生信息。实验要求:1. 搜集并掌握JAVA和C++中常见的数据结构和迭代器的使用方法,例如,vector,list,map和set等......
  • C++ merge()函数
    merge()函数用于将2个有序序列合并为1个有序序列,前提是这2个有序序列的排序规则相同(要么都是升序,要么都是降序)。并且最终借助该函数获得的新有序序列,其排序规则也和这2个有序序列相同。merge()函数支持自定义规则排序,merge()有两种语法格式//以默认的升序排序作为排......
  • DX后台截图C++实现代码
    DX后台截图C++实现代码文章仅发布于https://www.cnblogs.com/Icys/p/DXGI.html和知乎上。传统的GDIAPI(BitBlt)虽然可以完美的完成后台截图的任务,但是归根结底效率还是太低。直接使用DXGI方法截图只能完成前台窗口的截图,而DXHOOK的截图方法平添风险,以及很多场景不现实。......
  • C++AVL树和红黑树的模拟实现
    前言在二叉树的基础上,为了让搜索更加快捷,出现的二叉搜索树,二叉搜索树规定,二叉树的左子树的值一定都小于其父亲节点的值,所有右子树的值一定都大于其父亲节点的值,这样就保证了在查找某一个数据时,让时间复杂度最低为变为logn。一、二叉树两种特殊的二叉树1.满二叉树满二叉树每层的节......
  • OpenSSL - Certificate Generation
    WewillusetheOpenSSL(https://www.openssl.org/source/)tooltogenerateself-signedcertificates.Acertificateauthority(CA)isresponsibleforstoring,signing,and issuingdigitalcertificates.Thismeanswewillfirstgenerateaprivatekeyanda......
  • P2240 【深基12.例1】部分背包问题(C/C++)
    P2240【深基12.例1】部分背包问题先把物品按照单位重量的价值降序排序,然后依次装入背包。如果背包容量不小于当前要装的物品重量,就全部装入,如果小于,那就剩余多少容量就装多少容量的当前物品。#include<bits/stdc++.h>usingnamespacestd;structjinbi{ doublem; doublev;......
  • C/C++ 获取主机网卡MAC地址
    MAC地址(MediaAccessControladdress),又称为物理地址或硬件地址,是网络适配器(网卡)在制造时被分配的全球唯一的48位地址。这个地址是数据链路层(OSI模型的第二层)的一部分,用于在局域网(LAN)中唯一标识网络设备。获取网卡地址主要用于网络标识和身份验证的目的。MAC地址是一个唯一的硬件......
  • C++默认参数实现原理分析
    简介定义C++默认参数指的是当函数调用中省略了实参时自动使用的一个值。写法如下:voidfoo(inta=1){}voidfoo(inta,intb=1,intc=1){}默认参数有两个规则,规则一:从第一个出现默认参数的参数开始,后面的参数必须也指定默认参数voidfoo(inta=1,intb,intc=1......
  • Code-C++-字符串分割
    Code-C++-字符串分割转自【C++中string如何实现字符串分割函数split()——4种方法-CSDNApp】http://t.csdnimg.cn/8iWb7stringstreamgetline()stringfind()substr()ccharstrtok()strtok_r()regex_token_iterator<>getline()voidStringsplit(stringstr,const......