Home | History | Annotate | Download | only in Lib
      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 from _operator import _compare_digest as compare_digest
      8 import hashlib as _hashlib
      9 
     10 trans_5C = bytes((x ^ 0x5C) for x in range(256))
     11 trans_36 = bytes((x ^ 0x36) for x in range(256))
     12 
     13 # The size of the digests returned by HMAC depends on the underlying
     14 # hashing module used.  Use digest_size from the instance of HMAC instead.
     15 digest_size = None
     16 
     17 
     18 
     19 class HMAC:
     20     """RFC 2104 HMAC class.  Also complies with RFC 4231.
     21 
     22     This supports the API for Cryptographic Hash Functions (PEP 247).
     23     """
     24     blocksize = 64  # 512-bit HMAC; can be changed in subclasses.
     25 
     26     def __init__(self, key, msg = None, digestmod = None):
     27         """Create a new HMAC object.
     28 
     29         key:       key for the keyed hash object.
     30         msg:       Initial input for the hash, if provided.
     31         digestmod: A module supporting PEP 247.  *OR*
     32                    A hashlib constructor returning a new hash object. *OR*
     33                    A hash name suitable for hashlib.new().
     34                    Defaults to hashlib.md5.
     35                    Implicit default to hashlib.md5 is deprecated and will be
     36                    removed in Python 3.6.
     37 
     38         Note: key and msg must be a bytes or bytearray objects.
     39         """
     40 
     41         if not isinstance(key, (bytes, bytearray)):
     42             raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
     43 
     44         if digestmod is None:
     45             _warnings.warn("HMAC() without an explicit digestmod argument "
     46                            "is deprecated.", PendingDeprecationWarning, 2)
     47             digestmod = _hashlib.md5
     48 
     49         if callable(digestmod):
     50             self.digest_cons = digestmod
     51         elif isinstance(digestmod, str):
     52             self.digest_cons = lambda d=b'': _hashlib.new(digestmod, d)
     53         else:
     54             self.digest_cons = lambda d=b'': digestmod.new(d)
     55 
     56         self.outer = self.digest_cons()
     57         self.inner = self.digest_cons()
     58         self.digest_size = self.inner.digest_size
     59 
     60         if hasattr(self.inner, 'block_size'):
     61             blocksize = self.inner.block_size
     62             if blocksize < 16:
     63                 _warnings.warn('block_size of %d seems too small; using our '
     64                                'default of %d.' % (blocksize, self.blocksize),
     65                                RuntimeWarning, 2)
     66                 blocksize = self.blocksize
     67         else:
     68             _warnings.warn('No block_size attribute on given digest object; '
     69                            'Assuming %d.' % (self.blocksize),
     70                            RuntimeWarning, 2)
     71             blocksize = self.blocksize
     72 
     73         # self.blocksize is the default blocksize. self.block_size is
     74         # effective block size as well as the public API attribute.
     75         self.block_size = blocksize
     76 
     77         if len(key) > blocksize:
     78             key = self.digest_cons(key).digest()
     79 
     80         key = key.ljust(blocksize, b'\0')
     81         self.outer.update(key.translate(trans_5C))
     82         self.inner.update(key.translate(trans_36))
     83         if msg is not None:
     84             self.update(msg)
     85 
     86     @property
     87     def name(self):
     88         return "hmac-" + self.inner.name
     89 
     90     def update(self, msg):
     91         """Update this hashing object with the string msg.
     92         """
     93         self.inner.update(msg)
     94 
     95     def copy(self):
     96         """Return a separate copy of this hashing object.
     97 
     98         An update to this copy won't affect the original object.
     99         """
    100         # Call __new__ directly to avoid the expensive __init__.
    101         other = self.__class__.__new__(self.__class__)
    102         other.digest_cons = self.digest_cons
    103         other.digest_size = self.digest_size
    104         other.inner = self.inner.copy()
    105         other.outer = self.outer.copy()
    106         return other
    107 
    108     def _current(self):
    109         """Return a hash object for the current state.
    110 
    111         To be used only internally with digest() and hexdigest().
    112         """
    113         h = self.outer.copy()
    114         h.update(self.inner.digest())
    115         return h
    116 
    117     def digest(self):
    118         """Return the hash value of this hashing object.
    119 
    120         This returns a string containing 8-bit data.  The object is
    121         not altered in any way by this function; you can continue
    122         updating the object after calling this function.
    123         """
    124         h = self._current()
    125         return h.digest()
    126 
    127     def hexdigest(self):
    128         """Like digest(), but returns a string of hexadecimal digits instead.
    129         """
    130         h = self._current()
    131         return h.hexdigest()
    132 
    133 def new(key, msg = None, digestmod = None):
    134     """Create a new hashing object and return it.
    135 
    136     key: The starting key for the hash.
    137     msg: if available, will immediately be hashed into the object's starting
    138     state.
    139 
    140     You can now feed arbitrary strings into the object using its update()
    141     method, and can ask for the hash value at any time by calling its digest()
    142     method.
    143     """
    144     return HMAC(key, msg, digestmod)
    145