简体   繁体   English

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

[英]Python 3 XChaCha20 test vectors work for encryption but decryption stage fails

I use the following vectors to test XChaCha20 encryption with AEAD by Poly1305 in python:我使用以下向量在 python 中使用 Poly1305 使用 AEAD 测试 XChaCha20 加密:

Vectors:矢量图:

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

pycryptodome: pycryptodome:

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

The drafts use HEX for the test vectors, if you really need to check me convert using this service:草稿使用 HEX 作为测试向量,如果您真的需要检查我是否使用此服务进行转换:

https://www.asciitohex.com/ 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']))

Why does my decryption stage fail if the test vectors encrypt correctly according to IETF-draft?如果测试向量根据 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=='

When I convert the byte arrays back to base64, they still match the JSON output.当我将字节 arrays 转换回 base64 时,它们仍然匹配 JSON Z78E6221F6393D14CED28666。 So reading my key values from JSON for decryption was done correctly.因此,从 JSON 读取我的密钥值以进行解密是正确的。

Where is the mistake?错误在哪里? I literally use a code example from the site offering pycryptodome and encryption was done correctly.我确实使用了提供 pycryptodome 的网站上的代码示例,并且加密已正确完成。 It should decrypt just fine.它应该解密就好了。

The decryption will be done correctly if you replace in the line如果您在该行中替换,解密将正确完成

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

the expression cipher.nonce with nonce_xchacha20 .带有nonce_xchacha20 cipher.nonce The bug causes an incorrect nonce to be supplied in the JSON.该错误会导致在 JSON 中提供不正确的随机数。

It seems that cipher.nonce can only be used to determine a randomly generated nonce (a random nonce is generated if no explicit nonce is specified when instantiating the cipher, s. here ).似乎cipher.nonce只能用于确定随机生成的随机数(如果在实例化密码时未指定显式随机数,则会生成随机随机数,s. here )。

A second (trivial) change is in the line第二个(微不足道的)变化即将到来

print("The message was: " + plaintext) 

necessary.必要的。 Here a UTF8 decoding must be performed, ie plaintext must be replaced by plaintext.decode('utf8') .这里必须执行 UTF8 解码,即plaintext必须替换为plaintext.decode('utf8')

In your first post, the AADs were also set incorrectly.在您的第一篇文章中,AAD 也设置不正确。 But this has been corrected in the meantime.但这已在此期间得到纠正。

With these two changes, the code, especially the decryption, works on my machine.通过这两个更改,代码,尤其是解密,可以在我的机器上运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM