ValueError: Ciphertext length must be equal to key size

ValueError: Ciphertext length must be equal to key size

我知道这个问题被问了很多,但我仍然不太明白如何调试我的代码。我在谷歌上搜索这个问题已经超过 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)


我对非对称加密/解密真的很陌生。

你的代码的解密部分的这个小修改使它对我有用:

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 字符串(使用 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 function prints the representation of the object rather than the object itself. Essentially, it does this by getting a printable value of inherently unprintable objects by using __repr__ or __str__ 方法。

这是 __str__ 的文档:

Called by str(object) and the built-in functions format() and print() to compute the “informal” or nicely printable string representation of an object. The return value must be a string object. . . The default implementation defined by the built-in type object calls object.__repr__().

__repr__

Called by the repr() built-in function to compute the “official” string representation of an object. If at all possible, this should look like a valid Python expression that could be used to recreate an object

__repr__ 返回的 "official" 表示允许我在解密代码中使用 eval 函数来解决问题。

TL;DR: 复制 print(encrypted) 的输出会复制 encrypted.__str__() 返回的非正式的、人类可读的值或 encrypted.__repr__() 返回的 "official" 表示,它们都是人类可读的编码,例如 utf-8。它们不能被编码回来(通过使用 utf-8 编码)来创建它们所代表的原始字节字符串。

question from a Whosebug user, facing the same issue. The answer gives a way to actually encode this representation back into a bytes object if you want. It's worth looking into this because eval should be avoided, it is very unsafe 也值得研究。要使该方法起作用,您必须在编码之前从字符串 textInput 中删除前导 b' 和尾随 '

我的最终建议是通过使用带有 pickle 模块的文件或某种形式的套接字编程,在两个程序之间传递整个对象 encrypted。最好不要使用 printinput 在程序之间传递这样的数据,以避免编码问题。