如何用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实现比较两段文本不同之处的方法
May 30 Python
Python实现朴素贝叶斯分类器的方法详解
Jul 04 Python
python opencv人脸检测提取及保存方法
Aug 03 Python
对python同一个文件夹里面不同.py文件的交叉引用方法详解
Dec 15 Python
Python同步遍历多个列表的示例
Feb 19 Python
Python基础之循环语句用法示例【for、while循环】
Mar 23 Python
python脚本开机自启的实现方法
Jun 28 Python
QML使用Python的函数过程解析
Sep 26 Python
python3中numpy函数tile的用法详解
Dec 04 Python
python函数不定长参数使用方法解析
Dec 14 Python
python实现画图工具
Aug 27 Python
Python词云的正确实现方法实例
May 08 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/05/21 PHP
PHP Error与Logging函数的深入理解
2013/06/03 PHP
php使用fsockopen函数发送post,get请求获取网页内容的方法
2014/11/15 PHP
PHP获取用户访问IP地址的5种方法
2016/05/16 PHP
PHP面向对象程序设计类的定义与用法简单示例
2016/12/27 PHP
php支付宝系列之电脑网站支付
2018/05/30 PHP
PHP中strtr与str_replace函数运行性能简单测试示例
2019/06/22 PHP
js检查页面上有无重复id的实现代码
2013/07/17 Javascript
jquery操作angularjs对象
2015/06/26 Javascript
深入学习JavaScript中的原型prototype
2015/08/13 Javascript
ExtJS 4.2 Grid组件单元格合并的方法
2016/10/12 Javascript
Vue.js开发环境搭建
2016/11/10 Javascript
JSON键值对序列化和反序列化解析
2017/01/24 Javascript
单击按钮发送验证码,出现倒计时的简单实例
2017/03/17 Javascript
使用vue框架 Ajax获取数据列表并用BootStrap显示出来
2017/04/24 Javascript
JS操作时间 - UNIX时间戳的简单介绍(必看篇)
2017/08/16 Javascript
vue.js 嵌套循环、if判断、动态删除的实例
2018/03/07 Javascript
浅谈super-vuex使用体验
2018/06/25 Javascript
微信小程序设置滚动条过程详解
2019/07/25 Javascript
微信小程序动态评分展示/五角星展示/半颗星展示/自定义长度展示功能的实现
2020/07/22 Javascript
python使用rabbitmq实现网络爬虫示例
2014/02/20 Python
介绍Python的@property装饰器的用法
2015/04/28 Python
Python使用剪切板的方法
2017/06/06 Python
Python实现对象转换为xml的方法示例
2017/06/08 Python
python+tkinter编写电脑桌面放大镜程序实例代码
2018/01/16 Python
python 多维切片之冒号和三个点的用法介绍
2018/04/19 Python
windows下添加Python环境变量的方法汇总
2018/05/14 Python
python遍历文件目录、批量处理同类文件
2019/08/31 Python
django 实现后台从富文本提取纯文本
2020/07/02 Python
3D动画《斗罗大陆》上线当日播放过亿
2021/03/16 国漫
Android面试题附答案
2014/12/08 面试题
村干部承诺书
2014/03/28 职场文书
少先队活动总结
2014/08/29 职场文书
办护照工作证明
2014/10/01 职场文书
小程序与后端Java接口交互实现HelloWorld入门
2021/07/09 Java/Android
Win10服务全部禁用了怎么启动?Win10服务全部禁用解决方法
2022/09/23 数码科技