Тестовые векторы Python 3 XChaCha20 работают для шифрования, но этап дешифрования не выполняется

Я использую следующие векторы для тестирования шифрования XChaCha20 с помощью AEAD от Poly1305 в python:

Векторы:

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

криптодом:

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

В черновиках для тестовых векторов используется HEX, если вам действительно нужно проверить конвертацию с помощью этого сервиса:

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 для расшифровки было выполнено правильно.

Где ошибка? Я буквально использую пример кода с сайта, предлагающего pycryptodome, и шифрование было выполнено правильно. Он должен нормально расшифровываться.

1 ответ

Расшифровка будет сделана правильно, если заменить в строке

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

выражение с nonce_xchacha20. Ошибка приводит к тому, что в JSON предоставляется неправильный одноразовый номер.

Кажется, что cipher.nonceможет использоваться только для определения случайно сгенерированного одноразового номера (случайный одноразовый номер генерируется, если при создании экземпляра шифра не указан явный одноразовый номер, см. здесь).

Второе (тривиальное) изменение находится в строке

      print("The message was: " + plaintext) 

необходимый. Здесь необходимо выполнить декодирование UTF8, т.е. plaintextдолжен быть заменен на plaintext.decode('utf8').

В вашем первом посте ААДы тоже были выставлены неправильно. Но это было исправлено в то же время.

С этими двумя изменениями код, особенно расшифровка, работает на моей машине.

Другие вопросы по тегам