加解密的问题


 本文抄自,author 小明 2019-07-16

前言:

传输中控制:

在生成中,密码或者重要的信息保密是非常重要的,如何对重要的信息进行加密防止网络数据传输面临的威胁,网络安全涉及很多方面,而网络数据的安全传输通常会面临以下几方面的威胁:

数据窃听与机密性: 即怎样保证数据不会因为被截获或窃听而暴露。

数据篡改与完整性: 即怎样保证数据不会被恶意篡改。

身份冒充与身份验证: 即怎样保证数据交互双方的身份没有被冒充。

相应的解决方案

针对以上几个问题,可以用以下几种数据加密方式来解决(每种数据加密方式又有多种不同的算法实现):

数据加密方式

描述

主要解决的问题

常用算法

对称加密

指数据加密和解密使用相同的密钥

数据的机密性

DES, AES

非对称加密

也叫公钥加密,指数据加密和解密使用不同的密钥--密钥对儿

身份验证

DSA,RSA

单向加密

指只能加密数据,而不能解密数据

数据的完整性

MD5,SHA系列算法

相关名词解释:

  • HASH: 一般翻译为“散列”(也有直接音译为“哈希”),就是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变成固定长度的输出,该输出值就是散列值。这种转换是一种压缩映射,也就是散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一确认输入值。简单来说,hash算法就是一种将任意长度的消息压缩为某一固定长度的消息摘要的函数。

 

  • MD5: 全称为 Message Digest algorithm 5,即信息摘要算法。该算法可以生成定长的数据指纹,被广泛应用于加密和解密技术,常用于文件和数据的完整性校验。

 

  • SHA: 全称为 Secure Hash Algorithm,即安全散列算法/安全哈希算法。该算法是数字签名等密码学应用中的重要工具,被广泛应用于电子商务等信息安全领域。根据生成的密文的长度而命名的各种具体的算法有:SHA1(160bits)、SHA224(224bits)、SHA256(256bits)、SHA384(384bits)等。

 

  • HMAC: 全称为 Hash Message Authentication Code,即散列消息鉴别码。HMAC是基于密钥的哈希算法认证协议,主要是利用哈希算法(如MD5, SHA1),以一个密钥和一个消息作为输入,生成一个消息摘要作为输出,因此其具体的算法名称为HMAC-MD5、HMAC-SHA1等。可见HMAC算法是基于各种哈希算法的,只是它在运算过程中还可以使用一个密钥来增强安全性。

Python内置模块简介

Python早期的相关模块这里不再介绍了,我们今天主要说明的是以下几个模块:

模块名

内置模块

描述

hashlib

Y

主要提供了一些常见的单向加密算法(如MD5,SHA等),每种算法都提供了与其同名的函数实现。

hmac

Y

提供了hmac算法的实现,hamc也是单向加密算法,但是它支持设置一个额外的密钥(通常被称为'salt')来提高安全性

random

Y

该模块主要用于一些随机操作,如获取一个随机数,从一个可迭代对象中随机获取指定个数的元素。

secrets

Y

这是Python 3.6中新增的模块,用于获取安全随机数。

base64

Y

该模块主要用于二进制数据与可打印ASCII字符之间的转换操作,它提供了基于Base16, Base32, 和Base64算法以及实际标准Ascii85和Base85的编码和解码函数。

pycrypto

N

支持单向加密、对称加密和公钥加密以及随机数操作,这是个第三方模块,需要额外安装。

 

本编主要针对内置模块hashlib和第三方模块pycrypto展开分析

hashlib模块:

hashlib模块包含的函数与属性:

函数名/属性名

描述

hashlib.new(name[, data])

这是一个通用的哈希对象构造函数,用于构造指定的哈希算法所对应的哈希对象。其中name参数用于指定哈希算法名称,如'md5', 'sha1',不区分大小写;data是一个可选参数,表示初始数据。

hashlib.哈希算法名称()

