Open carloscn opened 2 years ago
Digest仅仅能够验证信息的完整性(Integrity),而没有办法确认信息的身份认证(Authetication)。例如,Alice收到一则需要Bob汇款1000元的消息,同时收到汇款消息的hash值,Alice可以计算hash确认1000元这个消息没有被篡改,但问题是,这则消息不是由Bob发的呢?因此就需要更高明的方法来帮助确认这个消息没有被篡改,还要确认这个消息是Bob发的。
消息认证有着广泛的应用,例如:
常用的MAC有:
在密码学中,消息认证码(英语:Message authentication code,缩写为MAC),又译为消息鉴别码、文件消息认证码、讯息鉴别码、信息认证码,是经过特定算法后产生的一小段信息,检查某段消息的完整性,以及作身份验证。它可以用来检查在消息传递过程中,其内容是否被更改过,不管更改的原因是来自意外或是蓄意攻击。同时可以作为消息来源的身份验证,确认消息的来源。
这里是一个消息认证码的实例,发送消息的人把明文消息和密钥送入MAC模块中会得到MAC,接收的人使用相同的密钥和明文消息进行计算,然后对MAC值进行对比,就可以确定这个消息是不是发送方发的。需要注意,两方确认身份的凭证和对称加密算法一样,都是通过共享密钥来确认身份的,所以在MAC里面也存在和SYM加解密一样的问题——密钥配送的问题(例如,公钥密码、Diffie-Hellman密钥交换、密钥分配中心等)
消息认证码的算法中,通常会使用带密钥的散列函数(HMAC),或者块密码
SHA-2之类的单向散列函数可以实现消息认证码,其中一种实现方法称为HMAC。使用AES之类的分组密码也可以实现消息认证码,将密钥作为消息认证码的共享密钥,使用固定的IV值,并用CBC模式将消息全部加密。
Alice认为既然同样持有密钥,对称加密兼顾了消息验证码的功能,只要解密出明文,就可以作为消息验证码使用,Alice想的对吗? 对称加密明文和密文长度是一致的,如果是一个加解密来确认,对于传输是有负担的,而消息认证码只有几个字节,方便传输; 如果使用ECB模式,明文块和块之间没有依赖,中间攻击者很可能删除一个完整块或做其他手脚,导致收到信息残缺,此时完整性已经被破坏,这是无法容忍的。 对于一些随机数或者密钥作为明文(人不可读的信息)的加密,当另一方解密的时候我们很难通过主观断言这就是我们想要的明文,因为对称解密解密错误也是输出一些人类无法识别的数据信息。 因此, Alice考虑的不完全正确。
Alice认为既然同样持有密钥,对称加密兼顾了消息验证码的功能,只要解密出明文,就可以作为消息验证码使用,Alice想的对吗?
因此, Alice考虑的不完全正确。
信息鉴别码不能提供对信息的保密,若要同时实现保密认证,同时需要对信息进行加密。2000年后,关于认证加密逐渐展开(AE或者AEAD)。认证加密是一种将对称密码、消息认证码结合的的技术,因此,同时满足了机密性、完整性和认证三大功能。
消息认证码我们将在 3.3_Security_对称密钥算法之AEAD 来详细说明,主要包含GCM/GMAC之类的。
利用MAC的一些特性,可以衍生出一些攻击,还需要一些其他手段来抵御这些攻击,提高可靠性和安全性。
重放攻击(英语:replay attack,或称为回放攻击)是一种恶意或欺诈的重复或延迟有效数据的网络攻击形式。 这可以由发起者或由拦截数据并重新传输数据的对手来执行。这是“中间人攻击”的一个较低级别版本。
Bob在接受多个重放攻击之后,导致Bob把自己的钱全部转给了Alice,而Alice就会很迷惑了。
对于抵抗重放攻击,我们通常有以下手段,本质上都是让每次的MAC值发生变化,即便是Mallory拿到了某一次的MAC值,也无法进行重放攻击。
和单向散列函数攻击一样,对消息认证码也可以进行暴力破解以及生日攻击。对于MAC来说,应保证不能根据MAC值推测出通信双方所使用的密钥。HMAC就是利用sha函数的单向性和抗碰撞性来保证无法根据MAC推测出密钥。
此外,密钥务必是由真随机数生成的,否则会被推测出来。
因为双方共同持有相同的密钥,所以第三方证明无法确认谁是发送,谁是接受。也同样没有办法防止否认。
Bob再接收到Alice的请求汇款的消息的时候,Bob想向第三方Victor证明这条消息是由Alice发的,Bob是做不到的。因此Victor认为,因为密钥Bob和Alice同样持有,Bob可以自己编写一个假消息,然后做MAC计算。Victor可能会怀疑Bob说谎,而Bob也没有办法来证明。
那同样的Alice真的发了消息,但是不承认自己发了,Alice说谎说是Bob自己编的消息然后算的MAC值,同样Bob也没办法来指出Alice在说谎。
因此,消息验证码没有办法证明出两个持有密钥的人之间的消息传递。而这就要靠数字签名来完成。
HMAC (有时扩展为 英语:keyed-hash message authentication code, 金钥杂凑讯息鉴别码, 或 英语:hash-based message authentication code,杂凑讯息鉴别码),是一种通过特别计算方式之后产生的讯息鉴别码(MAC),使用密码杂凑函数,同时结合一个加密金钥。它可以用来保证资料的完整性,同时可以用来作某个讯息的身份验证。
HMAC有个比较大条的思路就是上面的图片,对消息做MD5或者HASH,求得单向散列,接着对单向散列的数据进行加密。思路是这样的,但是实际上比这个情况要复杂的多。
根據RFC 2104,HMAC的數學公式為:
其中:
进行处理的过程,我们可以从:
KEY和IPAD和OPAD与message之间是有信息冗余的,然后经过两轮HASH算法之后得到的MAC,我们可以更清晰的从这个角度来看,message和key和i_pad和o_pad之间的信息冗余:
我们以HMAC384为例,使用mbedtls来完成这个例子:
https://github.com/carloscn/cryptography/blob/master/modules/digest/src/mbedtls_hmac.c
int mbedtls_hmac_sha384(const unsigned char *key, size_t key_byte_size, const unsigned char *input, size_t input_byte_size, unsigned char output[48]) { int ret = 0, mret = 0; mbedtls_md_info_t *info = NULL; mbedtls_md_context_t ctx; if (key == NULL || input == NULL || output == NULL) { ret = ERROR_COMMON_INPUT_PARAMETERS; mbedtls_printf(" * input parameters error, returned %d, line: %d\n", ret, __LINE__); goto finish; } if (key_byte_size == 0 || input_byte_size == 0) { ret = ERROR_NONE; mbedtls_printf(" * key size or input size == 0, returned %d, line: %d\n", ret, __LINE__); goto finish; } mbedtls_md_init(&ctx); info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); if (NULL == info) { ret = ERROR_CRYPTO_INIT_FAILED; mbedtls_printf(" * init failed, returned %d, line: %d\n", ret, __LINE__); goto ctx_inited; } mret = mbedtls_md_setup(&ctx, info, 1); if (0 != mret) { ret = ERROR_CRYPTO_INIT_FAILED; mbedtls_printf(" * init failed, returned %d, line: %d\n", ret, __LINE__); goto ctx_inited; } mret = mbedtls_md_hmac_starts(&ctx, key, key_byte_size); if (0 != mret) { ret = ERROR_CRYPTO_INIT_FAILED; mbedtls_printf(" * start failed, returned %d, line: %d\n", ret, __LINE__); goto ctx_inited; } mret = mbedtls_md_hmac_update(&ctx, input, input_byte_size); if (0 != mret) { ret = ERROR_CRYPTO_ENCRYPT_FAILED; mbedtls_printf(" * update failed, returned %d, line: %d\n", ret, __LINE__); goto ctx_inited; } mret = mbedtls_md_hmac_finish(&ctx, output); if (0 != mret) { ret = ERROR_CRYPTO_ENCRYPT_FAILED; mbedtls_printf(" * finish failed, returned %d, line: %d\n", ret, __LINE__); } ctx_inited: mbedtls_md_free(&ctx); finish: return ret; }
测试函数为:
https://github.com/carloscn/cryptography/blob/master/testsuite/src/unit_test_mbedtls.c#L599
static void test_mbedtls_hmac_384(void) { int ret = 0, i = 0; unsigned char key[] = {1,5,8,8,9,5,6,204,5,4,8,0,0,0,0}; unsigned char input[] = {1,5,8,8,9,5,6,204,5,4,8,0,0,0,0}; unsigned char output[48] = {0}; ret = mbedtls_hmac_sha384(key, sizeof(key)/sizeof(key[0]), input, sizeof(input)/sizeof(input[0]), output); for (i = 0; i < 48; i ++) { mbedtls_printf("%x", output[i]); } mbedtls_printf("\n"); CU_ASSERT_EQUAL(ret, 0); }
消息认证码还有另一大类就是CMAC(Cipher-Based Message Authentication Code,CMAC)。提到CMAC就不得不提一下CBC-MAC,CMAC是CBC-MAC的变体,CBC-MAC因为只能对固定长度的消息进行运算,因此存在安全问题,CMAC可以补足这个问题。CMAC最后的输出叫做tag。
CBC-MAC是在实践中应用非常广泛的standard message MAC。当message的长度固定时,CBC-MAC是安全的。CBC-MAC是最为广泛使用的消息认证算法之一,同时它也是一个ANSI标准(X9.17)。CBC-MAC实际上就是对消息使用CBC模式进行加密,取密文的最后一块作为认证码tag。
CBC的构造方法如下:
CBC-MAC和CBC操作模式是相似的但还是存在一些重要的区别:
由于有更好的MAC可以供选择,比如HMAC和OMAC,因此,CBC-MAC很难在一些密码库中看到身影。(至少mbedtls没有这个函数)
One-key MAC (OMAC)是一种消息认证码。在定义上,OMAC分为OMAC1和OMAC2,其中OMAC1就是我们说的CMAC,这个定义是2005年NIST进行推荐的。
业界发现了CBC-MAC存在的一些安全问题(在消息不是等长的时候,破坏fixed -length),进而创建了密码型消息身份验证代码(Cipher-Based Message Authentication Code,CMAC)。CMAC提供与CBC-MAC相同类型的数据源身份验证和完整性,但在数学上更为安全。CMAC 是CBC-MAC 的一种变体,它被批准与AES和三重DES一起使用。
CMAC的核心也是借助CBC-MAC:
算法一共有三个密钥,K, K1, K2, 其中K1和K2可以由K导出。对于CMAC来说,有两种情况,第一种是数据长度恰好就是分组长度的整数倍,对于这种情况,使用K1和最后一个分组异或之后加密得出结果,另一种情况是数据长度不是分组的整数倍,这就要先padding到分组的整数倍,Padding方法是先添加1bit的1, 其余bit填充0, 直到数据满足分组的整数倍。
OMAC和AES的关系是:
mbedtls提供了CMAC的接口,可以使用CMAC接口来计算消息的tag。注,mbedtls需要在编译的时候使能CMAC。CONFIG_MBEDTLS_MAC_CMAC_ENABLED^2。
CONFIG_MBEDTLS_MAC_CMAC_ENABLED
int mbedtls_cmac_aes_128_ecb(const unsigned char *key, size_t key_byte_size, const unsigned char *input, size_t input_byte_size, unsigned char *output, size_t *output_byte_size) { int rc = 0; /* mbedtls layer error code */ int ret = 0; /* current layer error code */ mbedtls_cipher_context_t ctx, *p_ctx = NULL; mbedtls_cipher_info_t *info = NULL; mbedtls_cipher_init(&ctx); p_ctx = &ctx; info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB); rc = mbedtls_cipher_setup(p_ctx, info); rc = mbedtls_cipher_cmac_starts(p_ctx, key, BYTE_CONV_BITS_NUM(key_byte_size)); rc = mbedtls_cipher_cmac_update(p_ctx, input, input_byte_size); rc = mbedtls_cipher_cmac_finish(p_ctx, output); *output_byte_size = mbedtls_cipher_get_key_bitlen(p_ctx)/8; if (NULL != p_ctx) { mbedtls_cipher_free(p_ctx); } return ret; }
使用示例: https://github.com/carloscn/cryptography/blob/master/modules/digest/src/mbedtls_cmac_exa.c
[^1]:Why I hate CBC-MAC
3.2_Security_对称密钥算法之MAC(CMAC + HMAC)
Digest仅仅能够验证信息的完整性(Integrity),而没有办法确认信息的身份认证(Authetication)。例如,Alice收到一则需要Bob汇款1000元的消息,同时收到汇款消息的hash值,Alice可以计算hash确认1000元这个消息没有被篡改,但问题是,这则消息不是由Bob发的呢?因此就需要更高明的方法来帮助确认这个消息没有被篡改,还要确认这个消息是Bob发的。
消息认证有着广泛的应用,例如:
常用的MAC有:
1. 概念
在密码学中,消息认证码(英语:Message authentication code,缩写为MAC),又译为消息鉴别码、文件消息认证码、讯息鉴别码、信息认证码,是经过特定算法后产生的一小段信息,检查某段消息的完整性,以及作身份验证。它可以用来检查在消息传递过程中,其内容是否被更改过,不管更改的原因是来自意外或是蓄意攻击。同时可以作为消息来源的身份验证,确认消息的来源。
这里是一个消息认证码的实例,发送消息的人把明文消息和密钥送入MAC模块中会得到MAC,接收的人使用相同的密钥和明文消息进行计算,然后对MAC值进行对比,就可以确定这个消息是不是发送方发的。需要注意,两方确认身份的凭证和对称加密算法一样,都是通过共享密钥来确认身份的,所以在MAC里面也存在和SYM加解密一样的问题——密钥配送的问题(例如,公钥密码、Diffie-Hellman密钥交换、密钥分配中心等)
1.1 消息认证码的实现
消息认证码的算法中,通常会使用带密钥的散列函数(HMAC),或者块密码
SHA-2之类的单向散列函数可以实现消息认证码,其中一种实现方法称为HMAC。使用AES之类的分组密码也可以实现消息认证码,将密钥作为消息认证码的共享密钥,使用固定的IV值,并用CBC模式将消息全部加密。
1.2 认证加密
信息鉴别码不能提供对信息的保密,若要同时实现保密认证,同时需要对信息进行加密。2000年后,关于认证加密逐渐展开(AE或者AEAD)。认证加密是一种将对称密码、消息认证码结合的的技术,因此,同时满足了机密性、完整性和认证三大功能。
消息认证码我们将在 3.3_Security_对称密钥算法之AEAD 来详细说明,主要包含GCM/GMAC之类的。
1.3 对MAC的攻击
利用MAC的一些特性,可以衍生出一些攻击,还需要一些其他手段来抵御这些攻击,提高可靠性和安全性。
1.3.1 重放攻击
重放攻击(英语:replay attack,或称为回放攻击)是一种恶意或欺诈的重复或延迟有效数据的网络攻击形式。 这可以由发起者或由拦截数据并重新传输数据的对手来执行。这是“中间人攻击”的一个较低级别版本。
Bob在接受多个重放攻击之后,导致Bob把自己的钱全部转给了Alice,而Alice就会很迷惑了。
对于抵抗重放攻击,我们通常有以下手段,本质上都是让每次的MAC值发生变化,即便是Mallory拿到了某一次的MAC值,也无法进行重放攻击。
1.3.2 推测密钥
和单向散列函数攻击一样,对消息认证码也可以进行暴力破解以及生日攻击。对于MAC来说,应保证不能根据MAC值推测出通信双方所使用的密钥。HMAC就是利用sha函数的单向性和抗碰撞性来保证无法根据MAC推测出密钥。
此外,密钥务必是由真随机数生成的,否则会被推测出来。
1.3.3 MAC的局限性
因为双方共同持有相同的密钥,所以第三方证明无法确认谁是发送,谁是接受。也同样没有办法防止否认。
第三方证明
Bob再接收到Alice的请求汇款的消息的时候,Bob想向第三方Victor证明这条消息是由Alice发的,Bob是做不到的。因此Victor认为,因为密钥Bob和Alice同样持有,Bob可以自己编写一个假消息,然后做MAC计算。Victor可能会怀疑Bob说谎,而Bob也没有办法来证明。
否认
那同样的Alice真的发了消息,但是不承认自己发了,Alice说谎说是Bob自己编的消息然后算的MAC值,同样Bob也没办法来指出Alice在说谎。
因此,消息验证码没有办法证明出两个持有密钥的人之间的消息传递。而这就要靠数字签名来完成。
2. HMAC原理
HMAC (有时扩展为 英语:keyed-hash message authentication code, 金钥杂凑讯息鉴别码, 或 英语:hash-based message authentication code,杂凑讯息鉴别码),是一种通过特别计算方式之后产生的讯息鉴别码(MAC),使用密码杂凑函数,同时结合一个加密金钥。它可以用来保证资料的完整性,同时可以用来作某个讯息的身份验证。
2.1 HMAC过程
HMAC有个比较大条的思路就是上面的图片,对消息做MD5或者HASH,求得单向散列,接着对单向散列的数据进行加密。思路是这样的,但是实际上比这个情况要复杂的多。
根據RFC 2104,HMAC的數學公式為:
其中:
进行处理的过程,我们可以从:
KEY和IPAD和OPAD与message之间是有信息冗余的,然后经过两轮HASH算法之后得到的MAC,我们可以更清晰的从这个角度来看,message和key和i_pad和o_pad之间的信息冗余:
2.2 mbedtls示例
我们以HMAC384为例,使用mbedtls来完成这个例子:
https://github.com/carloscn/cryptography/blob/master/modules/digest/src/mbedtls_hmac.c
测试函数为:
https://github.com/carloscn/cryptography/blob/master/testsuite/src/unit_test_mbedtls.c#L599
3. CBC-MAC和CMAC
消息认证码还有另一大类就是CMAC(Cipher-Based Message Authentication Code,CMAC)。提到CMAC就不得不提一下CBC-MAC,CMAC是CBC-MAC的变体,CBC-MAC因为只能对固定长度的消息进行运算,因此存在安全问题,CMAC可以补足这个问题。CMAC最后的输出叫做tag。
3.1 CBC-MAC
CBC-MAC是在实践中应用非常广泛的standard message MAC。当message的长度固定时,CBC-MAC是安全的。CBC-MAC是最为广泛使用的消息认证算法之一,同时它也是一个ANSI标准(X9.17)。CBC-MAC实际上就是对消息使用CBC模式进行加密,取密文的最后一块作为认证码tag。
CBC的构造方法如下:
CBC-MAC和CBC操作模式是相似的但还是存在一些重要的区别:
由于有更好的MAC可以供选择,比如HMAC和OMAC,因此,CBC-MAC很难在一些密码库中看到身影。(至少mbedtls没有这个函数)
3.2 OMAC
One-key MAC (OMAC)是一种消息认证码。在定义上,OMAC分为OMAC1和OMAC2,其中OMAC1就是我们说的CMAC,这个定义是2005年NIST进行推荐的。
业界发现了CBC-MAC存在的一些安全问题(在消息不是等长的时候,破坏fixed -length),进而创建了密码型消息身份验证代码(Cipher-Based Message Authentication Code,CMAC)。CMAC提供与CBC-MAC相同类型的数据源身份验证和完整性,但在数学上更为安全。CMAC 是CBC-MAC 的一种变体,它被批准与AES和三重DES一起使用。
CMAC的核心也是借助CBC-MAC:
算法一共有三个密钥,K, K1, K2, 其中K1和K2可以由K导出。对于CMAC来说,有两种情况,第一种是数据长度恰好就是分组长度的整数倍,对于这种情况,使用K1和最后一个分组异或之后加密得出结果,另一种情况是数据长度不是分组的整数倍,这就要先padding到分组的整数倍,Padding方法是先添加1bit的1, 其余bit填充0, 直到数据满足分组的整数倍。
OMAC和AES的关系是:
mbedtls提供了CMAC的接口,可以使用CMAC接口来计算消息的tag。注,mbedtls需要在编译的时候使能CMAC。
CONFIG_MBEDTLS_MAC_CMAC_ENABLED
^2。使用示例: https://github.com/carloscn/cryptography/blob/master/modules/digest/src/mbedtls_cmac_exa.c
Ref
[^1]:Why I hate CBC-MAC