之前的文章http://blog.csdn.net/u013578500/article/details/77905924
简单介绍了一下使用PyCrypto模块实现对字符串的加密解密,里面有提到我利用这个模块写了一个对文本文件进行加密解密的小脚本,这里和大家分享一下。
1.脚本运行流程
脚本非首次运行时,当前目录下存在且仅密文Pwencrypt,脚本首先会读取密文文件,执行解密并将结果写入PW.txt,随后调用系统接口打开PW.txt。此时脚本将被挂起,当PW.txt被关闭后,脚本继续运行,读取PW.txt并加密,写入Pwencrypt,最后删除PW.txt。如果是第一次运行脚本,则脚本目录下应不存在密文文件Pwencrypt,且存在PW.txt,此时脚本直接读取PW.txt并执行加密流程。
脚本运行流程如下图。
2.输入密码
打开脚本首先需要输入密码,可以使用Python自带的getpass模块,代码如下:import getpass
…
# 输入密码
key = getpass.getpass("Password Please:")
3.计算MD5值
PyCrypto同样可以进行MD5值的计算,这里我通过对明文的MD5码进行校验,来确认输入的密码是否正确。MD5计算模块的用法如下:from Crypto.Hash import MD5
MD5hash = MD5.new()
MD5hash.update('Hello')
print MD5hash.hexdigest()
关于PyCrypto的用法,可以参考下面这个链接:
https://pythonhosted.org/pycrypto/Crypto-module.html
4.编写基本的加密解密函数
直接使用之前文章中的代码即可,这里使用CBC加密模式。from Crypto.Cipher import AES
from binascii import a2b_hex,b2a_hex
# 补全字符
def align(str, isKey=False):
# 如果接受的字符串是密码,需要确保其长度为16
if isKey:
if len(str) > 16:
return str[0:16]
else:
return align(str)
# 如果接受的字符串是明文或长度不足的密码,则确保其长度为16的整数倍
else:
zerocount = 16-len(str) % 16
for i in range(0, zerocount):
str = str + '\0'
return str
# CBC模式加密
def encrypt_CBC(str, key):
# 补全字符串
str = align(str)
key = align(key, True)
# 初始化AES,引入初始向量
AESCipher = AES.new(key, AES.MODE_CBC, '1234567890123456')
# 加密
cipher = AESCipher.encrypt(str)
return b2a_hex(cipher)
# CBC模式解密
def decrypt_CBC(str, key):
# 补全字符串
key = align(key, True)
# 初始化AES
AESCipher = AES.new(key, AES.MODE_CBC, '1234567890123456')
# 解密
paint = AESCipher.decrypt(a2b_hex(str))
return paint
5.解密流程
读取密文文件并用密码解密,首先以只读方式打开Pwencrypt,如果文件不存在,则触发异常直接进入加密流程。Pwencrypt文件分两部分,前半部分为文件密文,后半部分为明文的哈希值,用符号‘,’分隔。
解密完成并校验后,会将密码写入明文文件PW.txt中,之后调用系统接口使用notepad打开该文件。
import os
os.system("notepad PW.txt")
打开文件后脚本进程将被暂时挂起,直到PW.txt文件被关闭。
解密流程具体代码如下:
# 尝试读取密文文件,如果密文文件不存在,则不进行解密直接进入加密流程
try:
fcipher = open("PWencrypt", "r")
fpaint = open("PW.txt", "w+")
# 读取密文文件
fcipherText = fcipher.read()
# 读取密文和校验哈希值
cipherText = fcipherText.split(',')[0]
painhash = fcipherText.split(',')[1]
# 用密码解密
painText = decrypt_CBC(cipherText, key)
# 去除/0
painText = painText.rstrip('\0')
# 校验密码
# 计算本次解密后明文的哈希值
MD5hash = MD5.new()
MD5hash.update(painText)
# 比对哈希值判断密码是否正确
if painhash != MD5hash.hexdigest():
print ('wrong password!!')
else:
fpaint.write(painText)
fpaint.close()
fcipher.close()
print ("Don't Close!!!")
os.system("notepad PW.txt")
except:
print("error!")
6.加密流程
首先以只读方式打开PW.txt,当解密失败或其他异常发生导致文件内容为空,则跳过加密流程直接结束。# 加密,加密明文文件,写入密文文件并删除明文文件
try:
fpaint = open("PW.txt", "r")
# 读取明文文件
painText = fpaint.read()
# 如果明文为空,则不执行加密
if len(painText) > 0:
fcipher = open("PWencrypt", "w")
# 加密
cipherText = encrypt_CBC(painText, key)
# 计算明文哈希值
MD5hash = MD5.new()
MD5hash.update(painText)
# 将密文和校验码写入密文文件
cipherText = cipherText + ',' + MD5hash.hexdigest()
fcipher.write(cipherText)
fcipher.close()
fpaint.close()
# 删除明文文件
os.remove("PW.txt")
except:
print("Something wrong when Encrypt!!")
7.完整代码
# -*- coding: UTF-8 -*-
from Crypto.Cipher import AES
from Crypto.Hash import MD5
from binascii import a2b_hex,b2a_hex
import getpass
import os
import time
# 补全字符
def align(str, isKey=False):
# 如果接受的字符串是密码,需要确保其长度为16
if isKey:
if len(str) > 16:
return str[0:16]
else:
return align(str)
# 如果接受的字符串是明文或长度不足的密码,则确保其长度为16的整数倍
else:
zerocount = 16-len(str) % 16
for i in range(0, zerocount):
str = str + '\0'
return str
# CBC模式加密
def encrypt_CBC(str, key):
# 补全字符串
str = align(str)
key = align(key, True)
# 初始化AES,引入初始向量
AESCipher = AES.new(key, AES.MODE_CBC, '1234567890123456')
# 加密
cipher = AESCipher.encrypt(str)
return b2a_hex(cipher)
# CBC模式解密
def decrypt_CBC(str, key):
# 补全字符串
key = align(key, True)
# 初始化AES
AESCipher = AES.new(key, AES.MODE_CBC, '1234567890123456')
# 解密
paint = AESCipher.decrypt(a2b_hex(str))
return paint
# 输入密码
key = getpass.getpass("Password Please:")
# 尝试读取密文文件,如果密文文件不存在,则不进行解密直接进入加密流程
try:
fcipher = open("PWencrypt", "r")
fpaint = open("PW.txt", "w+")
# 读取密文文件
fcipherText = fcipher.read()
# 读取密文和校验哈希值
cipherText = fcipherText.split(',')[0]
painhash = fcipherText.split(',')[1]
# 用密码解密
painText = decrypt_CBC(cipherText, key)
# 去除/0
painText = painText.rstrip('\0')
# 校验密码
# 计算本次解密后明文的哈希值
MD5hash = MD5.new()
MD5hash.update(painText)
# 比对哈希值判断密码是否正确
if painhash != MD5hash.hexdigest():
print ('wrong password!!')
else:
fpaint.write(painText)
fpaint.close()
fcipher.close()
# 打开PW.txt后脚本会被挂起
print ("Don't Close!!!")
os.system("notepad PW.txt")
except:
print("Something wrong when Decrypt!")
# 加密,加密明文文件,写入密文文件并删除明文文件
try:
fpaint = open("PW.txt", "r")
# 读取明文文件
painText = fpaint.read()
# 如果明文为空,则不执行加密
if len(painText) > 0:
fcipher = open("PWencrypt", "w")
# 加密
cipherText = encrypt_CBC(painText, key)
# 计算明文哈希值
MD5hash = MD5.new()
MD5hash.update(painText)
# 将密文和校验码写入密文文件
cipherText = cipherText + ',' + MD5hash.hexdigest()
fcipher.write(cipherText)
fcipher.close()
fpaint.close()
# 删除明文文件
os.remove("PW.txt")
except:
print("Something wrong when Encrypt!!")
# 延时,方便看控制台的输出
print ("Quit after 3S")
time.sleep(3)