尝试解密加密的 .docx 文件时出现字体错误

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

我正在开发一个项目,该项目创建一个框架,用于使用 RSA 保护用 Python 编写的用户登录信息。当我尝试运行该框架时,一切都很正常,直到进入解密阶段。在显示字母字体选项的框中。预览文本的字体似乎有错误。 enter image description here enter image description here

def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

def mod_inverse(a, m):
    if gcd(a, m) != 1:
        return None
    u1, u2, u3 = 1, 0, a
    v1, v2, v3 = 0, 1, m
    while v3 != 0:
        q = u3 // v3
        v1, v2, v3, u1, u2, u3 = u1 - q * v1, u2 - q * v2, u3 - q * v3, v1, v2, v3
    return u1 % m

def generate_keypair(p, q):
    n = p * q
    phi = (p - 1) * (q - 1)
    e = random.randrange(1, phi)
    g = gcd(e, phi)
    while g != 1:
        e = random.randrange(1, phi)
        g = gcd(e, phi)
    d = mod_inverse(e, phi)
    return (e, n), (d, n)

def encrypt(message, public_key):
    e, n = public_key
    cipher = [pow(ord(char), e, n) for char in message]
    return cipher

def decrypt(cipher, private_key):
    d, n = private_key
    message = [chr(pow(char, d, n)) for char in cipher]
    return ''.join(message)

def browse_file():
    filepath = filedialog.askopenfilename()
    file_entry.delete(0, tk.END)
    file_entry.insert(tk.END, filepath)

def encrypt_file():
    p = 61
    q = 53
    public_key, _ = generate_keypair(p, q)
    filepath = file_entry.get()
    try:
        with open(filepath, "r", encoding="utf-8") as f:
            plaintext = f.read()
    except UnicodeDecodeError:
        with open(filepath, "r", encoding="latin-1") as f:  # Sử dụng mã hóa "latin-1" nếu gặp lỗi UnicodeDecodeError
            plaintext = f.read()
    encrypted_data = encrypt(plaintext, public_key)
    encrypted_filepath = filepath + ".encrypted"
    with open(encrypted_filepath, "w", encoding="utf-8") as f:
        f.write(' '.join(map(str, encrypted_data)))
    result_label.config(text="File encrypted successfully.")

def decrypt_file():
    p = 61
    q = 53
    _, private_key = generate_keypair(p, q)
    filepath = file_entry.get()
    
    try:
        with open(filepath, "r", encoding="utf-8") as f:  # Sử dụng mã hóa utf-8
            encrypted_data = f.read().split()
    except UnicodeDecodeError:
        result_label.config(text="Failed to open decrypted file: Invalid encoding (UTF-8)")
        return
    
    encrypted_data = list(map(int, encrypted_data))
    decrypted_data = decrypt(encrypted_data, private_key)
    
    # Create a decrypted file with a ".decrypted" extension
    decrypted_filepath = filepath[:-10]  # Remove ".encrypted" from the end of the file name
    decrypted_filepath += ".decrypted"
    
    # Convert decrypted data to bytes before writing (using utf-8 encoding)
    decrypted_data_bytes = bytes(decrypted_data, 'utf-8')
    
    try:
        with open(decrypted_filepath, "wb") as f:
            f.write(decrypted_data_bytes)
    except Exception as e:
        result_label.config(text="Failed to open decrypted file: " + str(e))
        return
    
    result_label.config(text="File decrypted successfully.")
    
    # Open the decrypted file
    try:
        with open(decrypted_filepath, "rb") as f:
            decrypted_data_bytes = f.read()
            # Now you can work with the decrypted_data_bytes as needed
    except Exception as e:
        result_label.config(text="Failed to open decrypted file: " + str(e))

browse_button = tk.Button(window, text="Browse", command=browse_file)
browse_button.place(x=290, y=120)

encrypt_button = tk.Button(window, text="Encrypt", command=encrypt_file)
encrypt_button.place(x=290, y=170)

decrypt_button = tk.Button(window, text="Decrypt", command=decrypt_file)
decrypt_button.place(x=290,y=220)

