如何用Python 加密文件


Posted in Python onSeptember 10, 2020

生活中,有时候我们需要对一些重要的文件进行加密,Python 提供了诸如 hashlib,base64 等便于使用的加密库。

但对于日常学习而言,我们可以借助异或操作,实现一个简单的文件加密程序,从而强化自身的编程能力。

基础知识

在 Python 中异或操作符为:^,也可以记作 XOR。按位异或的意思是:相同值异或为 0,不同值异或为 1。具体来讲,有四种可能:0 ^ 0 = 0,0 ^ 1 = 1, 1 ^ 0 = 1, 1 ^ 1 = 0。我们还可总结出规律(A 为 0 或 1):0 和 A 异或为 A本身;1 和 A 异或为 A 反。

让我们想看看一位二进制数满足的性质:

  • 一位二进制数与自身的异或值为 0

b ^ b = 0

  • 异或操作满足交换律

a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c

  • 0 与 a 的异或为 a

(a ^ b) ^ b = a ^ (b ^ b) = a ^ 0 = a

易知,对任意长二进制数都满足上述性质。

原理

通过了解异或操作的性质,加密原理就非常清晰了。

加密操作:

首先将文件转换成二进制数,再生成与该二进制数等长的随机密钥,将二进制数与密钥进行异或操作,得到加密后的二进制数。

解密操作:

将加密后的二进制程序与密钥进行异或操作,就得到原二进制数,最后将原二进制数恢复成文本文件。

生成随机密钥:

secrets 库是 Python 3.6 引入的伪随机数模块,适合生成随机密钥。token_bytes 函数接受一个 int 参数,用于指定随机字节串的长度。int.from_bytes 把字节串转换为 int,也就是我们需要的二进制数。

from secrets import token_bytes

def random_key(length):
  key = token_bytes(nbytes=length)
  key_int = int.from_bytes(key, 'big')
  return key_int

加密单元:

encrypt 函数接受一个 str 对象,返回元组 (int, int)。通过 encode 方法,我们将字符串编码成字节串。int.from_bytes 函数将字节串转换为 int 对象。最后对二进制对象和随机密钥进行异或操作,就得到了加密文本。

def encrypt(raw):
  raw_bytes = raw.encode()
  raw_int = int.from_bytes(raw_bytes, 'big')
  key_int = random_key(len(raw_bytes))
  return raw_int ^ key_int, key_int

解密单元:

decrypt 接受两个 int 对象,分别为加密文本和随机密钥。首先对两者进行异或操作,计算解密出来的 int 对象所占比特数。decrypted.bit_length 函数得到的是二进制数的位数,除以 8 可以得到所占比特大小。为了防止,1 ~ 7 位的二进制数整除 8 得到 0,所以要加上 7,然后再进行整除 8 的操作。使用 int.to_bytes 函数将解密之后的 int 的对象转换成 bytes 对象。最后通过 decode 方法,将字节串转换成字符串。

def decrypt(encrypted, key_int):
  decrypted = encrypted ^ key_int
  length = (decrypted.bit_length() + 7) // 8
  decrypted_bytes = int.to_bytes(decrypted, length, 'big') 
  return decrypted_bytes.decode()

利用上述函数,我们可以很轻松对文本文件进行加密、解密操作。

>>> raw = '画图省识春风面,环?空归夜月魂'
>>> encrypted = encrypt(raw)
>>> encrypted
(217447100157746604585...,
 9697901906831571319...)
>>> decrypt(*encrypted)
'画图省识春风面,环?空归夜月魂'

加密文本文件

path 为待加密文件的地址,如果不指定密钥地址,则在该目录下新建目录和文件。

import json
from pathlib import Path

def encrypt_file(path, key_path=None, *, encoding='utf-8'):
  path = Path(path)
  cwd = path.cwd() / path.name.split('.')[0]
  path_encrypted = cwd / path.name 
  if key_path is None:
    key_path = cwd / 'key'
  if not cwd.exists():
    cwd.mkdir()
    path_encrypted.touch()
    key_path.touch()

  with path.open('rt', encoding=encoding) as f1, \
    path_encrypted.open('wt', encoding=encoding) as f2, \
      key_path.open('wt', encoding=encoding) as f3:
    encrypted, key = encrypt(f1.read())
    json.dump(encrypted, f2)
    json.dump(key, f3)

解密文件

