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(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方式實現
消息認證碼可以使用 單向散列函數和 對稱密碼等技術來實現
參考:
1、http://www.jianshu.com/p/8d7c8f59ea21
2、http://www.ftsafe.com.cn/service/kbase/infomation-2