学了一门课 ,叫《现代密码学》,做实验要实现AES加密文件,RSA加密AES秘钥,然后再反向解密出来,模拟的过程如下:
Alice先加密!
加密过程:
之后Bob再解密!
解密过程:
鉴于是个学渣,用到的RSA,AES,MD5算法都只是大概了解一下,并没有花心思去实现,而且密码学老师给的密码库并不会用,所以,在另外一位同学的建议下,用了只是知道一点点的python来实现,因为有两个挺好的密码库来用 pycrypto M2crypto
过程很曲折,轻易勿模仿!
之后是实验报告
实验报告
一、 设计思路
加密:
Alice拥有: AES秘钥,Bob公钥,Alice的私钥
解密:
Bob拥有:Alice的公钥,Bob的私钥
二、 程序结构
采用python编写,用到两个加解密库:pycrypto,M2crypto
main.py 主函数,调用其他函数
functions.py 具体函数的实现
三、 函数代码
① # AES加密
def aes_encrypt(aes_file, key,iv): #aes_file 文件,key 16-bytes 对称秘钥
from Crypto.Cipher import AES
from Crypto import Random
cipher = AES.new(key, AES.MODE_OFB,iv) # 生成了加密时需要的实际密码,这里采用OFB模式
# if fs is a multiple of 16
x = len(aes_file) % 16
print '要加密文件的长度是: ', len(aes_file)
print '需要填充的数据长度 : ',(16- x)%16
if x != 0:
aes_file_pad = aes_file + '0'*(16 - x)# It should be 16-x
else:
aes_file_pad=aes_file
msg = cipher.encrypt(aes_file_pad)
return msg,(16- x)%16
② # AES解密
def aes_decrypt(aes_file, key,iv):
from Crypto.Cipher import AES
cipher = AES.new(key, AES.MODE_OFB,iv) # 生成了解密时需要的实际密码,这里采用OFB模式
msg=cipher.decrypt(aes_file)
return msg
③# 计算MD5值
def md5_encrypt(md5_file):
from Crypto.Hash import MD5
msg = MD5.new()
msg.update(md5_file)
return msg.hexdigest()
④# RSA私钥加密
def rsa_private_encrypt(msg,file_rsa_private_key_name):
from M2Crypto import RSA # 用M2Crypto下的RSA模块
rsa_private_key=RSA.load_key(file_rsa_private_key_name)
msg_encrypted=rsa_private_key.private_encrypt(msg,RSA.pkcs1_padding)
return msg_encrypted
RSA公钥加密、私钥解密、公钥解密与此类似
四、 问题解决
1. 采用AES加密CFB(输出反馈模式),需要初始化加密模块,生成16位的iv,需要给Bob发送,可以跟AES秘钥一样采用RSA加密
2. 读入字符串时,区别raw_input(),input(),只能用前者
原因:input会把输入的字符串当做一个变量名
3.AES加密时遇到数据块不足一整块情况,会进行填充,这样导致内容发生变化,以致解密出的文件与原文件MD5不一致,故需把填充位数发送给Bob,解密时可去掉填充部分
五、 参考网页
基本python语法:(这网站挺好的)
http://www.runoob.com/python/python-tutorial.html
关于命令行显示:http://jingyan.baidu.com/article/925f8cb8e00554c0dde0562b.html
pycrypto库说明:(MD5例子在此找到)
https://pythonhosted.org/pycrypto/
M2crypto库说明:
http://www.heikkitoivonen.net/m2crypto/api/
实现AES:
http://blog.chinaunix.net/uid-26275986-id-4349364.html
实现RSA:
生成RSA公钥秘钥:
http://codego.net/438504/
环境配置(建议自己用virtualenv配置一个虚拟python环境):
Python安装:
http://jingyan.baidu.com/article/7908e85c78c743af491ad261.html
或者http://www.runoob.com/python/python-install.html
两个库安装(直接使用pip):
pip install pycrypto
pip install --egg M2CryptoWin32
再之后是乱乱的代码
main.py
# coding:utf8
import functions
from functions import file_encrypt, file_decrypt, printCN, raw_inputCN
while 1: # 相当于主程序了。。。
printCN("这是一个加解密文件程序,请按照提示输入!\n")
printCN("请选择:\n1.加密文件 2.解密文件 3.退出")
select = input()
if select == 1:
file_encrypt()
break
elif select == 2:
file_decrypt()
break
else:
break
functions.py
# coding:utf8
# 终端输出中文不乱码
def printCN(str1):
print(str1.decode("utf8"))
def raw_inputCN(str1):
return raw_input(str1.decode("utf8").encode("gbk"))
def file_encrypt():
printCN("请把以下文件放在与此程序同一路径下")
printCN("1.要加密的文件")
printCN("2.AES秘钥文件")
printCN("3.你的RSA私钥文件")
printCN("4.接收者的RSA公钥文件")
raw_inputCN("放好之后,回车继续\n")
file_name=raw_inputCN("请输入要加密的文件名:\n")
file_aes_key_name=raw_inputCN("请输入AES秘钥文件名:\n")
file=open(file_name,'rb') # 打开要加密文件
file_msg=file.read()
file_aes_key=open(file_aes_key_name,'rb') # 打开AES秘钥文件
aes_key=file_aes_key.read()
from Crypto.Cipher import AES
from Crypto import Random
# iv用来记录AES随机生成的一个16字节初始向量
iv = Random.new().read(AES.block_size) # 使用Crypto中Random模块,读取16字节数据作为iv的值,AES分块大小固定为16字节
printCN("开始对原文件进行AES加密......")
file_encrypted_msg,fill_number=aes_encrypt(file_msg,aes_key,iv) # 调用AES加密函数 fill_number填充的位数
file_encrypted=open('file_encrypted','wb') # 生成存储加密后文件
file_encrypted.write(file_encrypted_msg)
file_encrypted.close()
printCN("原文件AES加密完成!")
file_fill_number=open('fill_number','wb') # 生成存储填充位数文件
file_fill_number.write(str(fill_number))
file_fill_number.close()
printCN("开始对原文件进行MD5摘要")
md5_msg=md5_encrypt(file_msg)
printCN("MD5摘要完成!")
file.close() # 已不用原文件,关闭
file_rsa_private_name=raw_inputCN("请输入你的RSA私钥文件名:\n")
printCN("开始对MD5摘要签名")
signature_msg=rsa_private_encrypt(md5_msg,file_rsa_private_name) # MD5摘要RSA加密
printCN("MD5摘要签名完成!")
printCN("对签名进行AES加密") # 因为MD5值是32位的,所以AES16位一块的加密不需要填充数据
signature_encrypted_msg,number=aes_encrypt(signature_msg,aes_key,iv) # number仅用来接收一个值,没有其他作用
file_signature_encrypted=open('file_signature_encrypted','wb') # 生成存储加密后的签名文件
file_signature_encrypted.write(signature_encrypted_msg)
file_signature_encrypted.close()
printCN("签名AES加密完成!")
file_receiver_rsa_public_name=raw_inputCN("请输入接收者RSA公钥文件名:\n")
printCN("开始对AES秘钥进行RSA加密")
aes_key_encrypted=rsa_public_encrypt(aes_key,file_receiver_rsa_public_name)
file_aes_key_encrypted=open('AES_key_encrypted','wb')
file_aes_key_encrypted.write(aes_key_encrypted)
file_aes_key_encrypted.close()
printCN("AES秘钥RSA加密完成!")
printCN("开始对iv进行RSA加密")
iv_encrypted=rsa_public_encrypt(iv,file_receiver_rsa_public_name)
file_iv_encrypted=open('file_iv_encrypted','wb')
file_iv_encrypted.write(iv_encrypted)
file_iv_encrypted.close()
printCN("对iv的RSA加密完成!")
file_aes_key.close()
printCN("加密过程结束!")
printCN("你需要发送给接收者的文件有:")
printCN("1.已加密文件:file_encrypted")
printCN("2.加密后的AES秘钥文件:AES_key_encrypted")
printCN("3.AES加密后的初始化向量文件:file_iv_encrypted")
printCN("4.加密后的签名文件:file_signature_encrypted")
printCN("5.填充位数文件:fill_number")
printCN("\n最后请删除程序所在路径下加入和生成的文件,谢谢!")
raw_inputCN("回车结束程序\n")
return
def file_decrypt():
printCN("请把以下文件放在与此程序同一路径下:")
printCN("1.加密的文件")
printCN("2.加密的AES秘钥文件")
printCN("3.加密的签名文件")
printCN("4.加密的iv文件")
printCN("5.你的RSA私钥文件")
printCN("6.发送者的RSA公钥文件")
printCN("7.填充位数文件")
raw_inputCN("放好之后,回车继续\n")
file_aes_key_encrypted_name=raw_inputCN("请输入加密的AES秘钥文件名:\n")
iv_encrypted_name=raw_inputCN("请输入加密的AES初始化向量文件名:\n")
file_rsa_private_key_name=raw_inputCN("请输入你的RSA私钥文件名:\n")
file_aes_key_encrypted=open(file_aes_key_encrypted_name,'rb')
aes_key_encrypted=file_aes_key_encrypted.read()
file_iv_encrypted=open(iv_encrypted_name,'rb')
iv_encrypted=file_iv_encrypted.read()
printCN("开始解密AES秘钥")
aes_key=rsa_private_decrypt(aes_key_encrypted, file_rsa_private_key_name)
printCN("AES秘钥解密完成!")
printCN("开始解密AES初始化向量")
iv=rsa_private_decrypt(iv_encrypted,file_rsa_private_key_name)
printCN("AES初始化向量解密完成!")
file_encrypted_name=raw_inputCN("请输入加密的文件名:\n")
file_encrypted=open(file_encrypted_name,'rb')
file_encrypted_msg=file_encrypted.read()
file_fill_number_name=raw_inputCN("请输入填充位数文件名:\n")
file_fill_number=open(file_fill_number_name,'rb')
fill_number=file_fill_number.read()
printCN("开始对加密文件进行AES解密")
file_msg=aes_decrypt(file_encrypted_msg,aes_key,iv)
file_msg=file_msg[0:len(file_msg)-int(fill_number)] # 去掉AES加密时填充的位
printCN("加密文件AES解密完成!")
file_fill_number.close()
file_decrypted=open('file_decrypted','wb') # 解密内容输出到文件
file_decrypted.write(file_msg)
md5_file_msg=md5_encrypt(file_msg) # 计算解密出来的文件的MD5值
file_decrypted.close()
file_encrypted.close() # 加密文件解密完成,关闭
file_signature_encrypted_name=raw_inputCN("请输入加密的签名文件名:\n")
file_signature_encrypted=open(file_signature_encrypted_name,'rb')
signature_encrypted=file_signature_encrypted.read()
printCN("加密签名文件AES解密")
file_signature=aes_decrypt(signature_encrypted,aes_key,iv)
printCN("加密签名文件AES解密完成!")
file_signature_encrypted.close()
file_aes_key_encrypted.close() # AES解密完成,关闭相关文件
file_iv_encrypted.close()
sender_public_key_name=raw_inputCN("请输入发送者的公钥文件名:\n")
printCN("开始签名文件RSA解密")
md5_decrypted=rsa_public_decrypt(file_signature,sender_public_key_name)
printCN("签名文件RSA解密完成,得到原文件MD5值!")
if md5_file_msg==md5_decrypted: # MD5值校验
printCN("MD5值校验成功!")
else:
printCN("MD5值校验失败,请重新传输或检查错误原因")
printCN("解密程序运行完毕,请提取解密文件,并删除此程序所在路径下导入及生成的文件,谢谢!")
raw_inputCN("回车结束程序\n")
return
# AES加密
def aes_encrypt(aes_file, key,iv): # aes_file 文件,key 16-bytes 对称秘钥
from Crypto.Cipher import AES
from Crypto import Random
cipher = AES.new(key, AES.MODE_OFB,iv) # 生成了加密时需要的实际密码,这里采用OFB模式
# if fs is a multiple of 16
x = len(aes_file) % 16
printCN("要加密文件的长度是: %d"%len(aes_file))
printCN("需要填充的数据长度 : %d"%((16- x)%16))
if x != 0:
aes_file_pad = aes_file + '0'*(16 - x) # It should be 16-x
else:
aes_file_pad=aes_file
msg = cipher.encrypt(aes_file_pad)
return msg,(16- x)%16
# AES解密
def aes_decrypt(aes_file, key,iv):
from Crypto.Cipher import AES
cipher = AES.new(key, AES.MODE_OFB,iv) # 生成了解密时需要的实际密码,这里采用OFB模式
msg=cipher.decrypt(aes_file)
return msg
# 计算MD5值
def md5_encrypt(md5_file):
from Crypto.Hash import MD5
msg = MD5.new()
msg.update(md5_file)
return msg.hexdigest()
# RSA私钥加密
def rsa_private_encrypt(msg,file_rsa_private_key_name):
from M2Crypto import RSA # 用M2Crypto下的RSA模块
rsa_private_key=RSA.load_key(file_rsa_private_key_name)
msg_encrypted=rsa_private_key.private_encrypt(msg,RSA.pkcs1_padding)
return msg_encrypted
# RSA公钥加密
def rsa_public_encrypt(msg,file_rsa_public_name):
from M2Crypto import RSA # 用M2Crypto下的RSA模块
rsa_public_key=RSA.load_pub_key(file_rsa_public_name)
msg_encrypted=rsa_public_key.public_encrypt(msg,RSA.pkcs1_padding)
return msg_encrypted
# RSA私钥解密
def rsa_private_decrypt(msg,file_rsa_private_key_name):
from M2Crypto import RSA # 用M2Crypto下的RSA模块
rsa_private_key=RSA.load_key(file_rsa_private_key_name)
msg_decrypted=rsa_private_key.private_decrypt(msg,RSA.pkcs1_padding)
return msg_decrypted
# RSA公钥解密
def rsa_public_decrypt(msg,file_rsa_public_name):
from M2Crypto import RSA # 用M2Crypto下的RSA模块
rsa_public_key=RSA.load_pub_key(file_rsa_public_name)
msg_decrypted=rsa_public_key.public_decrypt(msg,RSA.pkcs1_padding)
return msg_decrypted
变量命名过长(没什么办法啊,组织能力不够)