python hashlib 哈希算法

寫在篇前

​ 哈希加密算法應用非常廣泛,包括數字簽名,身份驗證,操作檢測,指紋,校驗和(消息完整性檢查),哈希表,密碼存儲等。在密碼學中,好的哈希算法應該滿足以下兩個條件:一是無法從哈希值解密原始消息;二是,更改原始消息的一個字節,哈希消息會發生非常大的變化。
​ 哈希函數以可變長度的字節序列的作爲輸入,並將其轉換爲固定長度的序列。這個過程是單向的,即意味着,如果f是哈希函數,則f(x)的計算相當簡單快捷,但是如果嘗試從f(x)獲得x則可能需要數年時間。哈希函數返回的值通常稱爲secure hash(安全哈希),message digest(消息摘要)或 checksum(校驗和)。大多數情況下,哈希函數會爲給定的輸入產生唯一的輸出。但是有的哈希算法有可能會發生哈希碰撞。
在這裏插入圖片描述

基本使用

hashlib標準庫提供了兩個常量屬性algorithms_availablealgorithms_guaranteed,前者表示當前python解釋器支持的hash算法名稱(包括openssl提供的hash算法);後者表示該標準庫穩定支持的hash算法,如下所示:

>>> print(hashlib.algorithms_available)
{'sha224', 'sha512-224', 'md4', 'sha3_224', 'sha512-256', 'whirlpool', 'blake2b', 'sha3_512', 'sha3_384', 'md5-sha1', 'sha1', 'sha384', 'sha3_256', 'sha3-384', 'sha256', 'shake_256', 'shake_128', 'sha3-224', 'sm3', 'blake2s256', 'sha3-256', 'ripemd160', 'shake256', 'shake128', 'sha512', 'blake2s', 'mdc2', 'md5', 'blake2b512', 'sha3-512'}
>>> print(hashlib.algorithms_guaranteed)
{'sha3_512', 'blake2s', 'shake_256', 'sha224', 'sha3_384', 'shake_128', 'sha1', 'sha3_224', 'sha384', 'sha3_256', 'md5', 'sha256', 'sha512', 'blake2b'}

hashlib模塊的基本使用非常簡單,只需通過hashlib.encryption_algorithm_name(b“ message")即可對原始消息進行哈希操作。另外,可以使用update()函數將字節消息附加到hash值中。最後,通過使用digest()orhexdigest()函數獲得hash值。需要注意的是,b被寫在消息的左邊表示該字符串是字節字符串:

>>> import hashlib
>>> hash_object = hashlib.md5(b'Hello World')
>>> print(hash_object.hexdigest())
b10a8db164e0754105b7a99be72e3fe5  # 32位
>>> hash_object.digest_size
16
>>> hash_object.block_size
64
>>> hash_object.name
'md5'

# 快捷方式
>>> hashlib.md5(b'Hello World').hexdigest()
b10a8db164e0754105b7a99be72e3fe5

>>> hash_object_b = hash_object.copy()
>>> hash_object_b.update(b' jeffery!').hexdigest()
df52e7ea0abbe37b8b799e7091522dff
>>> hashlib.md5(b'Hello World jeffery!').hexdigest()
df52e7ea0abbe37b8b799e7091522dff

​ 構造hash對象還可以通過通用的new('encryption_algorithm_name')來實現,但是這種構造方法相比hashlib.encryption_algorithm_name()這類方法速度更慢,所以瞭解即可:

>>> h = hashlib.new('ripemd160')
>>> h.update(b"Nobody inspects the spammish repetition")
>>> h.hexdigest()
'cc4a5ce1b3df48aec5d22d1f16b894a0b894eccc'

應用示例

md5文件校驗

​ 上面例子中多次用到MD5算法,MD5,即Message-Digest Algorithm 5,是一種歷經MD2、MD3和MD4發展而來的單向散列算法。其特點是,MD5接受任意長度的信息作爲輸入,輸出爲128位的數字指紋,且該數據指紋具有唯一性、不可逆性。MD5算法其中一個重要用途就是文件校驗,比如大家上傳資源到CSDN資源下載平臺,發現平臺已有的資源會被禁止上傳,其中也許也用到了這種類似的算法,下面給出一個例子供參考:

import os
import hashlib


def get_file_md5_value(path, mode='rb', buffer=1024*1024, salt=None, encoding='utf-8'):
    """

    :param path: 文件路徑
    :param mode: 文件讀取模式
    :param buffer: buffer大小,單位爲B, 默認爲1024*1024B,即1M
    :param salt: 鹽,一般文件重複校驗不加鹽
    :param encoding: 編碼方式
    :return:
    """

    md5_obj = hashlib.md5()
    if salt is not None:
        if isinstance(salt, bytes):
            md5_obj.update(salt)
        else:
            md5_obj.update(str(salt).encode(encoding))

    file_size = os.path.getsize(path)  # 單位是字節,B
    with open(path, mode) as f:
        while file_size:
            if mode == 'rb':
                content = f.read(buffer)
            else:
                content = f.read(buffer).encode(encoding)
            file_size -= len(content)
            md5_obj.update(content)
    return md5_obj.hexdigest()


print(get_file_md5_value('result/AE_NET01.h5', salt='gc'))

hmac密碼加密

​ 我們知道數據庫用戶密碼肯定不能明碼存儲,需要加密存儲,但是直接加密md5(password)也同樣不安全,因爲根據彩虹表還是有很大機率可以破解密碼,因此我們可以通過加鹽的方式,讓密碼破解的難度更上一層樓。所謂加鹽,即每位用戶分配一段隨機序列,作爲salt(鹽)和用戶一起加密,即md5(password + salt)。python標準庫hmac(Keyed-Hashing for Message Authentication)是一個對所有哈希算法都通用的標準算法。在計算哈希值的過程中,把salt混入。

>>> import hmac
>>> message = b'Hello, world!'
>>> key = b'secret'
>>> h = hmac.new(key, message, digestmod='MD5')
>>> h.hexdigest()
'fa4ee7d173f2d97ee79022d1a7355bcf'

​ 在hash標準庫中也有一個類似的函數hashlib.pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None),其中參數 name 是 HMAC 要用到的哈希摘要算法如sha256;passwordsalt 爲字節串,應該大約 16 或更多個 bytes,可用os.urandom();參數 iterations 應基於算法和計算能力設置,比如 100,000 輪 SHA-256 是推薦的次數;參數 dklen 是導出的密鑰的長度。如果 dklenNone 那麼就用參數 name 指定的哈希算法的摘要長度,比如SHA-512爲64。

>>> import hashlib, binascii
>>> dk = hashlib.pbkdf2_hmac('sha256', b'password', b'salt', 100000)
>>> binascii.hexlify(dk)  # 返回二進制的十六進制
b'0394a2ede332c9a13eb82e9b24631604c31df978b4e2f0fbd2c549944f9d79a5'

hashlib標準庫中還提供了一個類似的加密函數hashlib.scrypt(password, *, salt, n, r, p, maxmem=0, dklen=64,該庫中還有很多有趣的hash算法,比如SHAKEBLAKE2,請參考官方文檔。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章