基于python实现文件加密功能

1. 前言

在当今时代,我们所用的计算机技术越来越先进。然而,随着技术的改进,也存在着黑客入侵和信息泄露的风险。因此,保护我们的文件安全是非常重要的。文件加密是一种有效的保护文件安全的方法,它可以保护我们的个人和商业文件,以避免它们被未经授权的人访问。

在这篇文章中,我们将使用Python实现文件加密功能。我们将介绍如何将普通文件转换为加密文件,并如何从加密文件中恢复原始数据。

2. 文件加密的实现思路

文件加密是通过加密算法将文件中的代码转换成另一种形式,从而使其难以被未经授权的用户阅读。在加密文件之前,我们需要先确定一个加密算法。通常使用的加密算法有对称密钥加密和公共密钥加密。在这篇文章中,我们将使用对称密钥加密算法。

对称密钥加密算法中,使用同一个密钥来加密和解密数据。因此,在加密之前需要确定秘钥并将其保存。我们将使用PyCryptodomex来实现加密和解密功能。PyCryptodomex是一个Python库,可实现常见的加密和解密算法。

3. 安装依赖项

在开始编写代码之前,我们需要安装必要的Python库。

pip install pycryptodomex

4. 文件加密

首先,我们需要定义一个函数来生成密钥和初始化向量(IV)。密钥和IV是加密算法的参数,用于在加密和解密过程中生成随机数。以下是生成密钥和IV的函数:

import os

import hashlib

from Cryptodome.Cipher import AES

def generate_key_and_iv(password, salt, key_length, iv_length):

"""

生成密钥和IV

"""

assert key_length + iv_length == 32

if isinstance(password, str):

password = password.encode()

if isinstance(salt, str):

salt = salt.encode()

password_hash = hashlib.pbkdf2_hmac('sha1', password, salt, 1000, key_length + iv_length)

return password_hash[:key_length], password_hash[key_length:]

随后,我们需要定义一个函数来加密文件。以下是加密文件的函数:

def encrypt_file(key, iv, in_filename, out_filename=None, chunksize=64*1024):

"""

加密文件

"""

if not out_filename:

out_filename = in_filename + '.enc'

iv = os.urandom(16)

encryptor = AES.new(key, AES.MODE_CBC, IV=iv)

filesize = os.path.getsize(in_filename)

with open(in_filename, 'rb') as infile:

with open(out_filename, 'wb') as outfile:

outfile.write(filesize.to_bytes(8, 'big'))

outfile.write(iv)

while True:

chunk = infile.read(chunksize)

if len(chunk) == 0:

break

elif len(chunk) % 16 != 0:

chunk += b' ' * (16 - len(chunk) % 16)

outfile.write(encryptor.encrypt(chunk))

我们可以定义一个函数,使其调用这两个函数来加密文件。

def encrypt(password, in_filename, out_filename=None):

"""

对文件进行加密

"""

if not out_filename:

out_filename = in_filename + '.enc'

salt = os.urandom(8)

key, iv = generate_key_and_iv(password, salt, 16, 16)

encrypt_file(key, iv, in_filename, out_filename)

return out_filename

现在,我们可以定义一个函数来加密文件。以下是函数操作流程:

读取所需加密的文件。

生成随机盐。

生成加密密钥,并与IV一起返回。

使用生成的密钥和IV加密文件的内容。

在加密文件之前,将文件大小和IV写入文件头。文件大小用于在解密期间还原文件。

下面是完整的文件加密函数:

def encrypt_file(key, iv, in_filename, out_filename=None, chunksize=64*1024):

"""

加密文件

"""

if not out_filename:

out_filename = in_filename + '.enc'

iv = os.urandom(16)

encryptor = AES.new(key, AES.MODE_CBC, IV=iv)

filesize = os.path.getsize(in_filename)

with open(in_filename, 'rb') as infile:

with open(out_filename, 'wb') as outfile:

outfile.write(filesize.to_bytes(8, 'big'))

outfile.write(iv)

while True:

chunk = infile.read(chunksize)

if len(chunk) == 0:

break

elif len(chunk) % 16 != 0:

chunk += b' ' * (16 - len(chunk) % 16)

outfile.write(encryptor.encrypt(chunk))

def generate_key_and_iv(password, salt, key_length, iv_length):

