【密码学】消息认证码

简介: (Message Authentication Code) 是一种确认完整性并进行认证的技术,简称 MAC。使用消息认证码可以确认自己收到的消息是否就是发送者的本意,也就是说可以判断消息是否被篡改,是否有人伪装成发送者发送了这条消息。消息认证码的输入包括任意长度的和一个发送者与接收者之间的。输出固定长度的数据,输出的数据就是 MAC 值。

一、什么是消息认证码?

消息认证码(Message Authentication Code) 是一种确认完整性并进行认证的技术,简称 MAC。

使用消息认证码可以确认自己收到的消息是否就是发送者的本意,也就是说可以判断消息是否被篡改,是否有人伪装成发送者发送了这条消息。

消息认证码的输入包括任意长度的消息和一个发送者与接收者之间的共享密钥。输出固定长度的数据,输出的数据就是 MAC 值。

二、为什么需要消息认证码

   在上个章节我们讲到了单向散列函数,单向散列函数也可以用在检查消息的完整性。那消息认证码和单向散列函数的区别是什么呢?

单向散列函数: 只有一个输入参数,就是消息本身, 只能用在检查消息的完整性。

消息认证码: 有两个输入参数,一个是消息本身,另一个是共享秘钥。所以消息认证码不仅可以确认消息的完整性,还可以确认消息发送者是否持有共同的共享秘钥。

单向散列函数与消息认证码的区别如下图:

103_1.png

消息认证码和单向散列函数的区别就在有没有这个共享密钥上了。所以消息认证码就是利用共享密钥进行认证的。消息认证码和单向散列函数的散列值一样,如果消息发生了 1 比特的变化,MAC 值也会发生变化。所以消息认证码正是用这个性质来进行完整性的。

所以消息认证码可以理解为消息认证码是一种与密钥相关联的单向散列函数。单向散列函数也是实现消息认证码最常见的一种方法,该类方法称为HMAC。

三、消息认证码的实现方式

消息认证码可以有其他密码技术构造,常见的消息认证码实现方式有:单向散列函数实现、分组密码实现和认证密码实现。

  1. 单向散列函数实现

    使用单向散列函数实现的消息认证码称为HMAC。单向散列函数可以检查消息的完整性,但无法验证消息来源的可靠性,所以单向散列算法不能直接应用于消息认证码算法。在HMAC算法中,共享秘钥没有长度限制,输入消息也没有长度限制,但HMAC算法的输入结果长度是固定的。

  2. 分组密码实现

    分组密码中的CBC模式也可以实现消息认证码算法,典型的实现方法为CBC-MAC。分组密码的秘钥可以作为消息认证码中的共享秘钥,对消息进行加密处理后将最后一个分组加密的结果作为消息认证码。由于CBC模式的最后一个分组结果由整个消息和密钥决定,所以这种方法也可以保证消息的完整性和真实性。
    CMAC也是基于分组密码的消息认证码算法,CMAC算法通过共享密钥派生出两个中间密钥K1和K2,其算法的安全性要高于CBC-MAC算法。

  3. 认证加密算法实现

    认证加密算法是在通信过程中提供数据机密性和完整性的密码算法,可以看做对称加密算法和消息认证码的结合。 认证加密算法的典型实现包括GCM算法和CCM算法,相比单向散列算法和分组密码实现的消息认证码算法,认证加密算法的应用更广泛。

四、HMAC 算法实现

HMAC 是一种使用单向散列函数来构造消息认证码的方法,HMAC 中的 H 是 Hash 的意思。官方文档见 RFC 2104

任何高强度的单向散列函数都可以被用于 HMAC 中,例如 SHA-1、SHA-224、SHA-256、SHA-384、SHA-512 所构造的 HMAC,分别称为 HMAC-SHA1、HMAC-SHA-224、HMAC-SHA-256、HMAC-SHA-384、HMAC-SHA-512。

HMAC 计算 MAC 值步骤如下:

103_3__.png

1. 密钥填充

如果密钥比单向散列函数的分组长度要短,就需要在末尾填充 0,使最终长度和单向散列函数分组长度一样。

如果密钥比分组长度要长,则要用单向散列函数求出密钥的散列值,然后把这个散列值作为 HMAC 的密钥。

2. 密钥变换 I

将填充后的密钥和 ipad 的比特序列进行 XOR 计算。ipad 是 00110110 (16进制的 36)不断循环直到长度和分组长度一样长的比特序列。ipad 的 i 是 inner 内部的意思。

XOR 得到的最终结果是一个和单向散列函数的分组长度相同,且和密钥相关的比特序列。这个序列称为 ipadkey。

3. 与消息组合

把 ipadkey 附加在消息的开头。

4. 计算散列值

把第 3 步的结果输入单向散列函数,计算出散列值。

5. 密钥变换 II

将填充后的密钥和 opad 的比特序列进行 XOR 计算。opad 是 01011100 (16进制的 5C)不断循环直到长度和分组长度一样长的比特序列。opad 的 o 是 outer 外部的意思。