这是一个hashlib.new()的替换方式,可以直接通过具体的哈希算法名称对应的函数来获取哈希对象,如 hashlib.md5(),hashlib.sha1()等。

hashlib.algorithms_guaranteed

Python 3.2新增的属性,它的值是一个该模块在所有平台都会支持的哈希算法的名称集合:set(['sha1', 'sha224', 'sha384', 'sha256', 'sha512', 'md5'])

hashlib.algorithms_available

Python 3.2新增的属性,它的值是是一个当前运行的Python解释器中可用的哈希算法的名称集合,algorithms_guaranteed将永远是它的子集。

hash对象包含的方法与属性:

函数名/属性名

描述

hash.update(data)

更新哈希对象所要计算的数据,多次调用为累加效果,如m.update(a); m.update(b)等价于m.update(a+b)

hash.digest()

返回传递给update()函数的所有数据的摘要信息--二进制格式的字符串

hash.hexdigest()

返回传递给update()函数的所有数据的摘要信息--十六进制格式的字符串

hash.copy()

返回该哈希对象的一个copy("clone"),这个函数可以用来有效的计算共享一个公共初始子串的数据的摘要信息。

hash.digest_size

hash结果的字节大小,即hash.digest()方法返回结果的字符串长度。这个属性的值对于一个哈希对象来说是固定的,md5:16,sha1(20), sha224(28)

hash.block_size

hash算法内部块的字节大小

hash.name

当前hash对象对应的哈希算法的标准名称--小写形式,可以直接传递给hashlib.new()函数来创建另外一个同类型的哈希对象。

hashlib模块使用步骤:

1)获取一个哈希算法对应的哈希对象(比如名称为hash): 可以通过 hashlib.new(哈希算法名称, 初始出入信息)函数,来获取这个哈希对象,如hashlib.new('MD5', 'Hello'),hashlib.new('SHA1', 'Hello')等;也可以通过hashlib.哈希算法名称()来获取这个哈希对象,如hashlib.md5(), hashlib.sha1()等。

2)设置/追加输入信息: 调用已得到哈希对象的update(输入信息)方法可以设置或追加输入信息,多次调用该方法,等价于把每次传递的参数凭借后进行作为一个参数垫底给update()方法。也就是说,多次调用是累加,而不是覆盖。

3)获取输入信息对应的摘要: 调用已得到的哈希对象的digest()方法或hexdigest()方法即可得到传递给update()方法的字符串参数的摘要信息。digest()方法返回的摘要信息是一个二进制格式的字符串,其中可能包含非ASCII字符,包括NUL字节,该字符串长度可以通过哈希对象的digest_size属性获取;而hexdigest()方法返回的摘要信息是一个16进制格式的字符串,该字符串中只包含16进制的数字,且长度是digest()返回结果长度的2倍,这可用邮件的安全交互或其它非二进制的环境中。

hashlib模块使用实例:

我们以MD5算法为例获取字符串"Hello, World"的摘要信息(也叫数据指纹)

import hashlib

hash  = hashlib.md5()

hash.update('Hello, ')

hash.update('World!')

ret1 = hash.digest()

print(type(ret1), len(ret1), ret1)

ret2 = hash.hexdigest()

print(type(ret2), len(ret2), ret2)

输出结果:

(<type 'str'>, 16, 'e\xa8\xe2}\x88y(81\xb6d\xbd\x8b\x7f\n\xd4')

(<type 'str'>, 32, '65a8e27d8879283831b664bd8b7f0ad4')

分析:

  1. digest()方法返回的结果是一个二进制格式的字符串,字符串中的每个元素是一个字节,我们知道1个字节是8bits,MD5算法获取的数据摘要长度是128bits,因此最后得到的字符串长度是128/8=16;
  2. hexdigest()方法返回的结果是一个16进制格式的字符串,字符串中每个元素是一个16进制数字,我们知道每个16进制数字占4bits,MD5算法获取的数据摘要长度是128bits,因此最后得到的字符串长度是128/4=32。