"""

生成密钥和IV

"""

assert key_length + iv_length == 32

if isinstance(password, str):

password = password.encode()

if isinstance(salt, str):

salt = salt.encode()

password_hash = hashlib.pbkdf2_hmac('sha1', password, salt, 1000, key_length + iv_length)

return password_hash[:key_length], password_hash[key_length:]

def encrypt(password, in_filename, out_filename=None):

"""

对文件进行加密

"""

if not out_filename:

out_filename = in_filename + '.enc'

salt = os.urandom(8)

key, iv = generate_key_and_iv(password, salt, 16, 16)

encrypt_file(key, iv, in_filename, out_filename)

return out_filename

5. 文件解密

现在,我们需要定义一个函数来解密文件。以下是解密文件的函数:

def decrypt_file(key, iv, in_filename, out_filename=None, chunksize=24*1024):

"""

解密文件

"""

if not out_filename:

out_filename = os.path.splitext(in_filename)[0]

decryptor = AES.new(key, AES.MODE_CBC, IV=iv)

filesize = int.from_bytes(in_file.read(8), 'big')

with open(in_filename, 'rb') as infile:

with open(out_filename, 'wb') as outfile:

while True:

chunk = infile.read(chunksize)

if len(chunk) == 0:

break

outfile.write(decryptor.decrypt(chunk))

outfile.truncate(filesize)

def decrypt(password, in_filename, out_filename=None):

"""

对文件进行解密

"""

if not out_filename:

out_filename = os.path.splitext(in_filename)[0]

with open(in_filename, 'rb') as infile:

salt = infile.read(8)

key, iv = generate_key_and_iv(password, salt, 16, 16)

decrypt_file(key, iv, in_filename, out_filename)

return out_filename

下面是完整的文件解密函数:

打开加密文件。

从文件头读取IV并生成密钥。

使用密钥和IV来解密文件的内容。

从解密后的文件中截取原始文件。

def decrypt_file(key, iv, in_filename, out_filename=None, chunksize=24*1024):

"""

解密文件

"""

if not out_filename:

out_filename = os.path.splitext(in_filename)[0]

decryptor = AES.new(key, AES.MODE_CBC, IV=iv)

filesize = int.from_bytes(in_file.read(8), 'big')

with open(in_filename, 'rb') as infile:

with open(out_filename, 'wb') as outfile:

while True:

chunk = infile.read(chunksize)

if len(chunk) == 0:

break

outfile.write(decryptor.decrypt(chunk))

outfile.truncate(filesize)

def generate_key_and_iv(password, salt, key_length, iv_length):

"""

生成密钥和IV

"""

assert key_length + iv_length == 32

if isinstance(password, str):

password = password.encode()

if isinstance(salt, str):

salt = salt.encode()

password_hash = hashlib.pbkdf2_hmac('sha1', password, salt, 1000, key_length + iv_length)

return password_hash[:key_length], password_hash[key_length:]

def decrypt(password, in_filename, out_filename=None):

"""

对文件进行解密

"""

if not out_filename:

out_filename = os.path.splitext(in_filename)[0]

with open(in_filename, 'rb') as infile:

salt = infile.read(8)

key, iv = generate_key_and_iv(password, salt, 16, 16)

decrypt_file(key, iv, in_filename, out_filename)

return out_filename

6. 测试代码

下面是一个简单的测试程序,它将文本文件encryption.txt加密为encryption.txt.enc,然后将加密后的文件解密为解密文本文件。

def test():

"""

测试加密和解密

"""

password = "mypassword"

in_filename = "encryption.txt"

out_filename = "encryption.txt.enc"

out_filename2 = "decryption.txt"

# 加密文件

encrypt(password, in_filename, out_filename)

print(f'加密文件{in_filename}完成,加密文件已保存至{out_filename}')

# 解密文件

decrypt(password, out_filename, out_filename2)

print(f'解密文件{out_filename}完成,解密文件已保存至{out_filename2}')

7. 总结

在本文中,我们学习了如何使用Python实现文件加密功能。我们已经了解了加密算法,以及如何使用PyCryptodomex库实现对文件进行加密和解密。我们也学习了如何生成密钥和IV,以及将IV写入加密文件头。希望这个教程有助于您保护您的个人和商业文件。

后端开发标签