一个基于Python的文件加密解密工具,使用AES-256-CFB加密算法,兼容原有的C#版本加密格式。
回顾
我们先来回顾一下C#版本的代码
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
namespace Abantes.Utils
{
// Token: 0x02000008 RID: 8
internal class Encryption
{
// Token: 0x0600002B RID: 43 RVA: 0x000045C0 File Offset: 0x000027C0
public static byte[] GenerateRandomSalt()
{
byte[] array = new byte[32];
using (RNGCryptoServiceProvider rngcryptoServiceProvider = new RNGCryptoServiceProvider())
{
for (int i = 0; i 0)
{
Application.DoEvents();
cryptoStream.Write(array2, 0, count);
}
fileStream2.Close();
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
finally
{
cryptoStream.Close();
fileStream.Close();
}
}
// Token: 0x0600002D RID: 45 RVA: 0x00004740 File Offset: 0x00002940
public static void FileDecrypt(string inputFile, string outputFile, string password)
{
byte[] bytes = Encoding.UTF8.GetBytes(password);
byte[] array = new byte[32];
FileStream fileStream = new FileStream(inputFile, FileMode.Open);
fileStream.Read(array, 0, array.Length);
RijndaelManaged rijndaelManaged = new RijndaelManaged();
rijndaelManaged.KeySize = 256;
rijndaelManaged.BlockSize = 128;
Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(bytes, array, 50000);
rijndaelManaged.Key = rfc2898DeriveBytes.GetBytes(rijndaelManaged.KeySize / 8);
rijndaelManaged.IV = rfc2898DeriveBytes.GetBytes(rijndaelManaged.BlockSize / 8);
rijndaelManaged.Padding = PaddingMode.PKCS7;
rijndaelManaged.Mode = CipherMode.CFB;
CryptoStream cryptoStream = new CryptoStream(fileStream, rijndaelManaged.CreateDecryptor(), CryptoStreamMode.Read);
FileStream fileStream2 = new FileStream(outputFile, FileMode.Create);
byte[] array2 = new byte[1048576];
try
{
int count;
while ((count = cryptoStream.Read(array2, 0, array2.Length)) > 0)
{
Application.DoEvents();
fileStream2.Write(array2, 0, count);
}
}
catch (CryptographicException ex)
{
Console.WriteLine("CryptographicException error: " + ex.Message);
}
catch (Exception ex2)
{
Console.WriteLine("Error: " + ex2.Message);
}
try
{
cryptoStream.Close();
}
catch (Exception ex3)
{
Console.WriteLine("Error by closing CryptoStream: " + ex3.Message);
}
finally
{
fileStream2.Close();
fileStream.Close();
}
}
}
}
文件加密解密流程详解
加密流程 (FileEncrypt 方法)
1. 生成随机盐
2. 打开输出文件流
3. 生成密钥和 IV
4. 配置加密算法
5. 写入盐
6. 创建加密流
7. 读取和加密文件
8. 关闭流
解密流程 (FileDecrypt 方法)
1. 读取盐
2. 生成密钥和 IV
3. 配置解密算法
4. 创建解密流
5. 写入解密后的文件
6. 关闭流
关键技术点说明
密钥和 IV 的派生
加密算法设置
流式处理设计
异常处理机制
安全性保障
这些步骤构成了一个安全可靠的文件加密和解密流程,适用于需要保护敏感数据的应用场景,同时提供了良好的性能和用户体验。
功能特性
安装依赖
pip install pycryptodome
使用方法
加密文件
# 使用默认密钥加密
python Abantes.py -encrypt 文件名
# 使用自定义密钥加密
python Abantes.py -encrypt 文件名 自定义密钥
解密文件
# 使用默认密钥解密
python Abantes.py -decrypt 文件名.Abantes
# 使用自定义密钥解密
python Abantes.py -decrypt 文件名.Abantes 自定义密钥
参数说明
文件格式
技术细节
示例
# 加密一个MP3文件
python Abantes.py -encrypt music.mp3
# 解密加密后的文件
python Abantes.py -decrypt music.mp3.Abantes
# 使用自定义密钥加密重要文档
python Abantes.py -encrypt document.pdf MyStrongPassword123
注意事项
[ol]
[/ol]
故障排除
如果遇到解密问题:
[ol]
[/ol]
如需技术支持,请提供详细的错误信息和操作步骤。
Python代码
import os
import sys
import argparse
from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Random import get_random_bytes
class Encryption:
@staticmethod
def generate_random_salt():
"""生成32字节的随机盐值"""
return get_random_bytes(32)
@staticmethod
def file_encrypt(input_file, password):
"""加密文件"""
try:
# 生成盐值
salt = Encryption.generate_random_salt()
# 创建输出文件
output_file = input_file + ".Abantes"
# 准备AES加密参数
key_size = 256
block_size = 128
# 使用PBKDF2生成密钥和IV
key_iv = PBKDF2(password.encode('utf-8'), salt, dkLen=(key_size + block_size) // 8, count=50000)
key = key_iv[:key_size // 8]
iv = key_iv[key_size // 8:key_size // 8 + block_size // 8]
# 创建AES加密器
cipher = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128)
with open(input_file, 'rb') as file_in:
with open(output_file, 'wb') as file_out:
# 写入盐值
file_out.write(salt)
# 加密并写入数据
while True:
chunk = file_in.read(1048576) # 1MB chunks
if not chunk:
break
encrypted_chunk = cipher.encrypt(chunk)
file_out.write(encrypted_chunk)
print(f"文件加密成功: {output_file}")
return True
except Exception as e:
print(f"加密错误: {e}")
return False
@staticmethod
def file_decrypt(input_file, output_file, password):
"""解密文件"""
try:
with open(input_file, 'rb') as file_in:
# 读取盐值
salt = file_in.read(32)
# 准备AES解密参数
key_size = 256
block_size = 128
# 使用PBKDF2生成密钥和IV
key_iv = PBKDF2(password.encode('utf-8'), salt, dkLen=(key_size + block_size) // 8, count=50000)
key = key_iv[:key_size // 8]
iv = key_iv[key_size // 8:key_size // 8 + block_size // 8]
# 创建AES解密器
cipher = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128)
with open(output_file, 'wb') as file_out:
# 解密并写入数据
while True:
chunk = file_in.read(1048576) # 1MB chunks
if not chunk:
break
decrypted_chunk = cipher.decrypt(chunk)
file_out.write(decrypted_chunk)
print(f"文件解密成功: {output_file}")
#Debug: 验证解密后的文件
#if output_file.lower().endswith('.mp3'):
# with open(output_file, 'rb') as f:
# header = f.read(3)
# if header == b'ID3':
# print("MP3文件头验证成功")
# else:
# print(f"警告: MP3文件头异常,前3字节: {header.hex()}")
#
#return True
except Exception as e:
print(f"解密错误: {e}")
return False
def main():
parser = argparse.ArgumentParser(description='文件加密解密工具')
parser.add_argument('-encrypt', metavar='文件路径', help='加密文件')
parser.add_argument('-decrypt', metavar='文件路径', help='解密文件')
parser.add_argument('key', nargs='?', default='WR8h2GIbf9FGz6VVlSzJ', help='加密密钥(可选,默认为WR8h2GIbf9FGz6VVlSzJ)')
args = parser.parse_args()
# 安装依赖检查
try:
from Crypto.Cipher import AES
except ImportError:
print("请安装pycryptodome库: pip install pycryptodome")
return
if args.encrypt:
if not os.path.exists(args.encrypt):
print(f"文件不存在: {args.encrypt}")
return
Encryption.file_encrypt(args.encrypt, args.key)
elif args.decrypt:
if not os.path.exists(args.decrypt):
print(f"文件不存在: {args.decrypt}")
return
# 生成解密后的文件名
if args.decrypt.endswith('.Abantes'):
output_file = args.decrypt[:-8] # 移除.Abantes后缀
else:
output_file = args.decrypt + '.decrypted'
# 检查输出文件是否已存在
if os.path.exists(output_file):
response = input(f"文件 {output_file} 已存在,是否覆盖?(y/n): ")
if response.lower() != 'y':
print("操作取消")
return
Encryption.file_decrypt(args.decrypt, output_file, args.key)
else:
print("请指定 -encrypt 或 -decrypt 参数")
parser.print_help()
if __name__ == "__main__":
main()