def decrypt_file(path_encrypted, key_path=None, *, encoding='utf-8'):
  path_encrypted = Path(path_encrypted)
  cwd = path_encrypted.cwd()
  path_decrypted = cwd / 'decrypted' 
  if not path_decrypted.exists():
    path_decrypted.mkdir()
    path_decrypted /= path_encrypted.name
    path_decrypted.touch()
  if key_path is None:
    key_path = cwd / 'key'
  with path_encrypted.open('rt', encoding=encoding) as f1, \
    key_path.open('rt', encoding=encoding) as f2, \
    path_decrypted.open('wt', encoding=encoding) as f3:
    decrypted = decrypt(json.load(f1), json.load(f2))
    f3.write(decrypted)

执行完加密、解密文件操作,得到的解密文件与原文件相同,示意图如下:

如何用Python 加密文件

以上就是如何用Python 加密文件的详细内容,更多关于Python 加密文件的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python获取外网ip地址的方法总结
Jul 02 Python
python timestamp和datetime之间转换详解
Dec 11 Python
Python中join函数简单代码示例
Jan 09 Python
理论讲解python多进程并发编程
Feb 09 Python
Python根据已知邻接矩阵绘制无向图操作示例
Jun 23 Python
Tensorflow使用支持向量机拟合线性回归
Sep 07 Python
Python代码太长换行的实现
Jul 05 Python
python求一个字符串的所有排列的实现方法
Feb 04 Python
Python函数生成器原理及使用详解
Mar 12 Python
keras实现VGG16方式(预测一张图片)
Jul 07 Python
python正则表达式的懒惰匹配和贪婪匹配说明
Jul 13 Python
浅析Python中的随机采样和概率分布
Dec 06 Python
Python 高效编程技巧分享
Sep 10 #Python
python操作redis数据库的三种方法
Sep 10 #Python
Python计算矩阵的和积的实例详解
Sep 10 #Python
python如何运行js语句
Sep 09 #Python
python如何爬取动态网站
Sep 09 #Python
python如何停止递归
Sep 09 #Python
python能做哪些生活有趣的事情
Sep 09 #Python
You might like
PHP 判断变量类型实现代码
2009/10/23 PHP
php生成随机密码自定义函数代码(简单快速)
2014/05/10 PHP
php微信开发之批量生成带参数的二维码
2016/06/26 PHP
Laravel4中的Validator验证扩展用法详解
2016/07/26 PHP
php基于websocket搭建简易聊天室实践
2016/10/24 PHP
PHP 二级子目录(后台目录)设置二级域名
2017/03/02 PHP
基于PHP的加载类操作以及其他两种魔术方法的应用实例
2017/08/28 PHP
PHP5.6.8连接SQL Server 2008 R2数据库常用技巧分析总结
2019/05/06 PHP
JavaScript 自动完成脚本整理(33个)
2009/10/20 Javascript
jQuery创建平滑的页面滚动(顶部或底部)
2013/02/26 Javascript
jQuery简单实现banner图片切换
2014/01/02 Javascript
js与C#进行时间戳转换
2014/11/14 Javascript
jQuery on方法传递参数示例
2014/12/09 Javascript
JS简单限制textarea内输入字符数量的方法
2015/10/14 Javascript
javascript自定义滚动条实现代码
2020/04/20 Javascript
浅析JavaScript的几种Math函数,random(),ceil(),round(),floor()
2016/12/22 Javascript
超全面的javascript中变量命名规则
2017/02/09 Javascript
JavaScript简单实现合并两个Json对象的方法示例
2017/10/16 Javascript
Python中使用md5sum检查目录中相同文件代码分享
2015/02/02 Python
Python简单进程锁代码实例
2015/04/27 Python
利用Python爬取微博数据生成词云图片实例代码
2017/08/31 Python
Python实现端口检测的方法
2018/07/24 Python
python使用adbapi实现MySQL数据库的异步存储
2019/03/19 Python
Python在OpenCV里实现极坐标变换功能
2019/09/02 Python
python函数定义和调用过程详解
2020/02/09 Python
python报错TypeError: ‘NoneType‘ object is not subscriptable的解决方法
2020/11/05 Python
Html5定位终极解决方案
2020/02/05 HTML / CSS
英国领先的男士服装和时尚零售商:Burton
2017/01/09 全球购物
构造器Constructor是否可被override?
2013/08/06 面试题
商超业务员岗位职责
2014/03/12 职场文书
细节决定成败演讲稿
2014/05/12 职场文书
ktv周年庆活动方案
2014/08/18 职场文书
四风问题对照检查整改措施思想报告
2014/10/05 职场文书
导游词之镇江-金山寺
2019/10/14 职场文书
导游词之白茶谷九龙峡
2019/10/23 职场文书
整理Python中常用的conda命令操作
2021/06/15 Python