AEAD接口用于同时加密和消息完整性认证。GCM是实现这个接口的一个具体实现模式。
1. 简介
TLS协议中使用的模式最开始有ECB、CBC等,为了对消息完整性进行确认,保证消息没有被篡改,还需要一个HMAC算法,其实就是对消息进行hash,得出来的值缀在被确认消息的后边。这就有个问题,是先对明文进行HMAC,再加密;还是先加密,再对密文进行HMAC。最开始是先对明文取HMAC,再加密(RFC5246,TLS1.2);后来认为这种不安全,就先加密,再对密文取HMAC(RFC7366, encrypt-then-mac);再后来认为这样也不安全,就出现了加密和验证在同一个操作中进行,也就是AEAD(RFC5116, Authenticated Encryption with Associated Data),带附加数据的认证加密算法。
GCM是一种加密模式,跟ECB、CBC类似,但相比后者的优势是多了附加数据认证,并且可以并行计算,速度很快。AEAD相当于定义了各个协议使用GCM模式的一个统一接口,AEAD可以用GCM去具体实现,也可以用CCM去实现。
2. GCM模式
还有个叫GMAC的算法,是GCM不输入附加数据,只对明文数据取最后的认证标签,算是GCM的一个变体。
计算的前提是已经选好了底层的块加密算法(AES,SM4等)和对应密钥key。
2.1. 带认证的加密模式
输入数据
- 明文P, len(P)<=2^39-256 位
- 附加数据A,包含不需要加密的但需要保证不能被改变的数据,比如IP、PORT等, len(A)<=2^64-1位
- 初始向量IV, 1<=len(IV)<=2^64-1 位,为了兼顾安全、效率,建议96位,12字节
输出数据
- 密文C,长度跟输入明文一样
- 鉴别标签,记为T,长度可以是128,120,112,104,96位这5个的一个
图例
2.2. 带认证的解密模式
输入数据
- 初始向量IV, 1<=len(IV)<=2^64-1,为了兼顾安全、效率,建议96位,12字节
- 附件数据A
- 密文C
- 鉴别标签T
输出数据
输出一下之一:
- 明文P
或者
- 特殊的错误代码
图例
3. AEAD接口
AEAD包含两个操作:带认证的加密和带认证的解密。RFC5116-An Interface and Algorithms for Authenticated Encryption规定了该接口的输入输出。AEAD其实就是封装了一下GCM模式算法。
3.1. 带认证的加密模式
输入数据
- 密钥K,长度为[1,255]字节,但对每个具体的AEAD算法,该长度是固定的
- 初始化向量IV,也叫nonce,建议是12字节
- 明文P,长度可以是0
- 附加认证数据A,长度可以是0
输出数据
- 成功:密文C,长度可以是0,最少是明文P的长度,实际中还要加上GCM的鉴别标签
- 失败:错误值,此时不能输出部分加密过的数据
图例
3.2. 带认证的解密模式
输入数据
- 密钥K,
- 初始化向量N
- 附加认证数据A,长度可以是0
- 密文C
输出数据
- 成功:明文P
- 失败:错误值,此时不能输出部分解密过的数据
图例
4. TLS1.2中使用的AEAD
RFC5288-AES Galois Counter Mode (GCM) Cipher Suites for TLS定义了如何在TLS1.2中跟RSA,DSA和DH密钥交换算法配合使用AEAD接口。该RFC定义了如下加密套件:
- CipherSuite TLS_RSA_WITH_AES_128_GCM_SHA256 = {0x00,0x9C}
- CipherSuite TLS_RSA_WITH_AES_256_GCM_SHA384 = {0x00,0x9D}
- CipherSuite TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = {0x00,0x9E}
- CipherSuite TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = {0x00,0x9F}
- CipherSuite TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = {0x00,0xA0}
- CipherSuite TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = {0x00,0xA1}
- CipherSuite TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = {0x00,0xA2}
- CipherSuite TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = {0x00,0xA3}
- CipherSuite TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = {0x00,0xA4}
- CipherSuite TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = {0x00,0xA5}
- CipherSuite TLS_DH_anon_WITH_AES_128_GCM_SHA256 = {0x00,0xA6}
- CipherSuite TLS_DH_anon_WITH_AES_256_GCM_SHA384 = {0x00,0xA7}
其中:
- 输出的鉴别标签长度都是16字节,128位
- nonce长度为12字节,96位,分为两部分
salt[4] || nonce_explicit[8]
。其中salt
是隐含部分,从握手中生成:client_write_IV 或 server_write_IV
;nonce_explicit
是发送端选取的,并放在TLS记录层的GenericAEADCipher.nonce_explicit
字段随包发送,在同一个GCM加密上下文中使用的nonce必须是唯一的,否则会严重降低安全性,nonce_explicit
可以是递增的64位序列号,不会回绕。 - 密钥K是
client_write_key或server_write_key
- 附加认证数据为
seq_num || TLSCompressed.type || TLSCompressed.version || TLSCompressed.length
5. TLCP中使用的AEAD
跟TLS1.2是一样一样的
6. TLS1.3中使用的AEAD
- 输出的鉴别标签长度都是16字节,128位
- nonce长度为12字节,构成方法为
0(paddings to iv length) seq(64bits) XOR client_write_iv/server_write_iv
, seq是64位从0开始递增的序列号 - 附加认证数据为
TLSCiphertext.opaque_type || TLSCiphertext.legacy_record_version || TLSCiphertext.length