ValueError: длина зашифрованного текста должна быть равна размеру ключа - PullRequest
1 голос
/ 30 апреля 2020

Я знаю, что этот вопрос задавали много, но я до сих пор не понимаю, как я могу отлаживать свой код. Я гуглил этот вопрос уже более 3 дней, но просто не могу найти подходящий ответ для своего кода. Я хочу добавить зашифрованное сообщение с вводом, но каждый раз, когда я запускаю свой код, он просто выдает ошибку

Traceback (most recent call last):
  File "decryption.py", line 27, in <module>
    label=None
  File "/opt/anaconda3/lib/python3.7/site-packages/cryptography/hazmat/backends/openssl/rsa.py", line 357, in decrypt
    raise ValueError("Ciphertext length must be equal to key size.")
ValueError: Ciphertext length must be equal to key size.

. Я знаю это с меткой, но я просто не могу найти ответ. Вот мой код для расшифровки:

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

with open("private_key.pem", "rb") as key_file:
    private_key = serialization.load_pem_private_key(
        key_file.read(),
        password=None,
        backend=default_backend()
    )
with open("public_key.pem", "rb") as key_file:
    public_key = serialization.load_pem_public_key(
        key_file.read(),
        backend=default_backend()
    )

textInput = str(input(">>> "))
encrypted = textInput.encode() 


original_message = private_key.decrypt(
    encrypted,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

original_decoded_message = original_message.decode("utf-8")

print(original_decoded_message)

И для шифрования:

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization

private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
    backend=default_backend()
)
public_key = private_key.public_key()


pem = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.PKCS8,
    encryption_algorithm=serialization.NoEncryption()
)
with open('private_key.pem', 'wb') as f:
    f.write(pem)

pem = public_key.public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo
)
with open('public_key.pem', 'wb') as f:
    f.write(pem)


raw_message = str(input(">>> "))
message = raw_message.encode("utf-8")

encrypted = public_key.encrypt(
    message,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)


print(encrypted)


Я действительно новый в Asymmetri c шифрование / дешифрование.

1 Ответ

1 голос
/ 30 апреля 2020

Это незначительное изменение в части расшифровки вашего кода заставило его работать на меня:

textInput = str(input(">>> "))
# encrypted = textInput.encode()  #this is incorrect!
encrypted = eval(textInput)

Вот что я получаю:

Для части шифрования:

>>> test message
b'>xB)\xf1\xc5I\xd6\xce\xfb\xcf\x83\xe2\xc5\x8f\xcfl\xb9\x0f\xa2\x13\xa5\xe1\x03\xf7p\xb3\x9c\xeb\r\xc1"\xf2\x17\x8b\xea\t\xed\xb2xG\xb7\r\xa9\xf8\x03eBD\xdd9>\xbe\xd1O\xe2\x9f\xbb\xf9\xff5\x96l\xea\x17FI\x8d\x02\x05\xea\x1dpM\xbb\x04J\xfc\x0c\\\xfe\x15\x07\xaf \x9e\xc2\xf9M\xa4\x1d$\xc3\x99my\xb6\xc5\xad\x97\xd06\xd2\x08\xd3\xe2\xc8H\xca\xd8\xfd{\xe6\xc6\xa3\x18\xeb\xe6\xcc\xc5\x9a\xc8*\xbb\xc1\x8c\x80,\x1f\r@\x9b\x9d\xc5\x91I\xa8\xc01y\xbc\xa73\xd3\x19;\xef\x8a\xfb\xc2\xc4\x9e\xbe\x8f\xeb\x1d\x12\xbd\xe4<\xa0\xbb\x8d\xef\xee\xa3\x89E\x07"m\x1d\xb0\xf3\xd2:y\xd9\xbd\xef\xdf\xc9\xbb\x1b\xd5\x03\x91\xa4l\x8bS\x9e\x80\x14\x90\x18\xc4\x9e\\?\x8eF\x05\xa1H\x9e:\x0c\x96\x8e\xb3E3\x90\xa2\xa1\xd9\x88\xa0<X\x7f\rIP\x00\xbf\xf6\x15\xfb9tW\x17\x9f\xca\x95\xf6|\xd7\x90\xbcp\xe5\xb5,V\x1b\xe9\x90\xf6\x87 v=6'

Теперь для расшифровки я использую вывод:

