python模塊--hmac

1.什麼叫hmac

它的全稱叫做Hash-based Message Authentication Code: 哈希消息認證碼,從名字中就可以看出來這個hmac基於哈希函數的,並且還得提供一個祕鑰key,它的作用就是用來保證消息的完整性,不可篡改。基本思想就是,將消息用一個哈希函數加上一個祕鑰key生成一個摘要,比如現在很流行的JWT就是基於hmac實現的。

摘要算法,也叫哈希算法,散列算法,其作用就是將任意長度的輸入值,轉換爲一個固定長度的輸出值,相同的輸入必定輸出也相同,並且不可逆,也就是說很難根據輸出值,計算出輸入值。所以摘要算法一般用來隱藏一些重要數據,但也可以驗證原始數據的真實性,比如應用中用戶密碼,不可能以明文的方式存儲在數據庫把,這樣的話一旦泄露,後果不堪設想,所以一般都是將用戶的密碼,進行hash後存儲起來的,這樣的話,泄露出去,也很難逆推出原始密碼。

常見的摘要算法:MD5 SHA1 SHA256 SHA52等等。
MD5 返回的數據固定長度爲128bit
SHA1 返回的數據固定長度爲160bit
SHA256 返回的數據固定長度爲256bit
SHA512 返回的數據固定長度爲512bit

2.hmac中的一個類和一個方法

看源碼可知python的hmac模塊提供了一個HMAC類new函數

應用中一般都是通過new函數來使用hmac模塊。

def new(key, msg = None, digestmod = None):
    """Create a new hashing object and return it.

    key: The starting key for the hash.
    msg: if available, will immediately be hashed into the object's starting
    state.

    You can now feed arbitrary strings into the object using its update()
    method, and can ask for the hash value at any time by calling its digest()
    method.
    """
    return HMAC(key, msg, digestmod)

其實new函數就是一個快捷api,返回一個HMAC對象,然後通過HMAC對象的digest()和hexdigest()方法來獲得消息簽名。
另外還可以根據update()方法來增量更新摘要,這和完整傳入消息的結果是一樣的

key: 就是祕鑰,並且必須是bytes類型或者bytearray類型
msg:需要加密的消息,並且必須是bytes類型或者bytearray類型
digestmod: 摘要算法,可以是一個hashlib模塊中的哈希算法類,也可以是字符串的類名,還可以不傳,不傳的情況下,默認使用hashlib.md5這個摘要算法

再來看看HMAC類的__init__()方法

import hashlib as _hashlib


class HMAC:
    """RFC 2104 HMAC class.  Also complies with RFC 4231.

    This supports the API for Cryptographic Hash Functions (PEP 247).
    """
    blocksize = 64  # 512-bit HMAC; can be changed in subclasses.

    def __init__(self, key, msg = None, digestmod = None):
        """Create a new HMAC object.

        key:       key for the keyed hash object.
        msg:       Initial input for the hash, if provided.
        digestmod: A module supporting PEP 247.  *OR*
                   A hashlib constructor returning a new hash object. *OR*
                   A hash name suitable for hashlib.new().
                   Defaults to hashlib.md5.
                   Implicit default to hashlib.md5 is deprecated and will be
                   removed in Python 3.6.

        Note: key and msg must be a bytes or bytearray objects.
        """

        if not isinstance(key, (bytes, bytearray)):
            raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)

        if digestmod is None:
            _warnings.warn("HMAC() without an explicit digestmod argument "
                           "is deprecated.", PendingDeprecationWarning, 2)
            digestmod = _hashlib.md5

        if callable(digestmod):
            self.digest_cons = digestmod
        elif isinstance(digestmod, str):
            self.digest_cons = lambda d=b'': _hashlib.new(digestmod, d)
        else:
            self.digest_cons = lambda d=b'': digestmod.new(d)

        self.outer = self.digest_cons()
        self.inner = self.digest_cons()
        self.digest_size = self.inner.digest_size

        if hasattr(self.inner, 'block_size'):
            blocksize = self.inner.block_size
            if blocksize < 16:
                _warnings.warn('block_size of %d seems too small; using our '
                               'default of %d.' % (blocksize, self.blocksize),
                               RuntimeWarning, 2)
                blocksize = self.blocksize
        else:
            _warnings.warn('No block_size attribute on given digest object; '
                           'Assuming %d.' % (self.blocksize),
                           RuntimeWarning, 2)
            blocksize = self.blocksize

        # self.blocksize is the default blocksize. self.block_size is
        # effective block size as well as the public API attribute.
        self.block_size = blocksize

        if len(key) > blocksize:
            key = self.digest_cons(key).digest()

        key = key.ljust(blocksize, b'\0')
        self.outer.update(key.translate(trans_5C))
        self.inner.update(key.translate(trans_36))
        if msg is not None:
            self.update(msg)

可以看出來hmac模塊是依賴hashlib這個模塊的,因爲如果digestmod以字符串的方式指定摘要算法,比如'sha256',需要使用hashlib.new('sha256')導入這個類。

另外如果key的長度不滿足指定摘要算法的要求,會以0填充滿

3. 使用

digest()方法和hexdigest()方法

>>>import hmac
>>>key = b'\&s23@3fsd'
>>>msg = b'hello world'
>>>md5 = hmac.new(key, msg)
>>>dg = md5.hexdigest()
>>>dg
c0ecec9b969d2d32ba4583170fc22651
>>>len(dg)
32
>>>bg = md5.digest()
>>>bg
b'\xc0\xec\xec\x9b\x96\x9d-2\xbaE\x83\x17\x0f\xc2&Q'
>>>len(bg)
16

md5返回數據長度的是128bit
hexdigest()方法是返回十六進制的字符串,所以長度爲32
digest()方式使返回二進制的字節串,所以長度爲16

其他的sha256等等都是一樣的道理

一般應用中都會使用返回二進制類型數據的digest()方法,比如JWT的最後簽名階段就是根據二進制的數據進行base64編碼,最終得到JWT

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