带附加数据的认证加密(AEAD):了解AES GCM、ChaCha20/Poly1305、AES CCM…

本文介绍了AEAD(Authenticated Encryption with Associated Data)认证加密技术,它通过在加密过程中加入额外的认证数据,在保证数据机密性的同时,也保证了数据的完整性和真实性。文章还介绍了目前主流的AEAD实现方案,包括AES GCM、AES SIV、AES CCM、ChaCha20/Poly1305和AES OCB3,并给出了相应的代码示例。

带有附加数据的身份验证加密(AEAD):了解 AES GCM、ChaCha20/Poly1305、AES CCM、AES SIV 和 AES OCB3

你是否讨厌网络安全中所有那些让人头疼的缩略词? 好吧,让我们解释几个... AES GCM、ChaCha20/Poly1305、AES CCM、AES SIV 和 AES OCB3,所有这些都可以大大增强系统的安全性,并阻止 Eve 玩弄你的秘密和受信任的信息。 在这种情况下,我们将研究用于创建 AEAD 的主要方法:SIV(合成初始化向量)、CCM(带有密码块链接消息认证码的计数器;带有 CBC-MAC 的计数器)、GCM(伽罗瓦/计数器模式)、ChaCha20(Daniel J. Bernstein 对舞蹈的热爱)和 OCB3。

通过设计实现安全

Alice 创建了一条秘密消息,并使用她的密钥对其进行加密,然后将其发送给 Bob。 他也有密钥,因此他将其解密并显示秘密消息。 上面写着“你可以把明天当作假期”。 Bob 很高兴并休假了。 然而,Eve 一直在监听他们的通信,并在第二天重新发送加密的消息,即使她无法读取它。 Bob 第二天休假,Alice 想知道他为什么不在工作。 因此,Eve 对 Alice 的加密消息执行了重放攻击。 因此,我们需要将密码绑定到网络连接或会话,以便 Eve 无法重现相同的场景。

通过增强的加密方法,我们既可以验证密码,又可以证明其完整性。 这被称为带有关联数据的身份验证加密AEAD)。 为此,我们提供附加数据来验证加密过程,我们可以在其中识别密文的修改位置,并防止其被解密。

对于大多数传统的 AEAD 方法,我们创建一个 nonce 值并添加附加数据(AD),这些数据经过身份验证但未加密。 附加数据可以包括【这里】:

地址、端口、序列号、协议版本号以及指示如何处理、转发或处理明文或密文的其他字段

通过这种方式,我们可以将网络数据包绑定到加密数据并提供完整性,以便入侵者无法从其他传输中复制和粘贴有效的密文。 例如,如果绑定到数据包序列号和端口,则对于另一个序列号或另一个端口,身份验证将失败。

我们可以用于 AEAD 的主要方法是 AES GCM、AES SIV、AES CCM、ChaCha20/Poly1305 和 AES OCB3。 这些将在以下各节中进行解释。

AES GCM — 快速流密码

AES GCM 将 AES 方法转换为流密码。 因此,它不需要填充并且比其他模式更快。 GCM 还支持 AEAD,我们可以在其中向密码中添加附加数据,这些数据可用于验证密码。 它通过添加身份验证标签来实现。 附加数据可能将密码绑定到给定的网络端口或会话。 这意味着入侵者无法重放密码,因为他们无法创建相同的附加数据 [这里]:

from cryptography.hazmat.primitives.ciphers.aead import AESGCM

key = AESGCM.generate_key(bit_length=keysize)
cipher = AESGCM(key)
ct = cipher.encrypt(nonce,message.encode(), add.encode())
rtn=cipher.decrypt(nonce,ct, add.encode())

AES SIV — 无 Nonce 方法和 Nonce 重用保护器

AES-SIV 现在已通过 RFC 5297 标准化。通过增强的加密方法,我们既可以验证密码,又可以证明其完整性。对于大多数传统的 AEAD 方法,我们创建一个 nonce 值并添加附加数据(AD),这些数据经过身份验证但未加密。使用无 nonce 方法,我们可以使用密钥包装方法,该方法通常用于保护加密密钥。

通过这种方式,我们可以将网络数据包绑定到加密数据,并提供完整性,以便入侵者无法从其他传输中复制和粘贴有效的密文。例如,如果绑定到数据包序列号和端口,则对于另一个序列号或另一个端口,身份验证将失败。

在 SIV 中,我们也可以有多个此附加数据的来源(称为字符串向量)。此信息可能分布在多个来源中,并且入侵者可能难以捕获和复制。这是 SIV 的特殊功能之一,允许将多个字符串用于身份验证,而不必将这些字符串合并为单个字符串以获取附加信息 [这里]:

from cryptography.hazmat.primitives.ciphers.aead import AESSIV

key = AESSIV.generate_key(bit_length=2*keysize)
cipher = AESSIV(key)
aad = [add.encode(), nonce]
ct = cipher.encrypt(message.encode(), aad)
rtn=cipher.decrypt(ct, aad)

在这种情况下,我们看到 aad 是一个向量列表,我们可以使用它们来验证数据。 这可以是字符串列表,例如用户名、会话 ID、域字符串等。

传统的 AEAD 方法在 nonce 重用以及 nonce 误用方面可能很弱。 在许多系统中,我们使用非确定性方法生成 nonce,因此无法知道以前生成的值是否已被使用。 另一个弱点是可以通过回滚虚拟机并发现使用的 nonce 值来“回放”nonce。 因此,大多数 AEAD 方法对于唯一的 nonce 是安全的,但是如果 nonce 不是唯一的,则无法保证安全性。 由于 nonce 值的大小有限,因此始终有可能使用相同的密钥重用它,因此我们可能必须定期更改我们的密钥。

SIV 为 nonce 重用/误用提供更多保护,攻击者只能确定给定的明文值和给定的关联数据集是使用定义的密钥和 nonce 值保护的。

AES CCM

使用 CBC(密码块链接)-MAC(消息认证码),我们使用共享密钥验证消息。 如果 Bob 想要向 Al-ice 发送一些文本,他会使用共享密钥对其进行加密,然后将此消息的消息摘要(或消息哈希)发送给 Alice。 Alice 对密钥执行相同的操作,并比较她获得的哈希值。 如果它们相同,则 Bob 继续证明他的身份(因为只有他才能拥有 Bob 和 Alice 共享的密钥),并且消息没有被更改。

总的来说,我们使用标准的 AES 形式加密了消息,然后丢弃了除最后一个块之外的所有内容,并将其用作固定长度的 MAC。 如果密钥不是秘密的,则该方法几乎无法提供安全性。

例如,如果我们有一个共享密钥“test123”和一条消息“hello”,则 CBC-MAC 是 9F63F3A838D17066(16x4 个十六进制字符是 64 位),但使用“hellp”则是 A2CD2D8CBD8E6DAD。 只有通过了解密钥,我才能确定正确的哈希值。 在 AES 密码块链接 (CBC) 加密中,我们使用 IV 来确保相同消息的位不同。 在 CBC-MAC 中,IV 设置为零,而使用 AES-CCM(带有 CBC-MAC 的计数器),IV 值用于更改消息摘要 [这里]:

from cryptography.hazmat.primitives.ciphers.aead import AESCCM

key = AESGCM.generate_key(bit_length=keysize)
cipher = AESCCM(key)
ct = cipher.encrypt(nonce,message.encode(), add.encode())
rtn=cipher.decrypt(nonce,ct, add.encode())

ChaCha20/Poly1305

Salsa20 和 ChaCha20 由 Daniel J. Bernstein 设计,是流密码。Google 已将 ChaCha20 定义为流加密的标准[RFC 7539],并包含在 TLS 标准中[RFC 7505]。 它使用 256 位密钥、32 位计数器和 96 位 nonce,以及 10 轮排列。 Poly1305 通过使用标签添加经过身份验证的数据 [这里]:

from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305

key = ChaCha20Poly1305.generate_key()
cipher = ChaCha20Poly1305(key)
ct = cipher.encrypt(nonce,message.encode(), add.encode())
rtn=cipher.decrypt(nonce,ct, add.encode())

ChaCha20 的优点在于它不是 AES。 如果你不信任 NIST 定义的 AES 标准,ChaCha20 是一个很好的替代方案。 此外,如果 AES 被破解,我们仍然可以使用 ChaCha20 作为替代方案。

AES OCB3

OCB3 是一种块密码模式,支持 64 位、96 位和 128 位身份验证标签 [这里]:

from cryptography.hazmat.primitives.ciphers.aead import AESOCB3

key = AESGCM.generate_key(bit_length=keysize)
cipher = AESOCB3(key)
ct = cipher.encrypt(nonce,message.encode(), add.encode())
rtn=cipher.decrypt(nonce,ct, add.encode())

RFC 在这里

编码

以下是一些说明这些方法的编码:

import os
import sys
import base64

from cryptography.hazmat.primitives.ciphers.aead import AESSIV,AESOCB3,AESGCM,ChaCha20Poly1305,AESCCM
message = "Hello"
add = "Session 1234"
method=0
keysize=128
if (len(sys.argv)>1):
 message=str(sys.argv[1])
if (len(sys.argv)>2):
 add=str(sys.argv[2])
if (len(sys.argv)>3):
 method=int(sys.argv[3])
if (len(sys.argv)>4):
 keysize=int(sys.argv[4])
nonce = os.urandom(12)
try:
 if (method==0):
  key = AESSIV.generate_key(bit_length=2*keysize)
  cipher = AESSIV(key)
  print(f"==AES SIV key size={2*keysize} ==")
 elif (method==1):
  key = AESGCM.generate_key(bit_length=keysize)
  cipher = AESGCM(key)
  print("==AES CCM==")
 elif (method==2):
  key = AESOCB3.generate_key(bit_length=keysize)  # 128, 192, 256
  cipher = AESOCB3(key)
  print("==AES AESOCB3==")
 elif (method==3):
  key = ChaCha20Poly1305.generate_key()
  cipher = ChaCha20Poly1305(key)
  print("==AES ChaCha20Poly1305==")
 elif (method==4):
  key = AESCCM.generate_key(bit_length=keysize)
  cipher = AESCCM(key)
  print("==AES CCM==")
 if (method==0):
  aad = [add.encode(), nonce]
  ct = cipher.encrypt(message.encode(), aad)
  rtn=cipher.decrypt(ct, aad)
 else:
  ct = cipher.encrypt(nonce,message.encode(), add.encode())
  rtn=cipher.decrypt(nonce,ct, add.encode())
 print(f"Message:\t{message}")
 print(f"AAD:\t\t{add}")
 print(f"\nNonce:\t\t{nonce.hex()}")
 print(f"\nKey:\t\t{key.hex()}")
 print(f"Key:\t\t{base64.b64encode(key).decode()}")
 print(f"\nCipher:\t\t{ct.hex()}")
 print(f"Cipher:\t\t{base64.b64encode(ct).decode()}")
 print(f"\nDecrypt:\t{rtn.decode()}")
except Exception as e:
    print(e)

以及 128 位 SIV 的示例运行(请注意,密钥大小是密钥的两倍) [这里]:

==AES SIV key size=256 ==
Message: Hello
AAD:  Test 123

Nonce:  cf48f99a3347e0730ea8267f
Key:  a1b3c8fdf5aec3dbd10954041a2102932d2bbb17f195692099a888a8770beb5a
Key:  obPI/fWuw9vRCVQEGiECky0ruxfxlWkgmaiIqHcL61o=
Cipher:  e1fcb6f4f594dcab847fd80ef8386bda7f17264b21
Cipher:  4fy29PWU3KuEf9gO+Dhr2n8XJksh
Decrypt: Hello

和 128 位 GCM [这里]:

==AES CCM==
Message: Hello
AAD:  Test 123

Nonce:  7f162b557f737427a651eb49
Key:  bb1cc6f724af8c48c25980dc68db64a5
Key:  uxzG9ySvjEjCWYDcaNtkpQ==
Cipher:  a263459142f53f73c893468a017342745a11112aa3
Cipher:  omNFkUL1P3PIk0aKAXNCdFoRESqj
Decrypt: Hello

结论

因此,AEAD 允许你将一些附加数据绑定到密码中,因此你可以绑定密文,因此它不能用于其他目的。

  • 原文链接: medium.com/asecuritysite...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
asecuritysite
asecuritysite
江湖只有他的大名,没有他的介绍。