RSA 加密数据从字节转换为字符串并返回字节?

RSA Encrypted data convert from bytes to string and back to bytes?

我正在尝试通过套接字通信在多个客户端之间使用 public 密钥加密实现对称密钥协议方案,并且我一直在测试加密和解密功能。​​

import rsa

def generateAKeys():
    (publicKey, privateKey) = rsa.newkeys(1024)
    with open('keys/APubKey.pem', 'wb') as p:
        p.write(publicKey.save_pkcs1('PEM'))
    with open('keys/APrivKey.pem', 'wb') as p:
        p.write(privateKey.save_pkcs1('PEM'))

def generateBKeys():
    (publicKey, privateKey) = rsa.newkeys(1024)
    with open('keys/BPubKey.pem', 'wb') as p:
        p.write(publicKey.save_pkcs1('PEM'))
    with open('keys/BPrivKey.pem', 'wb') as p:
        p.write(privateKey.save_pkcs1('PEM'))

def loadKeys():
    with open('keys/APubKey.pem', 'rb') as p:
        APubKey = rsa.PublicKey.load_pkcs1(p.read())
    with open('keys/APrivKey.pem', 'rb') as p:
        APrivKey = rsa.PrivateKey.load_pkcs1(p.read())
    with open('keys/BPubKey.pem', 'rb') as p:
        BPubKey = rsa.PublicKey.load_pkcs1(p.read())
    with open('keys/BPrivKey.pem', 'rb') as p:
        BPrivKey = rsa.PrivateKey.load_pkcs1(p.read())
    return APubKey, APrivKey, BPubKey, BPrivKey

def encrypt(message, key):
    return rsa.encrypt(message.encode('utf8'), key)

def decrypt(ciphertext, key):
    try:
        return rsa.decrypt(ciphertext, key).decode('utf8')
    except:
        return False

def sign(message, key):
    return rsa.sign(message.encode('utf8'), key, 'SHA-1')

def verify(message, signature, key):
    try:
        return rsa.verify(message.encode('utf8'), signature, key,) == 'SHA-1'
    except:
        return False


APubKey, APrivKey, BPubKey, BPrivKey = loadKeys()

message = 'Hello'
ciphertext = encrypt(message, BPubKey)
print(ciphertext)
print(type(ciphertext))

signature = sign(message, APrivKey)

message1 = "{}|{}".format(ciphertext, signature)

#Simulating message transfer over socket

message2 = message1 #Recived Messgae

message2 = message2.split("|")

ciphertext1, signature1 = message2[0], message2[1]

print(ciphertext1)
print(type(ciphertext1))

print(ciphertext == ciphertext1)
plaintext = decrypt(ciphertext1, BPrivKey)

if plaintext:
    print(f'Message text: {plaintext}')
else:
    print(f'Unable to decrypt the message.')

if verify(plaintext, signature1, APubKey):
    print('Successfully verified signature')
else:
    print('The message signature could not be verified')

在客户端之间来回发送的信息被打包成以下格式 message1 = "{}|{}".format(ciphertext, signature),这样就可以将消息拆分并分段读取。在这个文件中,我只是将消息打包成这种格式来模拟客户端之间的传输。

我的问题是,一旦创建了加密消息(以字节为单位)并将其打包为上面显示的格式,它就会转换为字符串。当我尝试提取该加密消息并对其进行解密时,我做不到,因为它不再是字节格式。我试过将字符串转换为字节但无济于事。任何帮助将不胜感激。

下面是输出的副本,其中加密的字节被转换为完全相同的字符串

b'\x8d\x19b\xbbE\xc1\xbf/K\x8b_}\xae\x0c\xb3\x8b\x94\x19\xfb\x8e\x01q6\xf5\xdd2O\\xd2\xbf\xe3\xca\xcf\xac\x03\x84\xe9\xd7\xce\x13\xaaB\x16x\x13\xb4x26\xfc\x1c\xfe6\x82\xf6\x89i\x8aT\x87\xa0\xe9\x85p\xea\x03\x0fK\xb1/\xe0\x1b\x10a\x83\xa2\x0b}b\x0b\xc3\xe1"\xc1\x94\xfa\x95\xb0iQ\xa8%sqs\xc9\x98`gd,\xdc;\xa3\x08\xb6\xc3T:2N\xede-\x16\xe6i\xdc?3\x1d\x8c\x12^\x10\xde*\xc5'
<class 'bytes'>
b'\x8d\x19b\xbbE\xc1\xbf/K\x8b_}\xae\x0c\xb3\x8b\x94\x19\xfb\x8e\x01q6\xf5\xdd2O\\xd2\xbf\xe3\xca\xcf\xac\x03\x84\xe9\xd7\xce\x13\xaaB\x16x\x13\xb4x26\xfc\x1c\xfe6\x82\xf6\x89i\x8aT\x87\xa0\xe9\x85p\xea\x03\x0fK\xb1/\xe0\x1b\x10a\x83\xa2\x0b}b\x0b\xc3\xe1"\xc1\x94\xfa\x95\xb0iQ\xa8%sqs\xc9\x98`gd,\xdc;\xa3\x08\xb6\xc3T:2N\xede-\x16\xe6i\xdc?3\x1d\x8c\x12^\x10\xde*\xc5'
<class 'str'>
False
Unable to decrypt the message.
The message signature could not be verified

