python笔记:常用内建模块—hashlib

Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)

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

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

一、md5

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

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


改动最后一个字母,可以看到MD5的值是完全不同的:

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

二、SHA1

另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全类似,SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法不仅越慢,而且摘要长度更长。


三、应用

摘要算法能应用到什么地方?
举例:任何允许用户登录的网站都会存储用户登录的用户名和口令。如何存储用户名和口令呢?方法是存到数据库表中,数据库表中存用户名明文和口令明文的MD5码,当用户登录时,首先计算用户输入的明文口令的MD5,然后和数据库存储的MD5对比,如果一致,说明口令输入正确,如果不一致,口令肯定错误。

三、练习

2.1第一题


import hashlib
db = {
    'michael': 'e10adc3949ba59abbe56e057f20f883e',
    'bob': '878ef96e86145580c38c87f0410ad153',
    'alice': '99b1c2188db85afee403b1536010c2c9'
}
def login(user, password):
    pwd5=hashlib.md5()
    pwd5.update(password.encode('utf-8'))
    pwdmd5=pwd5.hexdigest()
    if user in db:
	    return True if db[user] == pwdmd5 else False
# 测试:
assert login('michael', '123456')
assert login('bob', 'abc999')
assert login('alice', 'alice2008')
assert not login('michael', '1234567')
assert not login('bob', '123456')
assert not login('alice', 'Alice2008')
print('ok')

或者简洁书写代码:

import hashlib
def login(user, password):
    return db[user] == hashlib.md5(password.encode('utf-8')).hexdigest()
运行:

2.2第二题

对于用户来讲,当然不要使用过于简单的口令。以防黑客通过MD5码得出的反推表进行破解。但是,我们能否在程序设计上对简单口令加强保护呢?由于常用口令的MD5值很容易被计算出来,所以,要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5,这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐”

def calc_md5(password):
    return get_md5(password + 'the-Salt')

但是如果有两个用户都使用了相同的简单口令比如123456,在数据库中,将存储两条相同的MD5值,这说明这两个用户的口令是一样的。有没有办法让使用相同口令的用户存储不同的MD5呢?如果假定用户无法修改登录名,就可以通过把登录名作为Salt的一部分来计算MD5,从而实现相同口令的用户也存储不同的MD5

练习


代码:

# -*- coding: utf-8 -*-
import hashlib, random

def get_md5(s):
    return hashlib.md5(s.encode('utf-8')).hexdigest()

class User(object):
    def __init__(self, username, password):
        self.username = username
        self.salt = ''.join([chr(random.randint(48, 122)) for i in range(20)])
        self.password = get_md5(password + self.salt)
db = {
    'michael': User('michael', '123456'),
    'bob': User('bob', 'abc999'),
    'alice': User('alice', 'alice2008')
}
def login(username, password):
    user = db[username]
    return user.password == get_md5(password+user.salt)

# 测试:
assert login('michael', '123456')
assert login('bob', 'abc999')
assert login('alice', 'alice2008')
assert not login('michael', '1234567')
assert not login('bob', '123456')
assert not login('alice', 'Alice2008')
print('ok')

运行:



猜你喜欢

转载自blog.csdn.net/zyckhuntoria/article/details/81019433