信息摘要算法之五:HMAC算法分析与实现

摘要:
目前,它主要集成了两系列消息摘要算法,MD和SHA。使用哈希函数H计算上一步生成的数据流的信息汇总值,输出结果是最终的HMAC值。

MAC(Message Authentication Code,消息认证码算法)是含有密钥散列函数算法,兼容了MD和SHA算法的特性,并在此基础上加上了密钥。因此MAC算法也经常被称作HMAC算法。

1HMAC概述

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

HMAC算法除了需要信息摘要算法外,还需要一个密钥。HMAC的密钥可以是任何长度,如果密钥的长度超过了摘要算法信息分组的长度,则首先使用摘要算法计算密钥的摘要作为新的密钥。一般不建议使用太短的密钥,因为密钥的长度与安全强度是相关的。通常选取密钥长度不小于所选用摘要算法输出的信息摘要的长度。

2HMAC算法分析

HMAC算法本身并不复杂,起需要有一个哈希函数,我们记为H。同时还需要有一个密钥,我们记为K。每种信息摘要函数都对信息进行分组,每个信息块的长度是固定的,我们记为B(如:SHA1为512位,即64字节)。每种信息摘要算法都会输出一个固定长度的信息摘要,我们将信息摘要的长度记为L(如MD5为16字节,SHA-1为20个字节)。正如前面所述,K的长度理论上是任意的,一般为了安全强度考虑,选取不小于L的长度。

HMAC算法其实就是利用密钥和明文进行两轮哈希运算,以公式可以表示如下:

HMAC(K,M)=H(K⊕opad∣H(K⊕ipad∣M)),其中:

Ipad为0x36重复B次

Opad为0x5c重复B次

M 代表一个消息输入

根据上面的算法表示公式,我们可以描述HMAC算法的运算步骤:

(1)、检查密钥K的长度。如果K的长度大于B则先使用摘要算法计算出一个长度为L的新密钥。如果后K的长度小于B,则在其后面追加0来使其长度达到B。

(2)、将上一步生成的B字长的密钥字符串与ipad做异或运算。

(3)、将需要处理的数据流text填充至第二步的结果字符串中。

(4)、使用哈希函数H计算上一步中生成的数据流的信息摘要值。

(5)、将第一步生成的B字长密钥字符串与opad做异或运算。

(6)、再将第四步得到的结果填充到第五步的结果之后。

(7)、使用哈希函数H计算上一步中生成的数据流的信息摘要值,输出结果就是最终的HMAC值。

由上述描述过程,我们知道HMAC算法的计算过程实际是对原文做了两次类似于加盐处理的哈希过程。

3、代码实现

前面我们描述了HMAC算法及其实现过程,接下来我们则将其实现。首先我们定义一个用于保存计算过程上下文的结构:

/** 该结构将为HMAC密钥哈希操作保存上下文信息*/

typedef struct HMACContext {

  int whichSha; /* 所用的SHA算法 */

  int hashSize; /* 所用SHA的哈希值大小 */

  int blockSize; /* 所用SHA块的大小 */

  SHAContext shaContext; /* SHA上下文 */

  unsigned char k_opad[SHA_Max_Message_Block_Size];/* outer padding - key XORd with opad */

  int Computed; /* Is the MAC computed? */

  int Corrupted; /* Cumulative corruption code */

} HMACContext;

接下来实现HMAC初始化函数。这个函数将初始化hmacContext以准备计算一个新的HMAC消息摘要。

int hmacReset(HMACContext *context, enum SHAversion whichSha,const unsigned char *key, int key_len)

{

  int i, blocksize, hashsize, ret;

  unsigned char k_ipad[SHA_Max_Message_Block_Size];/* inner padding - key XORd with ipad */

  unsigned char tempkey[SHAMaxHashSize];/* temporary buffer when keylen > blocksize */

  if (!context) return shaNull;

  context->Computed = 0;

  context->Corrupted = shaSuccess;

  blocksize = context->blockSize = SHABlockSize(whichSha);

  hashsize = context->hashSize = SHAHashSize(whichSha);

  context->whichSha = whichSha;

  /*如果键长于哈希块大小,将其重置为key = hash (key)。 */

  if (key_len > blocksize) {

    SHAContext tcontext;

    int err = SHAReset(&tcontext, whichSha) ||

    SHAInput(&tcontext, key, key_len) ||

    SHAResult(&tcontext, tempkey);

    if (err != shaSuccess) return err;

    key = tempkey;

    key_len = hashsize;

  }

  /*将key与ipad和opad按位异或*/

  for (i = 0; i < key_len; i++) {

    k_ipad[i] = key[i] ^ 0x36;

    context->k_opad[i] = key[i] ^ 0x5c;

  }

  /*将key填充0直到blocksize并与ipad和opad按位异或 */

  for ( ; i < blocksize; i++) {

    k_ipad[i] = 0x36;

    context->k_opad[i] = 0x5c;

  }

  /* 开始内层哈希运算 */

  ret = SHAReset(&context->shaContext, whichSha) ||

  SHAInput(&context->shaContext, k_ipad, blocksize);

  return context->Corrupted = ret;

}

