Staging
v0.5.1
https://github.com/python/cpython
Revision d62ecbf0bae673af61fb87d8932cdb1ea80e8922 authored by Georg Brandl on 26 November 2010, 08:52:36 UTC, committed by Georg Brandl on 26 November 2010, 08:52:36 UTC
svn+ssh://svn.python.org/python/branches/py3k

........
  r85728 | georg.brandl | 2010-10-19 20:54:25 +0200 (Di, 19 Okt 2010) | 1 line

  #10092: Properly reset locale in Locale*Calendar classes.  The context manager was buggy because setlocale() returns the *new* locale, not the old.  Also add a test for this.
........
  r85731 | georg.brandl | 2010-10-19 23:07:16 +0200 (Di, 19 Okt 2010) | 1 line

  Be consistent in the spelling of thread-safe(ty).
........
  r85735 | georg.brandl | 2010-10-20 08:50:19 +0200 (Mi, 20 Okt 2010) | 1 line

  Fix r85728: use "" to mean the system default locale, which should work on more systems.
........
  r85766 | georg.brandl | 2010-10-21 09:40:03 +0200 (Do, 21 Okt 2010) | 1 line

  #10159: sort completion matches before comparing to dir() result.
........
  r85767 | georg.brandl | 2010-10-21 14:49:28 +0200 (Do, 21 Okt 2010) | 1 line

  #9095, #8912, #8999: add support in patchcheck for Mercurial checkouts, C file reindenting, and docs whitespace fixing.
........
  r85768 | georg.brandl | 2010-10-21 14:59:14 +0200 (Do, 21 Okt 2010) | 1 line

  #9919: fix off-by-one error in lineno command in Misc/gdbinit; also add newline to its output.
........
  r85769 | georg.brandl | 2010-10-21 15:01:23 +0200 (Do, 21 Okt 2010) | 1 line

  Fix missing import.
........
  r85770 | georg.brandl | 2010-10-21 15:29:10 +0200 (Do, 21 Okt 2010) | 1 line

  #3077: fix h2py substitution of character literals.
........
  r85771 | georg.brandl | 2010-10-21 15:34:51 +0200 (Do, 21 Okt 2010) | 1 line

  #1203650: allow larger list of files in windows makefile for freeze.
........
  r85773 | georg.brandl | 2010-10-21 15:45:52 +0200 (Do, 21 Okt 2010) | 1 line

  #4829: better error message for invalid file mode
........
  r85777 | georg.brandl | 2010-10-21 17:44:51 +0200 (Do, 21 Okt 2010) | 1 line

  Add .hgeol file for the Mercurial EOL extension.
........
1 parent ab32fec
Raw File
Tip revision: d62ecbf0bae673af61fb87d8932cdb1ea80e8922 authored by Georg Brandl on 26 November 2010, 08:52:36 UTC
Merged revisions 85728,85731,85735,85766-85771,85773,85777 via svnmerge from
Tip revision: d62ecbf
hmac.py
"""HMAC (Keyed-Hashing for Message Authentication) Python module.

Implements the HMAC algorithm as described by RFC 2104.
"""

import warnings as _warnings

trans_5C = bytes((x ^ 0x5C) for x in range(256))
trans_36 = bytes((x ^ 0x36) for x in range(256))

# The size of the digests returned by HMAC depends on the underlying
# hashing module used.  Use digest_size from the instance of HMAC instead.
digest_size = None

# A unique object passed by HMAC.copy() to the HMAC constructor, in order
# that the latter return very quickly.  HMAC("") in contrast is quite
# expensive.
_secret_backdoor_key = []

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.
                   Defaults to hashlib.md5.

        Note: key and msg must be bytes objects.
        """

        if key is _secret_backdoor_key: # cheap
            return

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

        if digestmod is None:
            import hashlib
            digestmod = hashlib.md5

        if hasattr(digestmod, '__call__'):
            self.digest_cons = digestmod
        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:
                # Very low blocksize, most likely a legacy value like
                # Lib/sha.py and Lib/md5.py have.
                _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

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

        key = key + bytes(blocksize - len(key))
        self.outer.update(key.translate(trans_5C))
        self.inner.update(key.translate(trans_36))
        if msg is not None:
            self.update(msg)

##    def clear(self):
##        raise NotImplementedError, "clear() method not available in HMAC."

    def update(self, msg):
        """Update this hashing object with the string msg.
        """
        if not isinstance(msg, bytes):
            raise TypeError("expected bytes, but got %r" % type(msg).__name__)
        self.inner.update(msg)

    def copy(self):
        """Return a separate copy of this hashing object.

        An update to this copy won't affect the original object.
        """
        other = self.__class__(_secret_backdoor_key)
        other.digest_cons = self.digest_cons
        other.digest_size = self.digest_size
        other.inner = self.inner.copy()
        other.outer = self.outer.copy()
        return other

    def _current(self):
        """Return a hash object for the current state.

        To be used only internally with digest() and hexdigest().
        """
        h = self.outer.copy()
        h.update(self.inner.digest())
        return h

    def digest(self):
        """Return the hash value of this hashing object.

        This returns a string containing 8-bit data.  The object is
        not altered in any way by this function; you can continue
        updating the object after calling this function.
        """
        h = self._current()
        return h.digest()

    def hexdigest(self):
        """Like digest(), but returns a string of hexadecimal digits instead.
        """
        h = self._current()
        return h.hexdigest()

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)
back to top