0

我正在实现一个可以加密和解密二维码内容的python包。我制作了一个名为 的模块rsa_module.py,用于对消息进行加密和解密,如下所示:

from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes
from Crypto.Cipher import AES, PKCS1_OAEP
import os

def generate_keys(secret_code):
    key = RSA.generate(2048)
    encrypted_key = key.exportKey(passphrase=secret_code, pkcs=8,
                                  protection="scryptAndAES128-CBC")

    output_directory=os.path.dirname(os.path.abspath(__file__))+'/Keys/'
    if(os.path.exists(output_directory)):
        # Save encrypted private key
        file_out = open(output_directory + "/rsa_private_key.pem", "wb")
        file_out.write(encrypted_key)
        # Save public key
        file_out = open(output_directory + "/rsa_public_key.pem", "wb")
        file_out.write(key.publickey().exportKey())
    else:
        os.mkdir(output_directory)
        # Save encrypted private key
        file_out = open(output_directory + "/rsa_private_key.pem", "wb")
        file_out.write(encrypted_key)
        # Save public key
        file_out = open(output_directory + "/rsa_public_key.pem", "wb")
        file_out.write(key.publickey().exportKey())

def encrypt(message):
    output_directory=os.path.dirname(os.path.abspath(__file__))+'/Keys/'

    with open('encrypted_data.txt', 'wb') as out_file:
        recipient_key = RSA.import_key(
        open(output_directory + '/rsa_public_key.pem').read())
        session_key = get_random_bytes(16)
        cipher_rsa = PKCS1_OAEP.new(recipient_key)
        out_file.write(cipher_rsa.encrypt(session_key))

        cipher_aes = AES.new(session_key, AES.MODE_EAX)
        encoded = message.encode("latin-1")
        data = encoded
        ciphertext, tag = cipher_aes.encrypt_and_digest(data)
        out_file.write(cipher_aes.nonce)

        out_file.write(tag)

        out_file.write(ciphertext)

    with open('encrypted_data.txt', 'rb') as fobj:
        output = [l for l in fobj.readlines()]
    os.remove('encrypted_data.txt')
    return output

def decrypt(encrypted_message, secret_code):
    code = secret_code
    output_directory=os.path.dirname(os.path.abspath(__file__))+'/Keys/'

    with open('encrypted_data.txt', 'wb') as temp_file:
        for item in (encrypted_message):
            temp_file.write(item)
    with open('encrypted_data.txt', 'rb') as fobj:
        private_key = RSA.import_key(
        open(output_directory + '/rsa_private_key.pem').read(),
        passphrase=code)
        enc_session_key, nonce, tag, ciphertext = [ fobj.read(x) 
        for x in (private_key.size_in_bytes(), 
        16, 16, -1) ]
        cipher_rsa = PKCS1_OAEP.new(private_key)
        session_key = cipher_rsa.decrypt(enc_session_key)
        cipher_aes = AES.new(session_key, AES.MODE_EAX, nonce)
        data = cipher_aes.decrypt_and_verify(ciphertext, tag)

    os.remove('encrypted_data.txt')
    return data.decode('utf8')

def main():
    generate_keys('secret one')
    encrypted = encrypt('blah blah blah blo')
    #encrypt_file('blah blah blah blo')
    print('Encryption Complete!')
    print('Decrypting message now....')
    print(encrypted)
    print(decrypt(encrypted, 'secret one'))
    #decrypt_file('secret one')

if __name__=='__main__': main()

如果我运行此脚本,则消息将被成功加密和解密。但是,当我在另一个模块中使用相同的函数时,从 QR 码中解密消息,我得到一个错误。该二维码解密模型名称为decrypt_qr.py,代码如下:

from qrtools import qrtools
from PIL import Image
import zbarlight
import os
from rsa_module import decrypt as de

def decrypt(file_name, password):
    keys_directory=os.path.dirname(os.path.abspath(__file__))+'/Keys/'
    private_key_path = keys_directory + '/rsa_private_key.pem'

    if(os.path.exists(private_key_path)):
        output_directory=os.path.dirname(os.path.abspath(__file__))+'/Output/'
        file_path = output_directory + file_name + '.PNG'
        with open(file_path, 'rb') as image_file:
            image = Image.open(image_file)
            image.load()
        codes = zbarlight.scan_codes('qrcode', image)
        decoded_result=codes[0].decode('utf8')
        print(codes[0].decode('utf8'))
        return de(decoded_result, password)
    else:
        print('No Public key available. Generate Public key and Private key first.')
        return None

def main():
    print(decrypt('my-qr','My secret'))

if __name__=='__main__': main()

如果我运行decrypt_qr.py,我会收到以下错误:

Traceback (most recent call last):   
  File "decrypt_qr.py", line 28, in <module>
    if __name__=='__main__': main()   
  File "decrypt_qr.py", line 26, in main
    print(decrypt('my-qr','My secret'))   
  File "decrypt_qr.py", line 20, in decrypt
    return de(decoded_result, password)   
  File "/Users/king/Documents/pyWorkspace/Encrypted_QR_Code_Using_AES/rsa_module.py", line 93, in decrypt
    temp_file.write(item)
TypeError: a bytes-like object is required, not 'str'

但是,如果我rsa_module.py只使用传递的消息运行它,那么它确实会正确解密。谁能建议我哪里出错了?

名为 的加密模块encrypt_qr.py如下:

from generate_qr import make_qr_and_save
from rsa_module import encrypt as en
from rsa_module import generate_keys
import os

def encrypt(message, filename, password, size=3):
    generate_keys(password)
    keys_directory=os.path.dirname(os.path.abspath(__file__))+'/Keys/'
    public_key_path = keys_directory + '/rsa_public_key.pem'

    if(os.path.exists(public_key_path)):
        encrypted_message = en(message)
        print('\n')
        print(encrypted_message)
        make_qr_and_save(encrypted_message, filename, size)
    else:
        print('No Public key available. Generate Public key and Private key first.')
        return None

def main():
    encrypt('Buzz off!','my-qr','My secret')

if __name__=='__main__': main()

如果我运行encrypt_qr.py脚本,则 qr 代码会正确生成并包含加密的字节流,然后在解密脚本 ( decrypt_qr.py) 中使用。

4

1 回答 1

0

您正在传递text,从 UTF-8 解码:

decoded_result=codes[0].decode('utf8')
# ...
return de(decoded_result, password)   

但是您的decrypt()函数期望这是bytes,因为您以二进制模式打开了文件:

def decrypt(encrypted_message, secret_code):
    # ...
    with open('encrypted_data.txt', 'wb') as temp_file:
        for item in (encrypted_message):
            temp_file.write(item)  

而是传入一个字节序列,而不是单个str对象:

decoded_result = codes[0]
# ...
return de([decoded_result], password)   

请注意,(encrypted_message)in与不带括号for item in (encrypted_message):的含义相同。encrypted_message仅用于对(...)元素进行分组,不创建元组。如果您要传入单个bytes对象,您将遍历一个整数序列(表示对象中的各个字节)。

此外,无需将数据写入磁盘上的文件。您可以将io.BytesIO()对象用于内存中的文件,或者将消息分割成正确的块大小。在此处使用磁盘上的文件实际上会使代码比实际更复杂,并且您对/tmp路径进行了硬编码(不同的操作系统使用不同的路径,tempfile模块可以为您抽象出来)。

于 2018-03-10T17:11:20.943 回答