如何用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中操作列表之List.append()方法的使用
May 20 Python
Python抽象类的新写法
Jun 18 Python
Python+matplotlib+numpy实现在不同平面的二维条形图
Jan 02 Python
Python爬虫实现获取动态gif格式搞笑图片的方法示例
Dec 24 Python
Python实现多态、协议和鸭子类型的代码详解
May 05 Python
使用PyQt4 设置TextEdit背景的方法
Jun 14 Python
Python控制台输出时刷新当前行内容而不是输出新行的实现
Feb 21 Python
python GUI库图形界面开发之PyQt5下拉列表框控件QComboBox详细使用方法与实例
Feb 27 Python
python框架flask入门之路由及简单实现方法
Jun 07 Python
Python与C/C++的相互调用案例
Mar 04 Python
浅谈Python numpy创建空数组的问题
May 25 Python
python使用pycharm安装pyqt5以及相关配置
Apr 22 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代码
2006/12/06 PHP
PHP学习笔记之字符串编码的转换和判断
2014/05/22 PHP
利用switch语句进行多选一判断的实例代码
2016/11/14 PHP
php实现微信分享朋友链接功能
2019/02/18 PHP
Laravel中10个有用的用法小结
2019/05/06 PHP
php面向对象重点知识分享
2019/09/27 PHP
基于PHP实现解密或加密Cloudflar邮箱保护
2020/06/24 PHP
PHP7移除的扩展和SAPI
2021/03/09 PHP
extJs 下拉框联动实现代码
2010/04/09 Javascript
JQuery 动态扩展对象之另类视角
2010/05/25 Javascript
IE6下CSS图片缓存问题解决方法
2010/12/09 Javascript
JQuery模板插件 jquery.tmpl 动态ajax扩展
2011/11/10 Javascript
jquery与prototype框架的详细对比
2013/11/21 Javascript
node.js中的path.basename方法使用说明
2014/12/09 Javascript
JavaScript基于setTimeout实现计数的方法
2015/05/08 Javascript
jQuery实现可展开合拢的手风琴面板菜单
2015/09/15 Javascript
JavaScript遍历求解数独问题的主要思路小结
2016/06/12 Javascript
浅谈jquery设置和获得checkbox选中的问题
2016/08/19 Javascript
React路由管理之React Router总结
2018/05/10 Javascript
Canvas实现微信红包照片效果
2018/08/21 Javascript
vue项目在安卓低版本机显示空白的原因分析(两种)
2018/09/04 Javascript
nodejs更新package.json中的dependencies依赖到最新版本的方法
2018/10/10 NodeJs
Python批量修改文本文件内容的方法
2016/04/29 Python
Python2.7基于淘宝接口获取IP地址所在地理位置的方法【测试可用】
2017/06/07 Python
python_matplotlib改变横坐标和纵坐标上的刻度(ticks)方式
2020/05/16 Python
mac系统下安装pycharm、永久激活、中文汉化详细教程
2020/11/24 Python
OpenCV+python实现膨胀和腐蚀的示例
2020/12/21 Python
Charlotte Tilbury英国官网:英国彩妆品牌
2017/05/26 全球购物
艺术家策划的室内设计:Curious Egg
2019/03/06 全球购物
信用社实习人员自我鉴定
2013/09/20 职场文书
怎么写好自荐信
2013/10/30 职场文书
幼儿生日活动方案
2014/08/27 职场文书
2015年度招聘工作总结
2015/05/28 职场文书
mysql 索引合并的使用
2021/08/30 MySQL
python代码实现扫码关注公众号登录的实战
2021/11/01 Python
Vue elementUI表单嵌套表格并对每行进行校验详解
2022/02/18 Vue.js