Как мне расшифровать зашифрованный текст, зашифрованный с помощью AES, с помощью pycryptodome?

Я делаю менеджер паролей на Python, который хранит и шифрует пароли (с использованием модуля pycriptodome) с основным паролем, установленным пользователем, но расшифровка не работает. Вот функция, которую я использую для расшифровки паролей

def decrypt_data(key, iv, ct):  # Makes the credentials readable and usable
    print(f'{bcolors.warning}\nDebug decrypt_data(1):\tiv:\t\t\t{iv}') # debug text
    print(f'Debug decrypt_data(2):\tiv variable type:\t{type(iv)}') # debug text
    print(f'Debug decrypt_data(3):\tiv_bytes:\t\t{bytes(iv, 'utf-8')}') # debug text
    print(f'Debug decrypt_data(4):\tiv_bytes type:\t\t{type(bytes(iv, 'utf-8'))}\n{bcolors.endc}') # debug text
    cipher = AES.new(key, AES.MODE_CBC)
    pt = unpad(cipher.decrypt(bytes(ct, 'utf-8')), AES.block_size)
    print(f'{bcolors.okcyan}Decripting done{bcolors.endc}')
    return decrypted.decode("UTF-8")

Вывод консоли:

Debug decrypt_data(1):  iv:                     +00X7cdUZm7L61ifRb9EDQ==
Debug decrypt_data(2):  iv variable type:       <class 'str'>
Debug decrypt_data(3):  iv_bytes:               b'+00X7cdUZm7L61ifRb9EDQ=='
Debug decrypt_data(4):  iv_bytes type:          <class 'bytes'>

Traceback (most recent call last):
  File "D:\py_proj\Password Manager\.venv\Lib\pw_manager.py", line 151, in <module>
    print(f'{bcolors.warning}Debug main(5):\t\tdecrypted main_pw:\t{decrypt_data(padded_key, encrypt_data(padded_key, main_pw)[1], encrypt_data(padded_key, main_pw)[0])}') # debug text
                                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\py_proj\Password Manager\.venv\Lib\pw_manager.py", line 107, in decrypt_data
    pt = unpad(cipher.decrypt(bytes(ct, 'utf-8')), AES.block_size)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Utente\AppData\Local\Programs\Python\Python312\Lib\site-packages\Crypto\Cipher\_mode_cbc.py", line 246, in decrypt
    raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size)
ValueError: Data must be padded to 16 byte boundary in CBC mode

Для справки вот код шифрования, а также часть основной функции.

def encrypt_data(key, pt): # protects the credentials in the file once saved
    print(f'\nDebug encrypt_data(1):\tplaintext:\t\t{pt}') # debug text
    print(f'Debug encrypt_data(2):\tbytetext:\t\t{bytes(pt, 'utf-8')}') # debug text
    print(f'Debug encrypt_data(3):\tpadded plaintext:\t{pad(bytes(pt, 'utf-8'), AES.block_size)}') # debug text
    cipher = AES.new(key, AES.MODE_CBC)
    ct_bytes = cipher.encrypt(pad(bytes(pt, 'utf-8'), AES.block_size))
    print(f'Debug encrypt_data(4):\tct_bytes:\t\t{ct_bytes}') # debug text
    iv = b64encode(cipher.iv).decode('utf-8')
    ct = b64encode(ct_bytes).decode('utf-8')
    print(f'Debug encrypt_data(5):\tb64 decoded ct:\t\t{ct}') # debug text
    print(f'Debug encrypt_data(6):\tiv:\t\t\t{iv}') # debug text
    print(f'Debug encrypt_data(7):\tciphertext:\t\t{ct}\n') # debug text
    print(f'Encripting done')

    return ct, iv

if __name__ == '__main__':
    # login screen
    if not os.path.exists(credentials_file):
        signin()
    main_pw = login()
    padded_key = pad(bytes(main_pw, 'utf-8'), AES.block_size)  # Pad the key to the correct length
    print(f'Debug main(1):\t\tmain_pw:\t\t{main_pw}') # debug text
    print(f'Debug main(2):\t\tbyte_pw:\t\t{bytes(main_pw, 'utf-8')}') # debug text
    print(f'Debug main(3):\t\tpadded_key:\t\t{padded_key}') # debug text
    print(f'Debug main(4):\t\tencrypted main_pw:\t{encrypt_data(padded_key, main_pw)[0]}') # debug text
    print(f'Debug main(5):\t\tdecrypted main_pw:\t{decrypt_data(padded_key, encrypt_data(padded_key, main_pw)[1], encrypt_data(padded_key, main_pw)[0])}') # debug text
    print(f'Debug main(6):\t\tunpadded decrypted main_pw:\t{decrypt_data(padded_key, encrypt_data(padded_key, main_pw)[1], encrypt_data(padded_key, main_pw)[0])}\n') # debug text

