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()
'gx98xfeZx1ax99xccmx82x8fxa7xa6x13xc6x96x0c\;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()
'gx98xfeZx1ax99xccmx82x8fxa7xa6x13xc6x96x0c\;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

原文地址:https://www.cnblogs.com/shengulong/p/7474621.html