XOR 得到的最终结果是一个和单向散列函数的分组长度相同,且和密钥相关的比特序列。这个序列称为 opadkey。

6. 与散列值组合

把 opadkey 附加在散列值的开头。

7. 计算散列值

把第 6 步的结果输入单向散列函数,计算出散列值。这个散列值即为最终 MAC 值。

最终的 MAC 值一定是一个和输入消息以及密钥都相关的长度固定的比特序列。

HMAC 如果用伪代码表示:

HMAC = hash(opadkey || hash(ipadkey || message))
     = hash( (key ⊕ opad) || hash( (key ⊕ ipad) || message) )

opadkey = key ⊕ opad
ipadkey = key ⊕ ipad

key 为密钥,message 为消息,hash 计算为 hash(),A || B 代表 A 放在 B 的前面

具体举一个 HMAC\_MD5 的例子:

/*
** Function: hmac_md5
*/

void hmac_md5(text, text_len, key, key_len, digest)
unsigned char*  text;                /* pointer to data stream */
int             text_len;            /* length of data stream */
unsigned char*  key;                 /* pointer to authentication key */
int             key_len;             /* length of authentication key */
caddr_t         digest;              /* caller digest to be filled in */

{
        MD5_CTX context;
        unsigned char k_ipad[65];    /* inner padding -
                                      * key XORd with ipad
                                      */
        unsigned char k_opad[65];    /* outer padding -
                                      * key XORd with opad
                                      */
        unsigned char tk[16];
        int i;
        /* if key is longer than 64 bytes reset it to key=MD5(key) */
        if (key_len > 64) {

                MD5_CTX      tctx;

                MD5Init(&tctx);
                MD5Update(&tctx, key, key_len);
                MD5Final(tk, &tctx);

                key = tk;
                key_len = 16;
        }

        /*
         * the HMAC_MD5 transform looks like:
         *
         * MD5(K XOR opad, MD5(K XOR ipad, text))
         *
         * where K is an n byte key
         * ipad is the byte 0x36 repeated 64 times
         * opad is the byte 0x5c repeated 64 times
         * and text is the data being protected
         */

        /* start out by storing key in pads */
        bzero( k_ipad, sizeof k_ipad);
        bzero( k_opad, sizeof k_opad);
        bcopy( key, k_ipad, key_len);
        bcopy( key, k_opad, key_len);

        /* XOR key with ipad and opad values */
        for (i=0; i<64; i++) {
                k_ipad[i] ^= 0x36;
                k_opad[i] ^= 0x5c;
        }
        /*
         * perform inner MD5
         */
        MD5Init(&context);                   /* init context for 1st
                                              * pass */
        MD5Update(&context, k_ipad, 64)      /* start with inner pad */
        MD5Update(&context, text, text_len); /* then text of datagram */
        MD5Final(digest, &context);          /* finish up 1st pass */
        /*
         * perform outer MD5
         */
        MD5Init(&context);                   /* init context for 2nd
                                              * pass */
        MD5Update(&context, k_opad, 64);     /* start with outer pad */
        MD5Update(&context, digest, 16);     /* then results of 1st
                                              * hash */
        MD5Final(digest, &context);          /* finish up 2nd pass */
}

输出

  key =         0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
  key_len =     16 bytes
  data =        "Hi There"
  data_len =    8  bytes
  digest =      0x9294727a3638bb1c13f48ef8158bfc9d
  
  
  key =         "Jefe"
  data =        "what do ya want for nothing?"
  data_len =    28 bytes
  digest =      0x750c783e6ab0b503eaa86e310a5db738
  
  
  key =         0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  key_len       16 bytes
  data =        0xDDDDDDDDDDDDDDDDDDDD...
                ..DDDDDDDDDDDDDDDDDDDD...
                ..DDDDDDDDDDDDDDDDDDDD...
                ..DDDDDDDDDDDDDDDDDDDD...
                ..DDDDDDDDDDDDDDDDDDDD
  data_len =    50 bytes
  digest =      0x56be34521d144c88dbb8c733f0e8b3f6

五 CBC-MAC 和 CMAC

  1. CBC-MAC

    CBC-MAC是数据认证算法的扩展实现。CBC-MAC的分组密码算法通常使用对称加密算法AES算法,并且使用全零分组作为初始化向量。但CBC-MAC在使用的时候需要满足一些限制条件,它仅能处理固定长度的消息。对于非固定长度的消息,该算法存在一定的安全隐患,假设给定一个消息分组M, 可以通过CBC-MAC计算得到消息认证码T,由于算法的特性,攻击者可以很容易计算出两个消息分组M‘=M||(M^T)的消息认证码,其结果还是T。为了解决该问题,人们在CBC-MAC基础上设计了CMAC算法。

  2. CMAC

    CMAC为了解决非固定长度消息的安全性问题,CMAC会通过密钥扩展出两个子密钥,子密钥会在最后一个消息分组加密前参与运算。CMAC的计算过程主要分为三部分,分别是子密钥生成、消息认证码的生成和验证消息认证码。

