Почему проверка MAC-адреса Pycryptodome не работает при шифровании и расшифровке файлов JSON?

Я пытаюсь зашифровать некоторые данные JSON с помощью AES-256, используя в качестве ключа пароль, хешированный с помощью pbkdf2_sha256. Я хочу хранить данные в файле, иметь возможность загружать их, расшифровывать, изменять, шифровать, сохранять и повторять.

Я использую библиотеки passlib и pycryptodome с python 3.8. Следующий тест выполняется внутри док-контейнера и выдает ошибку, которую я не смог исправить.

Кто-нибудь знает, как я могу улучшить свой код (и знания)?

Test.py:

import os, json
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES
from passlib.hash import pbkdf2_sha256

def setJsonData(jsonData, jsonFileName):
    with open(jsonFileName, 'wb') as jsonFile:
        password = 'd'
        key = pbkdf2_sha256.hash(password)[-16:]

        data = json.dumps(jsonData).encode("utf8")
        cipher = AES.new(key.encode("utf8"), AES.MODE_EAX)
        ciphertext, tag = cipher.encrypt_and_digest(data)

        [ jsonFile.write(x) for x in (cipher.nonce, tag, ciphertext) ]

def getJsonData(jsonFileName):
   with open(jsonFileName, 'rb') as jsonFile:
        password = 'd'
        key = pbkdf2_sha256.hash(password)[-16:]

        nonce, tag, ciphertext = [ jsonFile.read(x) for x in (16, 16, -1) ]
        cipher = AES.new(key.encode("utf8"), AES.MODE_EAX, nonce)
        data = cipher.decrypt_and_verify(ciphertext, tag)

        return json.loads(data)


dictTest = {}
dictTest['test'] = 1

print(str(dictTest))
setJsonData(dictTest, "test")

dictTest = getJsonData("test")
print(str(dictTest))

Вывод:

{'test': 1}
Traceback (most recent call last):
  File "test.py", line 37, in <module>
    dictTest = getJsonData("test")
  File "test.py", line 24, in getJsonData
    data = cipher.decrypt_and_verify(ciphertext, tag)
  File "/usr/local/lib/python3.8/site-packages/Crypto/Cipher/_mode_eax.py", line 368, in decrypt_and_verify
    self.verify(received_mac_tag)
  File "/usr/local/lib/python3.8/site-packages/Crypto/Cipher/_mode_eax.py", line 309, in verify
    raise ValueError("MAC check failed")
ValueError: MAC check failed

Исследования:

  • Просмотрел этот ответ, но я считаю, что мой verify() вызов находится в нужное место

  • #P8# <блочная цитата> #P9# #P10#
  • Я подозревал, что проблема в форматировании json, поэтому я сделал тот же тест со строкой и не делал вызовы json.loads и json.dumps, но у меня та же ошибка.


person Uriah Wardlaw    schedule 15.12.2019    source источник


Ответы (1)


Проблема здесь в том, что key = pbkdf2_sha256.hash(password)[-16:] хэширует ключ с новой солью при каждом вызове. Следовательно, шифр, используемый для шифрования и дешифрования зашифрованного текста, будет отличаться, давая разные данные и, таким образом, не пройдя проверку целостности.

Я изменил свою ключевую функцию вывода на следующее:

h = SHA3_256.new()
h.update(password.encode("utf-8"))
key = h.digest()
person Uriah Wardlaw    schedule 15.12.2019