Wolf从零学编程-用Python打造简单加密程序(一)

来源:互联网 发布:匿名者专用黑页源码 编辑:程序博客网 时间:2024/06/05 12:46

一、程序分析

近期需要做一个Python小程序,要求根据用户的选择,分别实现文件的数字签名、DES加密、RSA加密。这东西离交付时间还早,进度会慢很多咯。

简单的设计了一个模型,按照如下逻辑实现:

mark

我需要解释一下混合加密的过程:

  1. 计算明文hash值
  2. 用接收方rsa公钥加密des密钥,写入数据文件
  3. 用des密钥加密hash值和明文,写入数据文件
  4. 接收方收到数据文件后,先解密出des密钥,用其解密hash值和明文,再计算明文hash值进行数据校验。

所以我需要完成的模块有SHA-1算法、DES加解密、RSA加解密以及友好的UI。

二、计算文件的HASH值

Python内建模块hashlib提供了常见的MD5、SHA-1等算法,MD5算法已被证实可破解,所以我采用了SHA-1。Hash函数输入可变长度的数据,产生固定长度的hash值,它是单向函数,无法从hash值倒推回输入数据,一般用于消息认证和数字签名。

具体实现时,文件发布者计算hash值,将文件和hash值一同发布,用户下载后,可以计算文件的hash值与发布者发布的hash值进行比较,以确定文件是否被篡改。SHA即安全HASH算法,SHA-1是它的第一个版本,可以产生160位的hash值。

计算hash值的操作十分简单:

import hashlibdata = 'data'sha1 = hashlib.sha1(data.encode('utf-8'))    #Unicode数据在计算前要编码sha1.hexdigest()>'a17c9aaa61e80a1bf71d0d850af4e5baa9800bbd'  #这就是data的hash值

在这里我需要计算文件的hash值,因为不知道文件大小,最好的办法是分块进行计算,需要用到hashlib的update()方法。sha1.update(‘hello’)及sha1.update(‘world’)的计算结果等于sha1.update(‘helloworld’)。

import hashlibdef get_sha1(f):    sha1 = hashlib.sha1()       while True:        data = f.read(10240)    #10240是每次读取的字节数,如不指定则默认全部读取        if not data:            #没数据则退出循环            break        sha1.update(data.encode('utf-8'))    return sha1.hexdigest()#open的第一个参数是要打开的文件,注意这里是'/',在windows资源管理器中显示是'\'#第二个参数的意义是二进制只读。with open('E:/new.txt','rb') as f:    file_sha1 = get_sha1(f)   #定义文件sha1,方便多次在程序中使用;调用get_sha1()计算

open()的第二个参数表示对文件进行的操作,’r’表示只读且为缺省默认;’w’表示写入,此时若已有同名文件则被覆盖;’a’为增加,默认将数据写入文件末尾;’r+’为读和写;’b’是二进制;’rb’是以二进制打开的只读;’r+b’是二进制的读和写。

‘new.txt’是新建的文本文档,随便写点什么就会得到完全不同的hash值。so magic!

关于hashlib的更多信息,可查阅官方文档hashlib

对于文件的操作,还有两个比较重要的方法,f.seek(0)让指针回到文件开始,f.close()操作完成后关闭文件。

关于文件读写,请参考官方文档文件读写

三、使用DES进行对称加密

对称加密就是收发双方共享密钥,使用相同的密钥加解密文件。
Gitgub上有pyDes可以拿来用,因为是纯Python编写,运行速度有限,正常使用是够的。小程序的DES模块就用它啦!

安装pyDES

pip install pydes

以下示例可以帮助理解各个方法和参数:

import pyDeskey = "DESCRYPT"mode = pyDes.CBCIV = "\0\0\0\0\0\0\0\0"data = "Please encrypt my data"k = pyDes.des(key, mode, IV, pad=None, padmode=pyDes.PAD_PKCS5)d = k.encrypt(data)print "Encrypted: %r" % dprint "Decrypted: %r" % k.decrypt(d)

key是加密密钥,使用DES需要8个字节,3-DES需要16或24字节,作为密钥使用的英文和数字都是一个字节,所以key相应的只能是8、16、24个字符。注意,字符和字节没有任何关系,我们看到的任何符号都是字符,字符的数量可以理解为所见即所得,“3二+四9”引号里是5个字符,不要和字节混淆,字节是储存单位。

mode是密码工作模式,提供ECB和CBC模式。ECB(电码本)适合加密小量数据,CBC(密文分组链接)适合加密大量数据。

IV(initial value)初始值,在CBC中加密的第一步需要用到初始值,而ECB中不需要,因此如选择CBC模式就必须提供IV,且必须是8字节。

data是待加密明文。

pad是设置填充字符,padmode是填充模式,作者建议使用PAD_PKCS5模式,此模式下无需担心pad的事情。

pyDes只有两个方法:加密encrypt(data)和解密decrypt(data)。

加密代码如下:

# -*- coding:utf-8 -*-import pyDes#加密def encryptfile(file):    key = str(input('请输入8字节密钥:'))    IV = str(input('请输入8字节初始值:'))    des = pyDes.des(key,pyDes.CBC,IV,pad=None,padmode=pyDes.PAD_PKCS5)    with open(file,'rb') as f1:        data = f1.read()  #pyDes只能加密编码过的信息,用rb读出来的就是        C = des.encrypt(data)        with open(file+'.des','wb') as f2:                f2.write(C)  #注意数据类型,C是二进制编码                f2.close()        f1.close()file = input('输入文件路径:')encryptfile(file)

起初我使用的是’r’模式打开文件,只有txt文件可以正常打开加密,尝试了vsd和doc都会报解码错误。直到看了官网中文件打开模式这段话后,改为’rb’一切正常,哈哈!

关于打开模式,官方文档中有一段话:

Normally, files are opened in text mode, that means, you read and write strings from and to the file, which are encoded in a specific encoding. If encoding is not specified, the default is platform dependent (see open()). ‘b’ appended to the mode opens the file in binary mode: now the data is read and written in the form of bytes objects. This mode should be used for all files that don’t contain text.

In text mode, the default when reading is to convert platform-specific line endings (\n on Unix, \r\n on Windows) to just \n. When writing in text mode, the default is to convert occurrences of \n back to platform-specific line endings. This behind-the-scenes modification to file data is fine for text files, but will corrupt binary data like that in JPEG or EXE files. Be very careful to use binary mode when reading and writing such files.

我的理解是:第一段说不包含文本的文件都用二进制模式打开;第二段说打开JPEG和EXE文件时,一定要用二进制模式。但是并没有说’b’对含有文本的文件有什么不良影响,因此我决定,所有文件都用’rb’打开。

我加密了前面的new.txt,用notepad++打开加密后的文件,是乱码。

mark

Python 3最重要的新特性大概要算是对文本和二进制数据作了更为清晰的区分。文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示。Python 3不会以任意隐式的方式混用str和bytes,正是这使得两者的区分特别清晰。你不能拼接字符串和字节包,也无法在字节包里搜索字符串(反之亦然),也不能将字符串传入参数为字节包的函数(反之亦然)。这是件好事。

关于各种编码格式,可以参考以下博客:
- 阿呆学Unicode之编码
- Python 3的bytes/str之别
- Unicode之痛

今天只能到这里了,待会还有大事~~下次要把DES的解密和RSA搞出来。

1 0
原创粉丝点击