六、认证加密CCM

CCM是CTR-CBC-MAC的简写,CBC算法计算过程需要使用CTR模式和CBC-MAC算法。 加密和认证时CCM的输入包括明文P、一次性整数N(nonce)、相关数据A和密钥K。输出密文C和认证码T。

CCM认证过程是对格式化后的数据进行CBC-MAC运算,输入得到长度为t的消息认证码Tag,然后使用Ctr0作为计数值对Tag进行AES-CTR加密,输入作为最终的消息认证码T。对明文的加密过程同样使用计数器模式,不同的是计数值从Ctr1开始,该过程无需对明文进行填充。完成上述操作后,将密文和消息认证码作为最终的输出结果。

CCM算法需要对明文进行两次加密处理,第一次使用CBC-MAC计算消息认证码,第二次使用CTR模式加密明文。但由于加密和认证可以同时进行,并且加密过程中所使用的CTR模式也支持并行计算,这些特点使该算法在有相应的硬件支持时性能提高显著。

认证
加密

七、认证加密GCM

GCM的整体流程与CCM类似,GCM的计算过程需要使用GHASH算法和GCTR算法。
进行填充。完成上述操作后,将密文和消息认证码作为最终的输出结果。

CCM算法需要对明文进行两次加密处理,第一次使用CBC-MAC计算消息认证码,第二次使用CTR模式加密明文。但由于加密和认证可以同时进行,并且加密过程中所使用的CTR模式也支持并行计算,这些特点使该算法在有相应的硬件支持时性能提高显著。

七、认证加密GCM

GCM的整体流程与CCM类似,GCM的计算过程需要使用GHASH算法和GCTR算法。

目录
相关文章
|
6月前
|
安全 算法 Java
互联网并发与安全系列教程(12) - 信息加密技术(单向散列加密)
互联网并发与安全系列教程(12) - 信息加密技术(单向散列加密)
46 0
|
6月前
|
算法 安全 数据安全/隐私保护
互联网并发与安全系列教程(13) - 信息加密技术(对称&非对称加密)
互联网并发与安全系列教程(13) - 信息加密技术(对称&非对称加密)
38 0
|
3天前
|
安全 算法 网络安全
|
3天前
|
人工智能 分布式计算 安全
【现代密码学】笔记1.2 -- 对称密钥加密、现代密码学的基本原则《introduction to modern cryphtography》现代密码学原理与协议
【现代密码学】笔记1.2 -- 对称密钥加密、现代密码学的基本原则《introduction to modern cryphtography》现代密码学原理与协议
118 0
|
存储 安全 区块链
非对称加密与共识机制
非对称加密与共识机制
84 0
|
算法 安全 数据安全/隐私保护
【密码学】 一篇文章讲透数字签名
数字签名(又称公钥数字签名)是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。它是一种类似写在纸上的普通的物理签名,但是在使用了公钥加密领域的技术来实现的,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。数字签名是非对称密钥加密技术与数字摘要技术的应用。数字签名可以识别消息是否被篡改, 并验证消息的可靠性, 也可以防止否认。
462 0
【密码学】 一篇文章讲透数字签名
|
算法 物联网安全 物联网
【密码学】单向散列函数简介
​  单项散列函数又称为安全散列函数或者哈希函数,可以将一段可变长度是输入数据转化为固定长度的一段输出值。 输入数据通常称为消息,输出数据通常称为消息摘要或者摘要,可用于检查消息的完整性。​  常用的单向散列算法有MD4/5系列和SHA系列等。由于MD4、MD5算法都已被攻破,渐渐退出历史舞台,而SHA系列算法在物联网安全领域比较常见,特别是SHA256算法。​  额外提一点,提到单向散列函数的特性,很多人一下子想到,我们经常使用到的CRC校验,例如将一段可变长度的数据经过CRC校验后,生成2个字节的校验值
264 0
【密码学】单向散列函数简介
|
算法 数据安全/隐私保护
数字签名技术
通过阅读本篇文章,你可以了解到如下知识: 1. 数字签名是什么 2. 数字签名的作用 3. 签名 和 验签的流程 4. RSA、RSA2 签名算法
262 0
|
并行计算 搜索推荐 算法
【密码学】分组密码模式
分组密码只能处理固定长度的分组,但是对于如何把每个分组组合起来,这里面也会有多种方案,一个非常简单的做法便是每个分组单独处理,然后把每个分组的结果拼接起来,这种方式其实也就是「ECB」模式,这个模式实际上是非常不安全的,各位读者在生产环境千万不要使用,本文在加下将描述几种模式。
【密码学】分组密码模式
|
算法 数据安全/隐私保护
【密码学】一文读懂Diffie-Hellman密钥交换协议
注意这个算法是基于离散对数的,如果对于离散对数不了解的读者可以查看我之前的对于离散对数讲解的文章。
【密码学】一文读懂Diffie-Hellman密钥交换协议