MD5 简介
Message Digest Algorithm MD5(中文名为消息摘要算法 https://baike.so.com/doc/6941562-7163923.html 第五版)为计算机安全领域广泛使用的一种散列函数, 用以提供消息的完整性保护. 该算法的文件号为 RFC 1321(R.Rivest,MIT Laboratory for Computer Science and RSA Data Security Inc. April 1992).
MD5 即 Message-Digest Algorithm 5(信息 - 摘要算法 5), 用于确保信息传输完整一致. 是计算机广泛使用的杂凑算法之一 (又译摘要算法, 哈希算法 https://baike.so.com/doc/6902798-7123502.html ), 主流编程语言普遍已有 MD5 实现. 将数据(如汉字) 运算为另一固定长度值, 是杂凑算法的基础原理, MD5 的前身有 MD2,MD3 https://baike.so.com/doc/2380309-2516809.html 和 MD4.
MD5 算法具有以下特点:
1, 压缩性: 任意长度的数据, 算出的 MD5 值长度都是固定的.
2, 容易计算: 从原数据计算出 MD5 值很容易.
3, 抗修改性: 对原数据进行任何改动, 哪怕只修改 1 个字节, 所得到的 MD5 值都有很大区别.
4, 强抗碰撞: 已知原数据和其 MD5 值, 想找到一个具有相同 MD5 值的数据 (即伪造数据) 是非常困难的.
MD5 的作用是让大容量信息在用数字签名 https://baike.so.com/doc/2871106-3029793.html 软件签署私人密钥前被 "压缩 https://baike.so.com/doc/3143727-3313214.html" 成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制 https://baike.so.com/doc/5330668-5565842.html 数字串). 除了 MD5 以外, 其中比较有名的还有 sha-1,RIPEMD 以及 Haval 等.
举个实际应用的例子. 比如你在百度云 qq 群文件等上传文件的时候, 有时上传几百兆的文件可以几秒内完成, 是真的网络有这么快么? 不是, 通常是服务器已经存在你所上传的文件. 那么系统是如何确定服务器已经存在你要上传的文件的呢? 多为计算你要上传文件的 MD5, 如果 MD5 和已有文件的 MD5 一致, 就认为文件已经存在.
计算 MD5
linux 下 shell 命令行工具 md5sum 用于计算与校验 RFC 1321 所描述的 128 位 MD5 哈希值.
- $ echo "hello"> hello
- $ md5sum hello
- b1946ac92492d2347c6235b4d2611184 hello
上述过程也可以用 python3 实现
- >>> import hashlib
- >>> hashlib.md5(open('hello','rb').read()).hexdigest()
- 'b1946ac92492d2347c6235b4d2611184'
上述代码的函数封装 https://github.com/china-testing/python-api-tesing/blob/master/data_common.py , 参见 get_md5 函数.
[Md5sum 英文维基百科参考]( https://en.wikipedia.org/wiki/Md5sum )
MD5 值重复文件多进程检查工具
测试过程中经常发现 MD5 值相同的图片. 之前没有用并发, 检查过程经常需要一个小时, 现在改成多进程. 一般 3 分钟以内可以完成处理(48 核).
此模式也是自行开发性能测试工具的模型之一.
代码:
- #!/usr/bin/python3
- # -*- coding: utf-8 -*-
- # Author: xurongzhong#126.com 技术支持 qq 群: 144081101
- # CreateDate: 2018-1-8
- # check_md5.py
- import multiprocessing
- from pathlib import Path
- import argparse
- import os
- import data_common
- def consumer(queue, results, lock):
- while True:
- item = queue.get()
- if item is None:
- break
- name = os.path.basename(item)
- md5 = data_common.get_md5(item, is_file=True)
- with lock:
- if md5 in results:
- print("Same md5", results[md5], name)
- else:
- results[md5] =[]
- results[md5] = results[md5] + [name]
- if __name__ == '__main__':
- parser = argparse.ArgumentParser()
- parser.add_argument('directory', action="store", help=u'目录')
- parser.add_argument('-t', action="store", dest="typename",
- default="*", help=u'文件扩展名')
- parser.add_argument('--version', action='version',
- version='%(prog)s 1.1 Rongzhong xu 2018 03 22')
- options = parser.parse_args()
- process = []
- queue = multiprocessing.Queue()
- results = multiprocessing.Manager().dict()
- lock = multiprocessing.Lock()
- if multiprocessing.cpu_count() <3:
- number = multiprocessing.cpu_count()
- else:
- number = multiprocessing.cpu_count() - 1
- # Launch the consumer process
- for i in range(number):
- t = multiprocessing.Process(
- target=consumer,args=(queue, results, lock))
- t.daemon=True
- process.append(t)
- for i in range(number):
- process[i].start()
- p = Path(options.directory)
- for item in p.glob('**/*.{}'.format(options.typename)):
- queue.put(str(item))
- for i in range(number):
- queue.put(None)
- for i in range(number):
- process[i].join()
- f = open("md5_files.txt",'w')
- f2 = open("files.txt",'w')
- for item in dict(results):
- f2.write("{},{}\n".format(item,results[item]))
- if len(results[item])> 1:
- f.write("{},{}\n".format(item,results[item]))
演示
- #!python
- $ python3 check_md5.py /home/andrew/code/paper
- Same md5 ['2018.01.07-19.38.15_0.9999967.jpg'] 2018.01.07-19.38.15_0.99999679.jpg
- $ cat md5_files.txt
- 43c5a6e1dcf79d095e97ce63885c5cd7,['2018.01.07-19.38.15_0.9999967.jpg', '2018.01.07-19.38.15_0.99999679.jpg']
- andrew@andrew-PowerEdge-T630:~/code/mobile_data/tools$
注意, 求 MD5 值依赖 https://github.com/china-testing/python-api-tesing/blob/master/data_common.py
来源: http://www.jianshu.com/p/ffa8e2da29bd