hmac的python實現


Hash-based message authentication code,利用哈希算法,以一個密鑰和一個消息為輸入,生成一個消息摘要作為輸出

可以查看python的內置模塊hmac.py的源碼來學習hmac的用法

舉例:

一、

1 import hmac
2 import hashlib
3 mac = hmac.new('secret_key','message_be_crypted',hashlib.md5)#第一個參數是密鑰key,第二個參數是待加密的字符串,第三個參數是hash函數
4 print mac.digest()#打印出字符串的ascii格式
5 print mac.hexdigest()#打印出加密后字符串的十六進制格式

>>> mac=hmac.new('secret_key','ssssddddddd',hashlib.sha1)
>>> mac.digest()
'g\x98\xfeZ\x1a\x99\xccm\x82\x8f\xa7\xa6\x13\xc6\x96\x0c\\;\xd5b' #ascii碼格式,里面包含十六進制格式
>>> mac.hexdigest()
'6798fe5a1a99cc6d828fa7a613c6960c5c3bd562' #把上面的ascii碼轉換為十六機制格式:\x98-->98;g-->十進制的103-->十六進制的0x67-->67
>>>

>>> ord('g')
103
>>> hex(103)
'0x67'
>>>

二、

1 import hmac
2 import hashlib
3 mac = hmac.new('secret_key',digestmod=hashlib.md5)
4 mac.update('message_be_crypted')
5 print mac.digest()
6 print mac.hexdigest()

>>> mac=hmac.new('secret_key',digestmod=hashlib.sha1)
>>> mac.update('ssssddddddd')
>>> mac.digest()
'g\x98\xfeZ\x1a\x99\xccm\x82\x8f\xa7\xa6\x13\xc6\x96\x0c\\;\xd5b'  #ascii碼格式,里面包含十六進制格式
>>> mac.hexdigest()
'6798fe5a1a99cc6d828fa7a613c6960c5c3bd562'  #把上面的ascii碼轉換為十六機制格式:\x98-->98;g-->十進制的103-->十六進制的0x67-->67
>>>

>>> ord('g')
103
>>> hex(103)
'0x67'
>>>

三、hmac.py源碼:支持的hash(散列)函數為==>'md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512'

  1 """HMAC (Keyed-Hashing for Message Authentication) Python module.
  2 
  3 Implements the HMAC algorithm as described by RFC 2104.
  4 """
  5 
  6 import warnings as _warnings
  7 
  8 from operator import _compare_digest as compare_digest
  9 
 10 
 11 trans_5C = "".join ([chr (x ^ 0x5C) for x in xrange(256)])
 12 trans_36 = "".join ([chr (x ^ 0x36) for x in xrange(256)])
 13 
 14 # The size of the digests returned by HMAC depends on the underlying
 15 # hashing module used.  Use digest_size from the instance of HMAC instead.
 16 digest_size = None
 17 
 18 # A unique object passed by HMAC.copy() to the HMAC constructor, in order
 19 # that the latter return very quickly.  HMAC("") in contrast is quite
 20 # expensive.
 21 _secret_backdoor_key = []
 22 
 23 class HMAC:
 24     """RFC 2104 HMAC class.  Also complies with RFC 4231.
 25 
 26     This supports the API for Cryptographic Hash Functions (PEP 247).
 27     """
 28     blocksize = 64  # 512-bit HMAC; can be changed in subclasses.
 29 
 30     def __init__(self, key, msg = None, digestmod = None):
 31         """Create a new HMAC object.
 32 
 33         key:       key for the keyed hash object.
 34         msg:       Initial input for the hash, if provided.
 35         digestmod: A module supporting PEP 247.  *OR*
 36                    A hashlib constructor returning a new hash object.
 37                    Defaults to hashlib.md5.
 38         """
 39 
 40         if key is _secret_backdoor_key: # cheap
 41             return
 42 
 43         if digestmod is None:
 44             import hashlib
 45             digestmod = hashlib.md5
 46 
 47         if hasattr(digestmod, '__call__'):
 48             self.digest_cons = digestmod
 49         else:
 50             self.digest_cons = lambda d='': digestmod.new(d)
 51 
 52         self.outer = self.digest_cons()
 53         self.inner = self.digest_cons()
 54         self.digest_size = self.inner.digest_size
 55 
 56         if hasattr(self.inner, 'block_size'):
 57             blocksize = self.inner.block_size
 58             if blocksize < 16:
 59                 # Very low blocksize, most likely a legacy value like
 60                 # Lib/sha.py and Lib/md5.py have.
 61                 _warnings.warn('block_size of %d seems too small; using our '
 62                                'default of %d.' % (blocksize, self.blocksize),
 63                                RuntimeWarning, 2)
 64                 blocksize = self.blocksize
 65         else:
 66             _warnings.warn('No block_size attribute on given digest object; '
 67                            'Assuming %d.' % (self.blocksize),
 68                            RuntimeWarning, 2)
 69             blocksize = self.blocksize
 70 
 71         if len(key) > blocksize:
 72             key = self.digest_cons(key).digest()
 73 
 74         key = key + chr(0) * (blocksize - len(key))
 75         self.outer.update(key.translate(trans_5C))
 76         self.inner.update(key.translate(trans_36))
 77         if msg is not None:
 78             self.update(msg)
 79 
 80 ##    def clear(self):
 81 ##        raise NotImplementedError, "clear() method not available in HMAC."
 82 
 83     def update(self, msg):
 84         """Update this hashing object with the string msg.
 85         """
 86         self.inner.update(msg)
 87 
 88     def copy(self):
 89         """Return a separate copy of this hashing object.
 90 
 91         An update to this copy won't affect the original object.
 92         """
 93         other = self.__class__(_secret_backdoor_key)
 94         other.digest_cons = self.digest_cons
 95         other.digest_size = self.digest_size
 96         other.inner = self.inner.copy()
 97         other.outer = self.outer.copy()
 98         return other
 99 
