Python模塊——HashLib與base64

摘要算法(hashlib)

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

什麼是摘要算法呢?摘要算法又稱哈希算法、散列算法。它經過一個函數,把任意長度的數據轉換爲一個長度固定的數據串(一般用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(),最後計算的結果是同樣的:ide

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': '123456', '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': '123456'
'21218cca77804d2ba1922c33e0151105': '888888'

這樣,無需破解,只須要對比數據庫的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': '123456', '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': '123456', 'bob': '123456'} 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'1234567' 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/

相關文章
相關標籤/搜索