摘要算法(hashlib)

Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。

什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)

你写了一篇文章,内容是一个字符串'how to use python hashlib - by Michael',并附上这篇文章的摘要是'2d73d4f15c0db7f5ecb321b6a65e5d6d'

如果有人篡改了你的文章,并发表为'how to use python hashlib - by Bob',你可以一下子指出Bob篡改了你的文章,因为根据'how to use python hashlib - by Bob'计算出的摘要不同于原始文章的摘要

可见,摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。

摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。

MD5

我们以常见的摘要算法MD5为例,计算出一个字符串的MD5值:

import hashlib

s = 'tz_spider'
m = hashlib.md5()
# 加密数据都是bytes
m.update(s.encode('utf-8'))
print('md5 hash %s'%m.hexdigest())
"""
md5 hash a4499790ea68682695a0a168a8ec1ecc
"""

如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的:

import hashlib
md5 = hashlib.md5()
md5.update('人生苦短,'.encode('utf-8'))
md5.update('我学Python'.encode('utf-8'))
print(md5.hexdigest()) import hashlib
md5 = hashlib.md5()
md5.update('人生苦短,我学Python'.encode('utf-8'))
print(md5.hexdigest()) """
d51a987403720a379fa5d20ab8b7741c
d51a987403720a379fa5d20ab8b7741c
"""

SHA1

MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。

另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全类似:

import hashlib
md5 = hashlib.sha1()
md5.update('人生苦短,'.encode('utf-8'))
md5.update('我学Python'.encode('utf-8'))
print(md5.hexdigest()) import hashlib
md5 = hashlib.sha1()
md5.update('人生苦短,我学Python'.encode('utf-8'))
print(md5.hexdigest()) """
5723b4cd6bc67f1f3682cab2a382e333518ed23a
5723b4cd6bc67f1f3682cab2a382e333518ed23a
"""

SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。

摘要算法应用

摘要算法主要用于用户登录时,对口令进行MD5加密,存储到数据库中,存储MD5的好处是即使运维人员能访问数据库,也无法获知用户的明文口令。

def get_md5(s):
md5 = hashlib.md5()
md5.update(s.encode('utf-8'))
return md5.hexdigest() user_md5_dict = {}
user_dict = {
'michael': '',
'bob': 'abc'} for item in user_dict:
user_md5_dict[item] = get_md5(user_dict.get(item))
print(user_md5_dict)
"""
{'michael': 'e10adc3949ba59abbe56e057f20f883e', 'bob': '900150983cd24fb0d6963f7d28e17f72'}
"""

采用MD5存储口令是否就一定安全呢?也不一定,很多用户喜欢用123456888888password这些简单的口令,于是,黑客可以事先计算出这些常用口令的MD5值,得到一个反推表:

'e10adc3949ba59abbe56e057f20f883e': ''
'21218cca77804d2ba1922c33e0151105': ''

这样,无需破解,只需要对比数据库的MD5,黑客就获得了使用常用口令的用户账号(撞库)。

由于常用口令的MD5值很容易被计算出来,所以,要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5,这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐”

def calc_md5(password, salt='add salt'):
md5 = hashlib.md5()
md5.update((password+salt).encode('utf-8'))
a = md5.hexdigest()
return a user_md5_dict = {}
user_dict = {
'michael': '',
'bob': 'abc'} for item in user_dict:
user_md5_dict[item] = calc_md5(user_dict.get(item))
print(user_md5_dict)
"""
{'michael': '121e5a2806adb57b7f5ddfb49c58cb38', 'bob': '655cb18b65100d50c375826e4a7138d9'}
"""

经过Salt处理的MD5口令,只要Salt不被黑客知道,即使用户输入简单口令,也很难通过MD5反推明文口令。

但是如果有两个用户都使用了相同的简单口令比如123456,在数据库中,将存储两条相同的MD5值,这说明这两个用户的口令是一样的。有没有办法让使用相同口令的用户存储不同的MD5呢?

如果假定用户无法修改登录名,就可以通过把登录名作为Salt的一部分来计算MD5,从而实现相同口令的用户也存储不同的MD5。

def calc_md5(user, password, salt='add salt'):
md5 = hashlib.md5()
md5.update((user + password + salt).encode('utf-8'))
a = md5.hexdigest()
return a user_md5_dict = {}
user_dict = {
'michael': '',
'bob': ''} for item in user_dict:
user_md5_dict[item] = calc_md5(item, user_dict.get(item))
print(user_md5_dict)
"""
{'michael': '18833a2efa41021c1659af9eb7ffc0e5', 'bob': 'b2c512421985a2622a64fa84b486dc0b'}
"""

 获取文件的MD5

import os
def calc_md5(filename):
"""
用于获取文件的md5值
:param filename: 文件名
:return: MD5码
"""
if not os.path.isfile(filename): # 如果校验md5的文件不是文件,返回空
return
myhash = hashlib.md5()
f = open(filename, 'rb')
while True:
b = f.read(2048)
if not b:
break
myhash.update(b)
f.close()
return myhash.hexdigest() print(calc_md5('BaiduStockInfo.txt'))
"""
94da595be98b4c65fc1ccf697a435322
"""

base64

base64模块是用来作base64编码解码的。这种编码方式在电子邮件中是很常见的。
它可以把不能作为文本显示的二进制数据编码为可显示的文本信息。编码后的文本大小会增大1/3。

Base64的原理很简单,首先,准备一个包含64个字符的数组:

['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']

然后,对二进制数据进行处理,每3个字节一组,一共是3x8=24bit,划为4组,每组正好6个bit

这样我们得到4个数字作为索引,然后查表,获得相应的4个字符,就是编码后的字符串。

