我如何使用 pycryptodome 解密使用 AES 加密的密文?

问题描述 投票:0回答:1

我正在用 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)]
python encryption pycrypto pycryptodome
1个回答
0
投票

这是代码的简化版和功能版本,为简单起见,它接受 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!'
© www.soinside.com 2019 - 2024. All rights reserved.