100     def _current(self):
101         """Return a hash object for the current state.
102 
103         To be used only internally with digest() and hexdigest().
104         """
105         h = self.outer.copy()
106         h.update(self.inner.digest())
107         return h
108 
109     def digest(self):
110         """Return the hash value of this hashing object.
111 
112         This returns a string containing 8-bit data.  The object is
113         not altered in any way by this function; you can continue
114         updating the object after calling this function.
115         """
116         h = self._current()
117         return h.digest()
118 
119     def hexdigest(self):
120         """Like digest(), but returns a string of hexadecimal digits instead.
121         """
122         h = self._current()
123         return h.hexdigest()
124 
125 def new(key, msg = None, digestmod = None):
126     """Create a new hashing object and return it.
127 
128     key: The starting key for the hash.
129     msg: if available, will immediately be hashed into the object's starting
130     state.
131 
132     You can now feed arbitrary strings into the object using its update()
133     method, and can ask for the hash value at any time by calling its digest()
134     method.
135     """
136     return HMAC(key, msg, digestmod)
hmac.py

四、方法:

HMAC(K,m) = H((K ⊕ opad) ∥ H((K ⊕ ipad) ∥ m))

【opad重復0x36,ipad重復0x5C】

通過兩次hash兩個不同的key來生成。 還沒有發現有任何的方法來產生碰撞。

步驟:

First-Hash: H(Ko XOR Ipad || (data to auth))

Second-Hash: H(Ko XOR Opad || First-Hash)

1. 字符含義

  H 代表所采用的HASH算法(如SHA-256) 

  K 代表認證密碼

  B 代表H中所處理的塊大小,這個大小是處理塊大小,而不是輸出hash的大小 【SHA-1和SHA-256 B = 64,SHA-384和SHA-512 B = 128 】

  Ko 代表HASH算法的密文 【在密鑰K后面添加0來創建一個字長為B的字符串。(例如,如果K的字長是20字節,B=64字節,則K后會加入44個零字節0x00) 

  Opad 用0x5a重復B次 
  Ipad 用0x36重復B次

2. Ko與ipad做異或運算。

3. 將數據流text填充至第2步的結果字符串中

4. 用H作用於第3步生成的數據流。 

5. Ko與opad做異或運算。

6. 再將第4步的結果填充進第5步的結果中。 

7. 用H作用於第6步生成的數據流,輸出最終結果

五、應用場景:

HMAC的一個典型應用是用在“挑戰/響應”(Challenge/Response)身份認證中

1. 客戶端向服務器發出一個驗證請求

2. 服務器接到此請求后生成一個隨機數並通過網絡傳輸給客戶端(此為挑戰)

3. 客戶端將收到的隨機數提供給ePass,由ePass使用該隨機數存儲在ePass中的密鑰進行HMAC-MD5運算並得到一個結果作為認證證據傳給服務器(此為響應)。

4. 與此同時,服務器也使用該隨機數存儲在服務器數據庫中的該客戶密鑰進行HMAC-MD5運算,如果服務器的運算結果與客戶端傳回的響應結果相同,則認為客戶端是一個合法用戶 

六、安全性:

HMAC算法更象是一種加密算法,它引入了密鑰,其安全性已經不完全依賴於所使用的HASH算法

1. 使用的密鑰是雙方事先約定的,第三方不可能知道。能夠得到的信息只有作為“挑戰”的隨機數和作為“響應”的HMAC結果,無法根據這兩個數據推算出密鑰。由於不知道密鑰,所以無法仿造出一致的響應。

2. HMAC與一般的加密重要的區別在於它具有“瞬時”性,即認證只在當時有效

六、MAC與HMAC:HMAC是MAC的hash方式實現

  消息認證碼(Message Authentication Code)是一種確認完整性並進行認證的技術,簡稱為MAC。消息認證碼的輸入包括 任意長度的消息和一個發送者與接受者之間 共享的密鑰,它可以輸出固定長度的數據,這個數據成為MAC值。要計算MAC必須持有共享密鑰,沒有共享密鑰的人就無法計算MAC值,消息認證碼正是利用這一性質來完成認證的。此外,和單向散列函數的散列值一樣,哪怕消息中發生1比特的變化,MAC值也會產生變化,消息認證碼正是利用這一性質來確認完整性的。消息認證碼可以說是一種與密鑰相關聯的單向散列函數。
  消息認證碼可以使用 單向散列函數對稱密碼等技術來實現
  如圖所示,MAC Algorithm使用HASH(md5/sh1/sh256……)函數,就是HMAC。

參考:

1、http://www.jianshu.com/p/8d7c8f59ea21

2、http://www.ftsafe.com.cn/service/kbase/infomation-2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM