总市值:$00
API
ZH
暗色

搜索SSI/Mag7/Meme/ETF/币种/指数/图表/研报
00:00 / 00:00
查看
    市场
    指数
    资讯
    TokenBar®
    分析
    宏观
    观察列表
分享

DAEAD:带关联数据的确定性认证加密

由AI翻译
Prof Bill Buchanan OBE
1K字
2025年6月29日

DAEAD:带关联数据的确定性认证加密

克服 Nonce 重用/滥用:SIV 模式

密码学中有一个核心原则,即输出可以是确定性的,也可以是非确定性的。对于确定性输出,对于相同的输入,我们总是得到相同的输出。例如,我们可以从明文创建一个密码,其输出将始终是相同的密文。对于非确定性,我们无法预测将使用什么输出,因为在该过程中使用了一些形式的随机化。对于签名,ECDSA 是非确定性的,而 EdDSA 是确定性的。

当涉及到对称密钥方法时,确定性性质在搜索数据时可能很有用,但从安全角度来看,它会更弱,因为攻击者可以将输入映射到输出。在这种情况下,我们将确定性性质与带关联数据的认证加密(Deterministic AEAD)相结合,并使用 AES-SIV 模式。

SIV — 合成初始化向量

我们泄露了太多的秘密,并且常常未能保护我们最重要的秘密之一……我们的加密密钥。为了克服这个问题,我们可以使用一种称为密钥包装的方法来保护密钥。这在通过不受信任的通道传输密钥或将其存储在没有强大访问控制的地方时尤其重要。对于密钥包装,Rogaway 等人提出了 SIV(合成初始化向量)方法 [here],该方法对密钥进行认证和加密,并对与密钥相关的任何附加数据进行认证:

该方法现在已通过 RFC 5297 [here] 进行了标准化。通过增强的加密方法,我们可以对密码进行认证并证明其完整性。这被称为带关联数据的认证加密(AEAD)。为此,我们提供额外的用于认证加密过程的数据,并且我们可以识别密文已被修改的位置,以便无法对其进行解密。对于大多数传统的 AEAD 方法,我们创建一个 nonce 值并添加额外的已认证但未加密的数据(AD)。使用无 nonce 的方法,我们可以使用密钥包装方法,该方法通常用于保护加密密钥。附加数据可以包括 [here]:

addresses, ports, sequence numbers, protocol version numbers, and other fields that indicate how the plaintext or ciphertext should be handled, forwarded, or processed

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

在以下代码中,我们将使用“101112131415161718191a1b1c1d1e1f2021222324252627”的附加信息,但在实践中,它可以是任何长度。在 SIV 中,我们也可以有多个此附加数据的来源(称为字符串向量)。此信息可以分布在多个来源中,并且入侵者可能难以捕获和复制。这是 SIV 的特殊功能之一,它允许使用多个字符串进行认证,而不必将它们合并为单个字符串以获取附加信息:

byte[] plaintext = pl.getBytes();

String additional="101112131415161718191a1b1c1d1e1f2021222324252627";
byte[] ciphertext = daead.encryptDeterministically(plaintext, Hex.decode(additional));

传统的 AEAD 方法在 nonce 重用和 nonce 滥用方面可能很弱。在许多系统中,我们使用非确定性方法生成 nonce,因此无法知道以前生成的值是否已被使用过。另一个弱点是 nonce 可以通过回滚虚拟机并发现使用的 nonce 值来“回放”。因此,大多数 AEAD 方法在使用唯一 nonce 时是安全的,但如果 nonce 不唯一,则无法保证安全性。由于 nonce 值的大小有限,因此始终存在使用相同密钥重用它的机会,因此,我们可能必须定期更改密钥。SIV 为 nonce 重用/滥用提供了更多保护,攻击者只能确定给定的明文值和给定的关联数据集是使用定义的密钥和 nonce 值进行保护的。

编码

在以下代码中,我们创建一个 SIV 密钥,然后创建密文值,这两个值应该相同 [here]:

package main

import (
"fmt"
"os"

"github.com/tink-crypto/tink-go/v2/daead"
"github.com/tink-crypto/tink-go/v2/keyset"


)

func main() {

msg:="Hello"
associated:="Hello"

argCount := len(os.Args[1:])
if (argCount>0) {msg = os.Args[1]}
if (argCount>1) {associated =os.Args[2]}

handle, _ := keyset.NewHandle(daead.AESSIVKeyTemplate())

primitive, _ := daead.New(handle)

plaintext := []byte(msg)
associatedData := []byte(associated)


ciphertext1, _:= primitive.EncryptDeterministically(plaintext, associatedData)
ciphertext2, _:= primitive.EncryptDeterministically(plaintext, associatedData)

res, _ := primitive.DecryptDeterministically(ciphertext1, associatedData)

fmt.Printf("Plaintext is %s\n",msg)
fmt.Printf("Associated data is %s\n\n",associated)

fmt.Printf("Key is %s\n\n",handle)

fmt.Printf("Cipher1 is %x\n\n",ciphertext1)
fmt.Printf("Cipher2 is %x\n\n",ciphertext2)
fmt.Printf("Decrypted is %s",res)


}

一个示例运行表明,当我们确定性地加密时,我们具有相同的密码 [here]:

Plaintext is Testing 123
Associated data is qwerty123

Key is primary_key_id:1537855825 key_info:{type_url:"type.googleapis.com/google.crypto.tink.AesSivKey" status:ENABLED key_id:1537855825 output_prefix_type:TINK}

Cipher1 is 015ba9d1518f3a5d213ce9630294f87af76ce86011c8631842aa96571d0dee03

Cipher2 is 015ba9d1518f3a5d213ce9630294f87af76ce86011c8631842aa96571d0dee03

Decrypted is Testing 123

10s 洞悉市场
协议隐私政策白皮书官方验证Cookie博客
sha512-gmb+mMXJiXiv+eWvJ2SAkPYdcx2jn05V/UFSemmQN07Xzi5pn0QhnS09TkRj2IZm/UnUmYV4tRTVwvHiHwY2BQ==
sha512-kYWj302xPe4RCV/dCeCy7bQu1jhBWhkeFeDJid4V8+5qSzhayXq80dsq8c+0s7YFQKiUUIWvHNzduvFJAPANWA==