0%

信息摘要算法的python实现和使用场景

概述

MD5(Message-Digest Algorithm 5 信息-摘要算法5)是一个128比特(16个字节)的数值,使用32个16进制位表示。它对应任何字符串都可以加密成一段唯一的固定长度的代码。MD5不是加密算法,加密算法的定义需要可以解密为原始的数据内容,但是MD5只有加密的过程(是一种单向散列哈希算法,不可逆)。MD5发生碰撞(对与不同的输入产生相同的值)的可能性有(但极小)。

python中的使用

生成

uuid.uuid3的实现就是通过MD5产生,内部的实现代码如下:

1
2
3
4
5
6
7
def uuid3(namespace, name):
from hashlib import md5
digest = md5(
namespace.bytes + bytes(name, "utf-8"),
usedforsecurity=False
).digest()
return UUID(bytes=digest[:16], version=3)

Python内置的hashlib模块提供了md5的实现:

1
2
3
4
5
6
7
8
9
10
import hashlib

key = 'this is md5 test!'
hash_md5 = hashlib.md5(key.encode('utf8')) # Unicode-objects must be encoded before hashing
print(hash_md5.hexdigest()) # fa4e0db9e854eddbaf7e0250cbf4f667

# 方式二,使用update传递key
hash_md5 = hashlib.md5()
hash_md5.update(key.encode('utf8')) # 对于key需要转换为bytes类型。
print(hash_md5.hexdigest())

key可以是任意长度的字符串,在传递之前需要先encode编码为非unicode字符(一般为utf8编码格式的字节类型bytes),传递的方式有两种:直接在传递给hashlib.md5(),或者使用hashlib.md5()返回的<class '_hashlib.HASH'>对象的update()方法传递。如果传递的key过长,可以分段使用updat进行传递:

1
2
3
4
hash_md5 = hashlib.md5()
hash_md5.update('this is'.encode('utf8'))
hash_md5.update(' md5 test!'.encode('utf8')) # 注意要和原始data一直,所以空格不能少。
print(hash_md5.hexdigest())

只要知晓使用的key就能得到相同的md5值,以此来验证数据是否被篡改。需要事先约定传递的key(一般为utf8编码格式)。

返回值处理

内置库hashlib对哈希算法都规定了统一的方法以及属性,包括:
name属性,得到该hash函数的名称。
digest_size属性,返回该hahs函数输出的值的字节数。
copy()方法,返回当前HASH对象的副本。
update()方法,添加其他的信息用来跟新当前摘要。
digest()方法,返回字节类型的二进制数据字符串。
hexgigest()方法,返回32个16进制数字字符串。

1
2
3
4
5
6
import hashlib

data = 'this is md5 test!'
hash_md5 = hashlib.md5(data.encode('utf8')) # Unicode-objects must be encoded before hashing
print(type(hash_md5.hexdigest())) # fa4e0db9e854eddbaf7e0250cbf4f667 <class 'str'>
print(hash_md5.digest()) # b'\xfaN\r\xb9\xe8T\xed\xdb\xaf~\x02P\xcb\xf4\xf6g' <class 'bytes'>

两者类型可以通过内置模块binascii进行转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import hashlib

md5 = hashlib.md5(b'hello')
hex = md5.hexdigest()
print(hex) # 5d41402abc4b2a76b9719d911017c592

binary = md5.digest()
print(binary) # b']A@*\xbcK*v\xb9q\x9d\x91\x10\x17\xc5\x92'

import binascii
print(binascii.hexlify(binary)) # b'5d41402abc4b2a76b9719d911017c592'
print(str(binascii.hexlify(binary), encoding='utf8')) # 5d41402abc4b2a76b9719d911017c592

print(binascii.unhexlify(hex)) #b']A@*\xbcK*v\xb9q\x9d\x91\x10\x17\xc5\x92'

应用场景

文件校验

大文件防篡改验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
import hashlib

def get_file_md5(f):
m = hashlib.md5()
while True:
data = f.read(10240)
if not data:
break
m.update(data)
return m.hexdigest()

with open(filedir, 'r') as f:
file_md5 = get_file_md5(f)

通过将得到的file_md5的值和下载文件时平台提供的md5值进行对比,以此验证文件是否被篡改。

支付场景中的应用

如第三方平台一般给你一个key值,要求将该key值以及商品信息等一些其他的信息利用md5(或者其他的摘要算法)产生一个签名,将签名和用户订单信息一起传递给平台,平台通过传递的订单信息以及自己保存的key值,利用相同的算法生成签名进行比较,验证数据的完整性,是否被篡改。
一般的,传递md5的时候,外部还需要使用RSA非对称加密算法进行加密传输。