在实际工作中,我们通常都是获取数据指纹的16进制格式,比如我们在数据库中存放用户密码时,不是明文存放的,而是存放密码的16进制格式的摘要信息。当用户发起登录请求时,我们按照相同的哈希算法获取用户发送的密码的摘要信息,与数据中存放的与该账号对应的密码摘要信息做比对,两者一致则验证成功。

Pycrypto模块:

pycrypto的安装与使用

pycrypto的安装

使用

pip install pycryptodome

安装这个库就可以了。

然后进入这个库的目录:Lib\site-packages

找到 crypto 这个库,更改为首字母大写 Crypto 即可

pycrypto的使用方式

由于pycrypto把不同的类别加密算法的实现模块都放到了Crypto下不同的子包下了,所以我们只需要确定我们所需要使用的加密算法的实现模块在哪个子包下,然后导入相应的实现模块就可以使用了。比如我们打算使用MD5算法,就可以通过from Crypto.Hash import MD5来导入MD5这个模块,然后就可以使用该模块相应的api了。

pycrypto使用实例1--- SHA256

实例1 使用SHA256算法获取一段数据的摘要信息

from Crypto.Hash import SHA256

hash = SHA256.new()

hash.update('Hello, World!')

digest = hash.hexdigest()

print(digest)

输出结果:

dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

实例2 使用AES算法加密,解密一段数据

from Crypto.Cipher import AES

 

# 加密与解密所使用的密钥,长度必须是16的倍数

secret_key = "ThisIs SecretKey"

# 要加密的明文数据,长度必须是16的倍数

plain_data = "Hello, World123!"

# IV参数,长度必须是16的倍数

iv_param = 'This is an IV456'

 

# 数据加密

aes1 = AES.new(secret_key, AES.MODE_CBC, iv_param)

cipher_data = aes1.encrypt(plain_data)

print('cipher data:', cipher_data)

 

# 数据解密

aes2 = AES.new(secret_key, AES.MODE_CBC, 'This is an IV456')

plain_data2 = aes2.decrypt(cipher_data)  # 解密后的明文数据

print('plain text:', plain_data2)

输出结果:

('cipher data\xef\xbc\x9a', '\xcb\x7fd\x03\x12T,\xbe\x91\xac\x1a\xd5\xaa\xe6P\x9a')

('plain text\xef\xbc\x9a', 'Hello, World123!')

pycrypto使用实例1--- AES

AES简介

高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下图:

 

下面看下编码实例:

  1 #!/usr/bin/env python3
  2 
  3 # -*- coding: utf-8 -*-
  4 
  5 # Author: xiaoming
  6 
  7 # @Time :2019/7/3 15:12
  8 
  9 # 这里使用pycrypto‎demo库
 10 
 11 # 安装方法 pip install pycrypto‎demo
 12 
 13  
 14 
 15 from Crypto.Cipher import AES
 16 
 17 from binascii import b2a_hex, a2b_hex
 18 
 19 """
 20 
 21 这里使用的是第三方库pycrypto来实现对敏感数据的加解密
 22 
 23 主要用到ES.new(self.key, self.mode, b'0000000000000000'),
 24 
 25 三个参数key是秘钥,AES.MODE_CBC加密方式,b'0000000000000000'是IV常常用key来代替也可以
 26 
 27 self.key和self.IV必须是16位的倍数, cryptor.encrypt(text)text机密的数据也是16位的倍数
 28 
 29 这里主要功能实现机密数据的自动补全16位的倍数,进行加解密
 30 
 31 使用过程提示TypeError: Object type <class 'str'> cannot be passed to C code
 32 
 33 解决办法:经过Debug发现,是因为传入参数的参数类型存在问题,需要更换为 bytearray"""
 34 
 35  
 36 
 37 class PrpCrypt(object):
 38 
 39  
 40 
 41     def __init__(self, key):
 42 
 43         self.key = key.encode('utf-8')
 44 
 45         self.mode = AES.MODE_CBC
 46 
 47  
 48 
 49     # 加密函数,如果text不足16位就用空格补足为16位,
 50 
 51     # 如果大于16当时不是16的倍数,那就补足为16的倍数。
 52 
 53     def encrypt(self, text):
 54 
 55         text = text.encode('utf-8')
 56 
 57         cryptor = AES.new(self.key, self.mode, b'0000000000000000')
 58 
 59         # 这里密钥key 长度必须为16(AES-128),
 60 
 61         # 24(AES-192),或者32 (AES-256)Bytes 长度
 62 
 63         # 目前AES-128 足够目前使用
 64 
 65         length = 16
 66 
 67         count = len(text)
 68 
 69         if count < length:
 70 
 71             add = (length - count)
 72 
 73             # \0 backspace
 74 
 75             # text = text + ('\0' * add)
 76 
 77             text = text + ('\0' * add).encode('utf-8')
 78 
 79         elif count > length:
 80 
 81             add = (length - (count % length))
 82 
 83             # text = text + ('\0' * add)
 84 
 85             text = text + ('\0' * add).encode('utf-8')
 86 
 87         self.ciphertext = cryptor.encrypt(text)
 88 
 89         # 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
 90 
 91         # 所以这里统一把加密后的字符串转化为16进制字符串
 92 
 93         return b2a_hex(self.ciphertext)
 94 
 95  
 96 
 97     # 解密后,去掉补足的空格用strip() 去掉
 98 
 99     def decrypt(self, text):