>>> b'>xB)\xf1\xc5I\xd6\xce\xfb\xcf\x83\xe2\xc5\x8f\xcfl\xb9\x0f\xa2\x13\xa5\xe1\x03\xf7p\xb3\x9c\xeb\r\xc1"\xf2\x17\x8b\xea\t\xed\xb2xG\xb7\r\xa9\xf8\x03eBD\xdd9>\xbe\xd1O\xe2\x9f\xbb\xf9\xff5\x96l\xea\x17FI\x8d\x02\x05\xea\x1dpM\xbb\x04J\xfc\x0c\\\xfe\x15\x07\xaf \x9e\xc2\xf9M\xa4\x1d$\xc3\x99my\xb6\xc5\xad\x97\xd06\xd2\x08\xd3\xe2\xc8H\xca\xd8\xfd{\xe6\xc6\xa3\x18\xeb\xe6\xcc\xc5\x9a\xc8*\xbb\xc1\x8c\x80,\x1f\r@\x9b\x9d\xc5\x91I\xa8\xc01y\xbc\xa73\xd3\x19;\xef\x8a\xfb\xc2\xc4\x9e\xbe\x8f\xeb\x1d\x12\xbd\xe4<\xa0\xbb\x8d\xef\xee\xa3\x89E\x07"m\x1d\xb0\xf3\xd2:y\xd9\xbd\xef\xdf\xc9\xbb\x1b\xd5\x03\x91\xa4l\x8bS\x9e\x80\x14\x90\x18\xc4\x9e\\?\x8eF\x05\xa1H\x9e:\x0c\x96\x8e\xb3E3\x90\xa2\xa1\xd9\x88\xa0<X\x7f\rIP\x00\xbf\xf6\x15\xfb9tW\x17\x9f\xca\x95\xf6|\xd7\x90\xbcp\xe5\xb5,V\x1b\xe9\x90\xf6\x87 v=6'
test message

Проблема с вашим исходным кодом состоит в том, что вы пишете представление строки байтов в качестве Unicode string (при использовании print(encrypted)), затем кодирует его в байтовый объект в коде расшифровки, а затем передает его в функцию расшифровки. Кодирование этой строки не даст исходную строку байтов encrypted.

Этот пример иллюстрирует проблему:

>>> x = bytes(bytearray.fromhex('f3'))
>>> x #A bytes string, similar to encrypt
b'\xf3'
>>> print(x)
b'\xf3'
>>> len(x)
1
>>> str(x) #this is what print(x) writes to stdout
"b'\\xf3'"
>>> print(str(x))
b'\xf3'
>>> len(str(x)) #Note that the lengths are different!
7 
>>> x == str(x)
False
>>> str(x).encode() #what you were trying to do
b"b'\\xf3'"
>>> x == str(x).encode()
False
>>> eval(str(x)) #what gets the desired result
b'\xf3'
>>> x == eval(str(x))
True

Дело в том, что функция print печатает представление объекта, а не сам объект. По сути, он делает это, получая значение для печати непечатаемых объектов, используя методы __repr__ или __str__ методов этого объекта.

Это документация для __str__:

Вызывается str(object) и встроенными функциями format() и print() для вычисления «неформального» или «приятного» печатное строковое представление объекта. Возвращаемое значение должно быть строковым объектом. , , Реализация по умолчанию, определяемая объектами встроенного типа, вызывает object.__repr__().

и __repr__:

Вызывается встроенной функцией repr() для вычислить «официальное» строковое представление объекта. Если это вообще возможно, это должно выглядеть как действительное выражение Python, которое можно использовать для воссоздания объекта

Это "официальное" представление, возвращаемое __repr__, позволило мне использовать eval функция в расшифровочном коде для решения проблемы.

TL; DR : копирование вывода print(encrypted) копирует неофициальное, читаемое человеком значение, возвращаемое encrypted.__str__() или "официальное" представление, возвращаемое encrypted.__repr__(), которые находятся в удобочитаемой кодировке, такой как utf-8. Они не могут быть закодированы обратно (с использованием кодировки utf-8) для создания исходной строки байтов, которую они представляют.

Стоит также изучить этот вопрос от пользователя stackoverflow, обращенного к та же проблема. Ответ дает способ фактически закодировать это представление обратно в байтовый объект, если хотите. Это стоит посмотреть, потому что eval следует избегать, это очень небезопасно . Для того, чтобы этот метод работал, вы должны были бы удалить начальную b' и конечную ' из строки textInput перед ее кодированием.

Моя последняя рекомендация - передать весь объект encrypted между двумя программами, используя файлы с модулем pickle, или какую-либо форму программирования сокетов. Лучше избегать использования print и input для передачи данных между программами во избежание проблем с кодировкой.

...