result_label = tk.Label(window, bg='#99CCFF')
result_label.place(x=240, y= 270)

简单介绍一下如何使用这个框架:

  • 点击“浏览”
  • 进入文本栏并选择 XYZ.docx 文件
  • 点击“加密”(应该显示“文件加密成功”
  • 再次点击“浏览”
  • 所选的.docx文件下面会有另一个XYZ.docx.加密文件,请选择它
  • 选择文件后,点击“解密”
  • 所选的.docx文件下面会有另一个XYZ.docx.decrypted文件,请打开它

我希望找到潜在的错误并修复这个问题,以便解密后文本能够正常

python security encryption rsa
1个回答
0
投票

我认为您误解了 RSA 用例,这不是文件加密的典型用途。文件越大,加密后的文件也越大。在这个“学习案例”中,我可以向您展示并纠正您的 RSA 实现的一个简单基础:

  • 您正在尝试获取
    uft-8
    ,但加密应该使用字节。尝试编码
    latin-1
    也是不合理的。
  • 解密过程中无法生成私钥,私钥应该在加密时生成并保存在不同的地方以便在解密时重复使用
  • 加密过程需要按顺序进行:获取文件字节 -> 加密为密码整数 -> 将整数转换为字节 -> 保存加密字节并保存私钥
  • 解密过程需要按顺序:获取加密字节和私钥 -> 转为密码整数 -> 将密码整数解密为字节 -> 连接字节。
import random

PREVIEW_LENGTH = 15
BYTES_PADDING_SIZE = 2

def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

def mod_inverse(a, m):
    if gcd(a, m) != 1:
        return None
    u1, u2, u3 = 1, 0, a
    v1, v2, v3 = 0, 1, m
    while v3 != 0:
        q = u3 // v3
        v1, v2, v3, u1, u2, u3 = u1 - q * v1, u2 - q * v2, u3 - q * v3, v1, v2, v3
    return u1 % m

def generate_keypair(p, q):
    n = p * q
    phi = (p - 1) * (q - 1)
    e = random.randrange(1, phi)
    g = gcd(e, phi)
    while g != 1:
        e = random.randrange(1, phi)
        g = gcd(e, phi)
    d = mod_inverse(e, phi)
    return (e, n), (d, n)

def encrypt(bytes, public_key):
    e, n = public_key
    print('Encrypting with public key', public_key)
    print('Origin bytes', bytes[:PREVIEW_LENGTH])
    # Encrypt each byte to an integer m^e mod n
    cipher_integers = [pow(byte, e, n) for byte in bytes]
    print('Cipher integers', cipher_integers[:PREVIEW_LENGTH])
    # Convert integers to bytes and concatenate them
    cipher_bytes = b''.join(int_to_bytes(char) for char in cipher_integers)
    print('Cipher bytes',cipher_bytes[:PREVIEW_LENGTH])
    return cipher_bytes

def decrypt(cipher_bytes, private_key):
    d, n = private_key
    print('Decrypting with private key', private_key)
    print('Cipher bytes', cipher_bytes[:PREVIEW_LENGTH])
    cipher_integers = [bytes_to_int(cipher_bytes[i:i + BYTES_PADDING_SIZE]) for i in range(0, len(cipher_bytes), BYTES_PADDING_SIZE)]
    print('Cipher integers', cipher_integers[:PREVIEW_LENGTH])
    decrypted_bytes = [pow(cipher_int, d, n) for cipher_int in cipher_integers]
    decrypted_bytes = bytes(decrypted_bytes)
    print('Origin bytes', decrypted_bytes[:PREVIEW_LENGTH])
    return decrypted_bytes

def int_to_bytes(n, padding=BYTES_PADDING_SIZE):
    # Convert an integer to its byte representation
    return n.to_bytes(padding, byteorder='big')

def bytes_to_int(b):
    # Convert bytes to integer
    return int.from_bytes(b, byteorder='big')

def key_to_pem(e, n, d):
    # Construct the PEM strings for public and private keys
    public_key_pem = f"-----BEGIN RSA PUBLIC KEY-----\n{int_to_bytes(e).hex()}\n{int_to_bytes(n).hex()}\n-----END RSA PUBLIC KEY-----\n"
    private_key_pem = f"-----BEGIN RSA PRIVATE KEY-----\n{int_to_bytes(n).hex()}\n{int_to_bytes(d).hex()}\n-----END RSA PRIVATE KEY-----\n"
    return public_key_pem, private_key_pem

def pem_to_key(private_key_pem):
    # Remove PEM header and footer
    private_key_pem = private_key_pem.replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", "").strip()
    # Convert hex strings to integers
    n_hex, d_hex = private_key_pem.split('\n')
    n = bytes_to_int(bytes.fromhex(n_hex))
    d = bytes_to_int(bytes.fromhex(d_hex))
    return d, n

def encrypt_file(filepath):
    p = 61
    q = 53
    public_key, private_key = generate_keypair(p, q)

    with open(filepath, "rb") as f:
        bytes = f.read()
    
    encrypted_data = encrypt(bytes, public_key)
    encrypted_filepath = filepath + ".encrypted"

    with open(encrypted_filepath, "wb") as f:
        f.write(encrypted_data)

    print("File encrypted successfully.")

    _, private_key_pem = key_to_pem(public_key[0], public_key[1], private_key[0])
    return encrypted_filepath, private_key_pem

def decrypt_file(filepath, private_key_pem):
    private_key = pem_to_key(private_key_pem)

    with open(filepath, "rb") as f:
        encrypted_data = f.read()
    
    decrypted_data = decrypt(encrypted_data, private_key)
    
    # Create a decrypted file with a ".decrypted" extension
    decrypted_filepath = filepath.replace('.encrypted', '')  # Remove ".encrypted" from the end of the file name
    decrypted_filepath = 'decrypted_' + decrypted_filepath

    with open(decrypted_filepath, "wb") as f:
        f.write(decrypted_data)
    
    print("File decrypted successfully.")
    return decrypted_filepath


def main():
    sample_path = 'file-sample_1MB.docx'

    # Download sample for testing purpose, comment this if you already have a file
    # import requests
    # url = "https://file-examples.com/storage/fe805ba0cc65378da968c5c/2017/02/file-sample_1MB.docx"
    # response = requests.get(url)

    # if response.status_code != 200:
    #     raise Exception('Error')

    # with open(sample_path, "wb") as f:
    #     f.write(response.content)

    encrypt_path, private_key_pem = encrypt_file(sample_path)
    decrypt_path = decrypt_file(encrypt_path, private_key_pem)

main()

现在你可以看到结果了:

Encrypting with public key (1613, 3233)
Origin bytes b'PK\x03\x04\x14\x00\x08\x08\x08\x00\xa6c\x10K\x00'
Cipher integers [2730, 658, 3077, 2601, 497, 0, 220, 220, 220, 0, 2869, 2590, 1765, 658, 0]
Cipher bytes b'\n\xaa\x02\x92\x0c\x05\n)\x01\xf1\x00\x00\x00\xdc\x00'
File encrypted successfully.
Decrypting with private key (677, 3233)
Cipher bytes b'\n\xaa\x02\x92\x0c\x05\n)\x01\xf1\x00\x00\x00\xdc\x00'
Cipher integers [2730, 658, 3077, 2601, 497, 0, 220, 220, 220, 0, 2869, 2590, 1765, 658, 0]
Origin bytes b'PK\x03\x04\x14\x00\x08\x08\x08\x00\xa6c\x10K\x00'
File decrypted successfully.

但问题是,1MB的文件加密到2.1MB(2倍)并且非常慢,即使RSA密钥是非常简单的数字,所以这就是为什么我们不应该使用RSA。相反,AES 是可行的方法,您也可以将 RSA 与 AES 密钥结合起来以提高安全性,但我不会让事情变得复杂。

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import os

PREVIEW_LENGTH = 15

def encrypt(bytes, aes_key, iv):
    cipher = Cipher(algorithms.AES(aes_key), modes.CFB(iv), backend=default_backend())

    # Encrypt the large file with AES
    encryptor = cipher.encryptor()
    cipher_bytes = encryptor.update(bytes) + encryptor.finalize()

    print('Encrypting with aes_key', aes_key)
    print('Origin bytes', bytes[:PREVIEW_LENGTH])
    print('Cipher bytes', cipher_bytes[:PREVIEW_LENGTH])
    return cipher_bytes

def decrypt(cipher_bytes, aes_key, iv):
    # Create an AES cipher object with the AES key and IV
    cipher = Cipher(algorithms.AES(aes_key), modes.CFB(iv), backend=default_backend())

    # Decrypt the encrypted file with AES
    decryptor = cipher.decryptor()
    decrypted_bytes = decryptor.update(cipher_bytes) + decryptor.finalize()

    print('Decrypting with aes key', aes_key)
    print('Cipher bytes', cipher_bytes[:PREVIEW_LENGTH])
    print('Origin bytes', decrypted_bytes[:PREVIEW_LENGTH])
    return decrypted_bytes

def generate_key():
    # Generate a random 256-bit AES key
    aes_key = os.urandom(32)
    iv = os.urandom(16)
    return aes_key, iv

def encrypt_file(filepath):
    aes_key, iv = generate_key()

    with open(filepath, "rb") as f:
        bytes = f.read()
    
    encrypted_data = encrypt(bytes, aes_key, iv)
    encrypted_filepath = filepath + ".encrypted"

    with open(encrypted_filepath, "wb") as f:
        f.write(encrypted_data)

    print("File encrypted successfully.")
    return encrypted_filepath, aes_key, iv

def decrypt_file(filepath, aes_key, iv):
    with open(filepath, "rb") as f:
        encrypted_data = f.read()
    
    decrypted_data = decrypt(encrypted_data, aes_key, iv)
    
    # Create a decrypted file with a ".decrypted" extension
    decrypted_filepath = filepath.replace('.encrypted', '')  # Remove ".encrypted" from the end of the file name
    decrypted_filepath = 'decrypted_' + decrypted_filepath

    with open(decrypted_filepath, "wb") as f:
        f.write(decrypted_data)
    
    print("File decrypted successfully.")
    return decrypted_filepath


def main():
    sample_path = 'file-sample_1MB.docx'

    # Download sample for testing purpose, comment this if you already have a file
    # import requests
    # url = "https://file-examples.com/storage/fe805ba0cc65378da968c5c/2017/02/file-sample_1MB.docx"
    # response = requests.get(url)

    # if response.status_code != 200:
    #     raise Exception('Error')

    # with open(sample_path, "wb") as f:
    #     f.write(response.content)

    encrypt_path, aes_key, iv = encrypt_file(sample_path)
    decrypt_path = decrypt_file(encrypt_path, aes_key, iv)

main()

结果快速、简单:

Encrypting with aes_key b"\xe1\xea\xbc~tP\xab\x00\\'Uf\xe8\x87|\xdd\xa0\x965\x0e\x88\n\xb3\xb4\xb8\xb4\r\xde\x00c\x0e\xf9"
Origin bytes b'PK\x03\x04\x14\x00\x08\x08\x08\x00\xa6c\x10K\x00'
Cipher bytes b'G\xb9B\xdeK\xedG\x9a\xcd_-\x9ebl\x07'
File encrypted successfully.
Decrypting with aes key b"\xe1\xea\xbc~tP\xab\x00\\'Uf\xe8\x87|\xdd\xa0\x965\x0e\x88\n\xb3\xb4\xb8\xb4\r\xde\x00c\x0e\xf9"
Cipher bytes b'G\xb9B\xdeK\xedG\x9a\xcd_-\x9ebl\x07'
Origin bytes b'PK\x03\x04\x14\x00\x08\x08\x08\x00\xa6c\x10K\x00'
File decrypted successfully.
© www.soinside.com 2019 - 2024. All rights reserved.