100 
101         cryptor = AES.new(self.key, self.mode, b'0000000000000000')
102 
103         plain_text = cryptor.decrypt(a2b_hex(text))
104 
105         # return plain_text.rstrip('\0')
106 
107         return bytes.decode(plain_text).rstrip('\0')
108 
109  
110 
111  
112 
113 if __name__ == '__main__':
114 
115     pc = PrpCrypt('keyskeyskeyskeys')  # 初始化密钥
116 
117     e = pc.encrypt("testtesttest")  # 加密
118 
119     d = pc.decrypt(e)  # 解密
120 
121     print("加密:", e)
122 
123     print("解密:", d)
AES加解密使用

 

打印结果是:

"D:\Program Files\Python36\python.exe" D:/PycharmProjects/test01/chapter01/test.py

加密: b'13634ced6377d8837e763fc8b0e7a76a'

解密: testtesttest

总结

上面讲了很多内容,现在我们简单总结下:

 

  • 数据加密方式大体分为3类:单向加密、对称加密 和 公钥加密(非对称加密)。
  • 这3类加密方式都各自包含不同的加密算法,如单向加密方式中包含MD5、SHA1、SHA256等,这些算法又称为“哈希算法”或“散列算法”或“数据摘要算法”
  • Python内置的hashlib和hmac只提供了单向加密的各种算法实现,如果要做对称加密或者公钥加密操作需要安装第三方扩展模块,常用的是pycrypto模块。另外,hmac允许在使用哈希算法计算数据摘要时使用一个密钥。
  • 随机数操作可以通过三个模块来做,Python内置的random模块和secrets模块(Python 3.6中才可用),还可以通过pycrypto模块中的Crypto.Random子包中的模块来完成。
  • base64只适合编码小段数据,且不能用于数据加密(算法是公开的,且没有密钥,所有人都可以解码)
  • pycrypto是一个加密算法库,几乎所有的加密算法都可以在它里面找到相应的实现模块。

参考网址:

https://www.cnblogs.com/yyds/p/7072492.html

https://blog.csdn.net/qq_28205153/article/details/55798628

需求定义:

密码管理系统

需求:

密码明文显示不安全,密码明文传输不安全, 密码复杂记不住

设计统一的平台管理所有加密后的密码,指定管理员权限,对访问批准授权,和并发访问用户的策略

详细代码设计:

采用的加密算法: 存储采用pycrypto对称加密, 传输采用sha256单项加密

参考网址:https://www.manageengine.cn/products/passwordmanagerpro/features.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章