这是一个正常的过程;加密后你肯定有 non-printable 个字符,甚至可能比可打印的字符更多。

为了使过程更加对称,您应该使用 字节字符串 而不是纯文本和密文的字符串,后者在 Python 中由前导 b 表示如 b"hello"。 (可用的加密模块也需要所有内容的字节字符串,这是加密文件(例如图片)的唯一方法)。请注意,bytesbyte strings 之间没有区别,只是表示法不同,因此您不必寻找编码对于每个普通字符 - 如果您已经有字节,则不需要转换

特别是在 Python 3 中,其内在使用 unicode 查看 codecs 单元可能会有所帮助。

我发现是他造成的,修改了你的代码使其工作(你仍然有编译错误,BTW),但我不会 post 它这里看起来很丑(代码风格明智 - 检查 [Python.PEPs]: PEP 8 - Style Guide for Python Code),我不想格式化整个东西。

问题是 message1 = "{}|{}".format(ciphertext, signature) 弄乱了(字节)字符串,当消息被拆分回来时(message2 = message2.split("|"))结果与 ciphertext签名
请注意,通过简单地 printing 变量 (print(message2, ciphertext, signature)) 很容易发现这些东西。

在我看来,熟悉 [Python.Docs]: Built-in Types - Bytes Objects.

不会对您造成伤害

可能的修复:

  • 发送时

    SEPARATOR = b"|"  # Notice the `b` prefix (byte string literal)
    message1 = ciphertext + SEPARATOR + signature
    
  • 接收时:

    message2 = message2.split(SEPARATOR)
    

输出:

[cfati@CFATI-5510-0:e:\Work\Dev\Whosebug\q071720539]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" orig.py
b"~\xd2\xdc\xdf\xde\x84U\xe0\x88\x82\x1e\xa4\x17Q`Wu\x03\x04)\xac\x88\xe9P\xa5E\x05I\x1d_\xa7\x03%\x0ckYZ\xf5\xc6\xcd=,nTF\xf4\x14\xae\x96E-\xa3I\x06\x06\x84_W\xd3f\xefQ3_;$\x03\x9e\xc1\x94P\xab\xf8\xa0\xaf#'\xdf\xaf\n< \xec\x14\x9b9E\xce\x9e 9\xaeH\xf4)R\xed\xdaD\xc5\x9e^j\xd7L>W\x07i\x91^T\xd6u\xf4E\x9dk\xe5VV\x04_\xa2s\xad\xae\xad"
<class 'bytes'>
True
b"~\xd2\xdc\xdf\xde\x84U\xe0\x88\x82\x1e\xa4\x17Q`Wu\x03\x04)\xac\x88\xe9P\xa5E\x05I\x1d_\xa7\x03%\x0ckYZ\xf5\xc6\xcd=,nTF\xf4\x14\xae\x96E-\xa3I\x06\x06\x84_W\xd3f\xefQ3_;$\x03\x9e\xc1\x94P\xab\xf8\xa0\xaf#'\xdf\xaf\n< \xec\x14\x9b9E\xce\x9e 9\xaeH\xf4)R\xed\xdaD\xc5\x9e^j\xd7L>W\x07i\x91^T\xd6u\xf4E\x9dk\xe5VV\x04_\xa2s\xad\xae\xad"
<class 'bytes'>
True
Message text: Hello
Successfully verified signature

不用说SEPARATOR两端要一样

注意: 管道字符(|, 竖线) 似乎是一个过于简单的值。如果您的输入字符串之一包含它(并且不能保证它不会),那么在拆分消息时,接收端会大吃一惊。因此,为了大大减少碰撞几率,您应该将其设置为更复杂的东西:

SEPARATOR = b"~!@#$%^&*()_+-=AbCd1234"