接下来输入将要处理的信息,这个函数接受一个字节数组作为消息的下一处理部分。

int hmacInput(HMACContext *context, const unsigned char *text,int text_len)

{

  if (!context) return shaNull;

  if (context->Corrupted) return context->Corrupted;

  if (context->Computed) return context->Corrupted = shaStateError;

  /* 报文内容 */

  return context->Corrupted =SHAInput(&context->shaContext, text, text_len);

}

最后处理完成全部过程,返回信息摘要。此函数将返回相应大小的消息摘要,具体是多长的信息摘要由具体的SHA算法决定。

int hmacResult(HMACContext *context, uint8_t *digest)

{

  int ret;

  if (!context) return shaNull;

  if (context->Corrupted) return context->Corrupted;

  if (context->Computed) return context->Corrupted = shaStateError;

  /* 完成内层哈希运算 */

  ret =SHAResult(&context->shaContext, digest) ||

  /* 执行外层哈希运算 */

      SHAReset(&context->shaContext, context->whichSha) ||

      SHAInput(&context->shaContext, context->k_opad,context->blockSize) ||

      SHAInput(&context->shaContext, digest, context->hashSize) ||

      SHAResult(&context->shaContext, digest);

  context->Computed = 1;

  return context->Corrupted = ret;

}

4、结果

我们已经实现了HMAC算法,接下来我们对其进行验证。我们采用简单的测试,取加密文本为text =“abcd”,设密钥为key=“123456”,基于SHA-1的HMAC运算结果如下:

 信息摘要算法之五:HMAC算法分析与实现第1张

基于SHA-256的HMAC运算结果如下:

 信息摘要算法之五:HMAC算法分析与实现第2张

基于SHA-512的运算结果如下:

 信息摘要算法之五:HMAC算法分析与实现第3张

我们测试了HMAC-SHA1、HMAC-SHA256、HMAC-512三种情况,与在线HMAC加密算法进行对比计算,记过完全一致。

欢迎关注:

信息摘要算法之五:HMAC算法分析与实现第4张

免责声明:文章转载自《信息摘要算法之五:HMAC算法分析与实现》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇使用 VisualVM 进行性能分析及调优微服务最强开源流量网关Kong下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

c# 如何捕捉控制台程序的关闭事件。(转)

最近要做个控制台程序,在用户关闭程序的时候要做些处理,但控制台程序却没有WinForm的Closing或Closed事件,想想只能用API才捕捉消息来实现了,代码如下: 1using System; 2using System.Windows.Forms; 3using System.Diagnostics; 4using System.Runtime....

ASP.NET Core 实现 MQTT通讯协议 Demo(开源库:MQTTnet)

1、什么是MQTT   MQTT(message queuing telemetry transport)是IBM开发的即时通讯协议,是一种发布/订阅极其轻量级的消息传输协议,专门为网络受限设备、低宽带以及高延迟和不可靠的网络而设计的。由于以上轻量级的特点,是实现智能家居的首选传输协议,相比于XMPP,更加轻量级而且占用宽带低。简单来说HQTT是一种通信...

selenium之处理alert弹出对话框

在完成某些操作时会弹出对话框来提示,主要分为"警告消息框","确认消息框","提示消息对话"三种类型的对话框。    1.警告消息框(alert)  警告消息框提供了一个"确定"按钮让用户关闭该消息框,并且该消息框是模式对话框,也就是说用户必须先关闭该消息框然后才能继续进行操作。   2.确认消息框(confirm)   确认消息框向用户提示一个"是与否"...

物联网时代-新基建-ThingsBoard调试环境搭建

前言 2020开年之际,科比不幸离世、疫情当道、经济受到了严重的损失。人们都不幸的感慨: 2020年真是太不真实的一年,可以重新来过就好了!国家和政府出台了拯救经济和加速建设的利好消息。3月份最热的词是什么?价值50万亿投资额的"新基建"当之无愧。 这场声势浩大的新基建投资的主要战场,涵盖包括5G建设、特高压、城际高速铁路和城市轨道交通、新能源汽车充电桩、...

java加解密算法--常见加解密算法

什么是加密算法?百度百科给出的解释如下: 数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码,通常称为“密文”,使其只能在输入相应的密钥之后才能显示出本来内容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的。该过程的逆过程为解密,即将该编码信息转化为其原来数据的过程。 简单来说,就是把某一段数据(明文),按照...

从BF算法到kmp算法详解

正文索引 一、KMP介绍 二、例子:子串匹配母串 1.BF算法的解决方法 三、kmp算法的实现 (1)为什么已经有BF算法了还要有KMP算法呢? (2)发明的算法基本思想 (3)具体实现 一、KMP介绍 KMP算法是一种改进的字符串匹配算法(有BF算法改进而来,BF算法是暴利搜索匹配的方式,而KMP则是对BF算法的回溯过程进行改进,从而大幅度降低了时间复...