Python 3 XChaCha20 测试向量可用于加密,但解密阶段失败

标签 python encryption cryptography ietf

我使用以下向量在 python 中通过 Poly1305 的 AEAD 测试 XChaCha20 加密:

向量:

https://datatracker.ietf.org/doc/html/draft-arciszewski-xchacha-03#appendix-A.3

pycryptodome:

https://pycryptodome.readthedocs.io/en/latest/src/cipher/chacha20_poly1305.html

草稿使用十六进制作为测试向量,如果您确实需要检查我使用此服务进行转换:

https://www.asciitohex.com/

import json
from base64 import b64encode
from base64 import b64decode
from Crypto.Cipher import ChaCha20_Poly1305
from Crypto.Random import get_random_bytes

#nonce_xchacha20 = get_random_bytes(24)
nonce_xchacha20 = b64decode("QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX")

#header = b"header"
header = b64decode("UFFSU8DBwsPExcbH")
plaintext = b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it."
#key = get_random_bytes(32)
key = b64decode("gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp8=")
cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce_xchacha20)
cipher.update(header)
ciphertext, tag = cipher.encrypt_and_digest(plaintext)

jk = [ 'nonce', 'header', 'ciphertext', 'tag' ]
jv = [ b64encode(x).decode('utf-8') for x in (cipher.nonce, header, ciphertext, tag) ]
result = json.dumps(dict(zip(jk, jv)))
print(result)

# We assume that the key was securely shared beforehand
try:
    b64 = json.loads(result)
    jk = [ 'nonce', 'header', 'ciphertext', 'tag' ]
    jv = {k:b64decode(b64[k]) for k in jk}

    cipher = ChaCha20_Poly1305.new(key=key, nonce=jv['nonce'])
    cipher.update(jv['header'])
    plaintext = cipher.decrypt_and_verify(jv['ciphertext'], jv['tag'])
    print("The message was: " + plaintext)
except (ValueError, KeyError):
    print("Incorrect decryption")

print("sanity check if key values are the same: ")
print(b64encode(jv['nonce']))
print(b64encode(jv['header']))
print(b64encode(jv['ciphertext']))
print(b64encode(jv['tag']))

如果测试向量根据 IETF 草案正确加密,为什么我的解密阶段会失败?

{"nonce": "AAAAAFBRUlNUVVZX", "header": "UFFSU8DBwsPExcbH", "ciphertext": "vW0XnT6D1DuVdleUk8DpOVcqFwAlK/rMvtKQLCE5bLtzHH8bC0qmRAvzqC9O2n45rmTGcIxUwhbLlrcuEhO0Ui+Mm6QNtdlFsRtpuYLBu54/P6wrw2lIj3ayODVl0//5IflmTJdjfal2iBL2FcaLE7Uu", "tag": "wIdZJMHHmHlH3q/YeArPSQ=="}
Incorrect decryption
sanity check if key values are the same:
b'AAAAAFBRUlNUVVZX'
b'UFFSU8DBwsPExcbH'
b'vW0XnT6D1DuVdleUk8DpOVcqFwAlK/rMvtKQLCE5bLtzHH8bC0qmRAvzqC9O2n45rmTGcIxUwhbLlrcuEhO0Ui+Mm6QNtdlFsRtpuYLBu54/P6wrw2lIj3ayODVl0//5IflmTJdjfal2iBL2FcaLE7Uu'
b'wIdZJMHHmHlH3q/YeArPSQ=='

当我将字节数组转换回 Base64 时,它们仍然与 JSON 输出匹配。 因此,从 JSON 读取 key 值进行解密是正确的。

哪里错了?我确实使用了提供 pycryptodome 的网站上的代码示例,并且加密已正确完成。它应该可以很好地解密。

最佳答案

如果您替换该行,解密将正确完成

jv = [ b64encode(x).decode('utf-8') for x in (cipher.nonce, header, ciphertext, tag) ]

表达式cipher.noncenonce_xchacha20。该错误会导致在 JSON 中提供不正确的随机数。

似乎 cipher.nonce 只能用于确定随机生成的随机数(如果在实例化密码时未指定显式随机数,则会生成随机随机数,s. here )。

第二个(微不足道的)更改即将进行

print("The message was: " + plaintext) 

有必要。这里必须执行UTF8解码,即plaintext必须替换为plaintext.decode('utf8')

在您的第一篇文章中,AAD 也设置不正确。但与此同时,此问题已得到纠正。

通过这两项更改,代码(尤其是解密部分)可​​以在我的计算机上运行。

关于Python 3 XChaCha20 测试向量可用于加密,但解密阶段失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66063475/

相关文章:

encryption - 如何从文件中读取加密文本并解密?

security - 可以存储可以检索的密码吗?

c# - 如何获取 "left-most 128 bits of a byte array"?

python pandas 基于列值的子字符串

python - 使用ndb和python从GAE中通过URL传递的自动分配的ID中检索 key

python - matplotlib hist 函数参数密度不起作用

python - 如何防止 python 服务器写入终端窗口?

javascript - JSEncrypt RSA 2048 加密输出大小

android - 如何确保文件从手机传输到服务器而不被篡改?

java - 验证 RSA SHA256 签名无法从证书获取私钥