所以,Base64编码会把3字节的二进制数据编码为4字节的文本数据,长度增加33%,好处是编码后的文本数据可以在邮件正文、网页等直接显示。

如果要编码的二进制数据不是3的倍数,最后会剩下1个或2个字节怎么办?Base64用\x00字节在末尾补足后,再在编码的末尾加上1个或2个=号,表示补了多少字节,解码的时候,会自动去掉。

import base64
s = b''
s1 = base64.b64encode(s) # 编码
print(s1)
print(base64.b64decode(s1)) # 解码

输出

b'MTIzNDU2Nw=='
b'1234567'

由于标准的Base64编码后可能出现字符+/,在URL中就不能直接作为参数,所以又有一种"url safe"的base64编码,其实就是把字符+/分别变成-_

import base64
s = b'i\xb7\x1d\xfb\xef\xff'
s1 = base64.b64encode(s) # 编码
print(s1)
s2 = base64.urlsafe_b64encode(s)
print(s2)
print(base64.b64decode(s1)) # 解码
print(base64.urlsafe_b64decode(s2)) # 解码

输出

b'abcd++//'
b'abcd--__'
b'i\xb7\x1d\xfb\xef\xff'
b'i\xb7\x1d\xfb\xef\xff'

 

参考https://www.liaoxuefeng.com/

Python模块——HashLib与base64的更多相关文章

  1. Python模块——HashLib(摘要算法)与base64

    摘要算法(hashlib) Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等. 什么是摘要算法呢?摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度 ...

  2. python模块: hashlib模块, configparse模块, logging模块,collections模块

    一. hashlib模块 Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等. 摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用 ...

  3. Python模块hashlib

    Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等. 什么是摘要算法呢?摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制 ...

  4. python模块hashlib & hmac

    Hash,译做“散列”,也有直接音译为“哈希”的.把任意长度的输入,通过某种hash算法,变换成固定长度的输出,该输出就是散列值,也称摘要值.该算法就是哈希函数,也称摘要函数. MD5是最常见的摘要算 ...

  5. python模块——hashlib模块(简单文件摘要算法实现)

    #!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = "loki" # Usage: hashlib模块 import ...

  6. Python模块——hashlib

    简介 hashlib模块是用于对字符串进行加密,其可以把任意长度的数据转换为一个长度固定的数据串,且这种加密是不可逆的,故这种加密方式的安全性都很高.hash本质是一个函数,该模块提供了许多不同的加密 ...

  7. python模块hashlib、xlwt、pymysql

    一.xlwt xlwt是python第三方模块,主要是对excel的写操作.xlwt使用时必须先安装. 1.安装 在操作系统的cmd窗口输入pip install xlwt回车即可在线安装. 安装完成 ...

  8. python模块--hashlib

    用于加密相关的操作,3.x里代替了md5模块和sha模块,主要提供SHA1,SHA224,SHA256,SHA384,SHA512,MD5算法 import hashlib m = hashlib.m ...

  9. python 模块 hashlib(提供多个不同的加密算法)

    hashlib是涉及安全散列和消息摘要,提供多个不同的加密算法借口,如SHA1.SHA224.SHA256.SHA384.SHA512.MD5等. import hashlib m = hashlib ...

随机推荐

  1. SpringCloud-day01-简介

    1.spring cloud简介 Spring Cloud是一系列框架的有序集合.它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册.配置中心.消息总线.负载 ...

  2. cdnbest架设cdn同一个源用不同的端口访问如何设置

    在站点里的应用防火墙-->高级设置里配置 比如test.com要同时用80和88访问

  3. HTML 元素大小

    1.元素的偏移量 元素的可见大小是由其高度.宽度决定,包括所有的内边距.滚动条和边框大小(不包括外边距). offsetHeight :元素在垂直方向上占用的空间大小,以像素计算.包括元素的高度,水平 ...

  4. 【读书笔记】深入应用C++11代码优化与工业级应用 读书笔记01

    第一章 使用C++11让程序更简洁.更现代 1.1  类型推导 1.1.1  auto类型推导 1.auto关键字的新意义 不同于python等动态类型语言的运行时进行变量类型的推导,隐式类型定义的类 ...

  5. 用<pre>预格式化的文本

    被包围在 <pre> 标签 元素中的文本通常会保留空格和换行符.而文本也会呈现为等宽字体. 提示: <pre> 标签的一个常见应用就是用来表示计算机的源代码.

  6. Linux下搭建ftp服务

    Linux下ftp服务可以通过搭建vsftpd服务来实现,以CentOS为例,首先查看系统中是否安装了vsftpd,可以通过执行命令 rpm -qa | grep vsftpd 来查看是否安装相应的包 ...

  7. centos7通过yum安装JDK1.8

    安装之前先检查一下系统有没有自带open-jdk 命令: rpm -qa |grep java rpm -qa |grep jdk rpm -qa |grep gcj 如果没有输入信息表示没有安装. ...

  8. URI编码时遇到特殊字符的处理方式

    今天遇到一个问题,在向一个地址发起get请求时,某个参数是这种形式:foo=xx&&yyyy,其中"&&"是参数值的一部分,在调用这个接口时,后台收 ...

  9. [C#.net]未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序

    C#操作Execl文件常用的2种方式是NPOI和Microsoft.Jet.OleDb,前者需要引用dll,后者需要安装Office客户端 今天发现别人电脑使用Microsoft.Jet.OleDb能 ...

  10. boost--日期处理

    1.timer 不同于系统函数的timer()一般生成一个定时器,boost中的timer是一个计时器,以秒为单位,最小精度为毫秒,使用需要包含头文件"boost\timer.hpp&quo ...