это полный вывод консоли:

Debug main(1):          main_pw:                test
Debug main(2):          byte_pw:                b'test'
Debug main(3):          padded_key:             b'test\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c'

Debug encrypt_data(1):  plaintext:              test
Debug encrypt_data(2):  bytetext:               b'test'
Debug encrypt_data(3):  padded plaintext:       b'test\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c'
Debug encrypt_data(4):  ct_bytes:               b'I\xdd\x95\x9fXl"\xa1\xd9Xfd~\xc5\xc2\xcd'
Debug encrypt_data(5):  b64 decoded ct:         Sd2Vn1hsIqHZWGZkfsXCzQ==
Debug encrypt_data(6):  iv:                     lmuFGlygOos07SPYpBWNBw==
Debug encrypt_data(7):  ciphertext:             Sd2Vn1hsIqHZWGZkfsXCzQ==

Encripting done
Debug main(4):          encrypted main_pw:      Sd2Vn1hsIqHZWGZkfsXCzQ==

Debug encrypt_data(1):  plaintext:              test
Debug encrypt_data(2):  bytetext:               b'test'
Debug encrypt_data(3):  padded plaintext:       b'test\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c'
Debug encrypt_data(4):  ct_bytes:               b'\t\r\xfbd\x07\x1d\xcay>\xa49\xdeK\xd9W\xbb'
Debug encrypt_data(5):  b64 decoded ct:         CQ37ZAcdynk+pDneS9lXuw==
Debug encrypt_data(6):  iv:                     +00X7cdUZm7L61ifRb9EDQ==
Debug encrypt_data(7):  ciphertext:             CQ37ZAcdynk+pDneS9lXuw==

Encripting done

Debug encrypt_data(1):  plaintext:              test
Debug encrypt_data(2):  bytetext:               b'test'
Debug encrypt_data(3):  padded plaintext:       b'test\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c'
Debug encrypt_data(4):  ct_bytes:               b'=\xf6\xa4\xcetfD\xe4\x12\xef\xff\xce\x0f(]t'
Debug encrypt_data(5):  b64 decoded ct:         PfakznRmROQS7//ODyhddA==
Debug encrypt_data(6):  iv:                     w/FfW0RCcLqv8FjqRtCpxg==
Debug encrypt_data(7):  ciphertext:             PfakznRmROQS7//ODyhddA==

Encripting done

Debug decrypt_data(1):  iv:                     +00X7cdUZm7L61ifRb9EDQ==
Debug decrypt_data(2):  iv variable type:       <class 'str'>
Debug decrypt_data(3):  iv_bytes:               b'+00X7cdUZm7L61ifRb9EDQ=='
Debug decrypt_data(4):  iv_bytes type:          <class 'bytes'>

Traceback (most recent call last):
  File "D:\py_proj\Password Manager\.venv\Lib\pw_manager.py", line 151, in <module>
    print(f'Debug main(5):\t\tdecrypted main_pw:\t{decrypt_data(padded_key, encrypt_data(padded_key, main_pw)[1], encrypt_data(padded_key, main_pw)[0])}') # debug text
                                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\py_proj\Password Manager\.venv\Lib\pw_manager.py", line 107, in decrypt_data
    pt = unpad(cipher.decrypt(bytes(ct, 'utf-8')), AES.block_size)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Utente\AppData\Local\Programs\Python\Python312\Lib\site-packages\Crypto\Cipher\_mode_cbc.py", line 246, in decrypt
    raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size)
ValueError: Data must be padded to 16 byte boundary in CBC mode

[processo terminato con codice 1 (0x00000001)]

Я попробовал заполнить перед расшифровкой, используя pt = unpad(cipher.decrypt(pad(bytes(ct, 'utf-8'), AES.block_size)), AES.block_size) вместо pt = unpad(cipher.decrypt(pad(bytes(ct, 'utf-8'), AES.block_size)), AES.block_size), но выдал следующую ошибку:

Traceback (most recent call last):
  File "D:\py_proj\Password Manager\.venv\Lib\pw_manager.py", line 151, in <module>
    print(f'Debug main(5):\t\tdecrypted main_pw:\t{decrypt_data(padded_key, encrypt_data(padded_key, main_pw)[1], encrypt_data(padded_key, main_pw)[0])}') # debug text
                                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\py_proj\Password Manager\.venv\Lib\pw_manager.py", line 107, in decrypt_data
    pt = unpad(cipher.decrypt(pad(bytes(ct, 'utf-8'), AES.block_size)), AES.block_size)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Utente\AppData\Local\Programs\Python\Python312\Lib\site-packages\Crypto\Util\Padding.py", line 92, in unpad
    raise ValueError("Padding is incorrect.")
ValueError: Padding is incorrect.

[processo terminato con codice 1 (0x00000001)]

Вероятно, вам не следует использовать режим шифрования без аутентификации, такой как CBC. Вы же хотите быть уверены, что зашифрованный текст не был подделан (или поврежден), верно?

AKX 26.07.2024 14:49

Во-вторых: вы возвращаете decrypted.decode(...), но никогда ничего не назначаете decrypted. Я не думаю, что код, который вы нам показываете, поднимает эти проблемы.

AKX 26.07.2024 14:50

Ваша функция decrypt_data также не использует IV, который вы передаете в качестве аргумента.

AKX 26.07.2024 14:51

он передает аргумент iv, потому что в более старой версии программы я создавал зашифрованный объект с помощью cipher = AES.new(key, AES.MODE_CBC, iv=iv), но он выдал ошибку Incorrect IV length (it must be 16 bytes long)'. Removing iv=iv` эта ошибка больше не выводилась, но я все еще не могу проверить, расшифровывается ли он зашифрованные тексты правильно, с ним или без него, из-за моей главной проблемы, я думаю, это проблема для меня в будущем. Я не писал об этом, потому что забыл об этом.

vghbjc 26.07.2024 15:03

Конечно, вы должны использовать IV во время расшифровки. Ошибка в вашем коде заключается в отсутствии декодирования Base64 зашифрованного текста и IV во время расшифровки. Другая ошибка заключается в том, что в тестах 5 и 6 зашифрованный текст и IV несовместимы, поскольку они исходят от двух разных вызовов encrypt_data().

Topaco 26.07.2024 16:17
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
5
67
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот упрощенная и функциональная версия вашего кода, которая для простоты принимает простые текстовые строки в кодировке Base64 в качестве ключа и материала IV (их легко хранить, например, в текстовых файлах).

Обратите внимание, что режим CBC, вероятно, не то, что вам нужно, поскольку он не обеспечивает никакой аутентификации (т. е. вы получаете обратно текст, который был изначально зашифрован).

import base64
import secrets

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad, pad


def encrypt_data(key_str: str, plaintext: str) -> tuple[str, str]:
    key_bytes = base64.b64decode(key_str.encode("utf-8"))
    cipher = AES.new(key_bytes, AES.MODE_CBC)
    ct_bytes = cipher.encrypt(pad(plaintext.encode("utf-8"), AES.block_size))
    iv = base64.b64encode(cipher.iv).decode("utf-8")
    ciphertext = base64.b64encode(ct_bytes).decode("utf-8")
    return ciphertext, iv


def decrypt_data(key_str: str, iv_str: str, ciphertext_str: str) -> str:
    key_bytes = base64.b64decode(key_str.encode("utf-8"))
    iv_bytes = base64.b64decode(iv_str.encode("utf-8"))
    ciphertext_bytes = base64.b64decode(ciphertext_str.encode("utf-8"))
    cipher = AES.new(key_bytes, AES.MODE_CBC, iv=iv_bytes)
    plaintext_bytes = unpad(cipher.decrypt(ciphertext_bytes), AES.block_size)
    return plaintext_bytes.decode("UTF-8")


key_bytes = secrets.token_bytes(32)
key_str = base64.b64encode(key_bytes).decode("utf-8")
plaintext = "Hello, World!"

print(f"{key_str=}, {plaintext=}")
ciphertext, iv = encrypt_data(key_str, plaintext)
print(f"{ciphertext=}, {iv=}")
decrypted = decrypt_data(key_str, iv, ciphertext)
print(f"{decrypted=}")

Это распечатывает (например)

key_str='Zdu1DUQC/dZhGC8Q1n0raD8BlW7pfzLZxwmPqn0o6s8=', plaintext='Hello, World!'
ciphertext='Es7w8eWcRHGhfpwBDnr6vQ==', iv='Grf/VFkH8Qp7VS6RVj2e2g=='
decrypted='Hello, World!'

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