Merged revisions 58862-58885 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r58868 | gregory.p.smith | 2007-11-05 16:19:03 -0800 (Mon, 05 Nov 2007) | 3 lines

  Fixes Issue 1385: The hmac module now computes the correct hmac when using
  hashes with a block size other than 64 bytes (such as sha384 and sha512).
........
This commit is contained in:
Guido van Rossum 2007-11-06 20:51:31 +00:00
parent a3538ebfe3
commit a19f80c6df
3 changed files with 186 additions and 8 deletions

View File

@ -52,6 +52,10 @@ spammish repetition'``::
>>> m.update(b" the spammish repetition") >>> m.update(b" the spammish repetition")
>>> m.digest() >>> m.digest()
b'\xbbd\x9c\x83\xdd\x1e\xa5\xc9\xd9\xde\xc9\xa1\x8d\xf0\xff\xe9' b'\xbbd\x9c\x83\xdd\x1e\xa5\xc9\xd9\xde\xc9\xa1\x8d\xf0\xff\xe9'
>>> m.digest_size
16
>>> m.block_size
64
More condensed:: More condensed::
@ -76,7 +80,11 @@ returned by the constructors:
.. data:: digest_size .. data:: digest_size
The size of the resulting digest in bytes. The size of the resulting hash in bytes.
.. data:: block_size
The internal block size of the hash algorithm in bytes.
A hash object has the following methods: A hash object has the following methods:

View File

@ -3,6 +3,8 @@
Implements the HMAC algorithm as described by RFC 2104. Implements the HMAC algorithm as described by RFC 2104.
""" """
import warnings as _warnings
trans_5C = bytes((x ^ 0x5C) for x in range(256)) trans_5C = bytes((x ^ 0x5C) for x in range(256))
trans_36 = bytes((x ^ 0x36) for x in range(256)) trans_36 = bytes((x ^ 0x36) for x in range(256))
@ -16,7 +18,7 @@
_secret_backdoor_key = [] _secret_backdoor_key = []
class HMAC: class HMAC:
"""RFC2104 HMAC class. """RFC 2104 HMAC class. Also complies with RFC 4231.
This supports the API for Cryptographic Hash Functions (PEP 247). This supports the API for Cryptographic Hash Functions (PEP 247).
""" """
@ -52,7 +54,21 @@ def __init__(self, key, msg = None, digestmod = None):
self.inner = self.digest_cons() self.inner = self.digest_cons()
self.digest_size = self.inner.digest_size 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 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: if len(key) > blocksize:
key = self.digest_cons(key).digest() key = self.digest_cons(key).digest()

View File

@ -1,6 +1,7 @@
import hmac import hmac
from hashlib import sha1 import hashlib
import unittest import unittest
import warnings
from test import test_support from test import test_support
class TestVectorsTestCase(unittest.TestCase): class TestVectorsTestCase(unittest.TestCase):
@ -43,7 +44,7 @@ def md5test(key, data, digest):
def test_sha_vectors(self): def test_sha_vectors(self):
def shatest(key, data, digest): def shatest(key, data, digest):
h = hmac.HMAC(key, data, digestmod=sha1) h = hmac.HMAC(key, data, digestmod=hashlib.sha1)
self.assertEqual(h.hexdigest().upper(), digest.upper()) self.assertEqual(h.hexdigest().upper(), digest.upper())
shatest(b"\x0b" * 20, shatest(b"\x0b" * 20,
@ -75,6 +76,161 @@ def shatest(key, data, digest):
b"and Larger Than One Block-Size Data"), b"and Larger Than One Block-Size Data"),
"e8e99d0f45237d786d6bbaa7965c7808bbff1a91") "e8e99d0f45237d786d6bbaa7965c7808bbff1a91")
def _rfc4231_test_cases(self, hashfunc):
def hmactest(key, data, hexdigests):
h = hmac.HMAC(key, data, digestmod=hashfunc)
self.assertEqual(h.hexdigest().lower(), hexdigests[hashfunc])
# 4.2. Test Case 1
hmactest(key = b'\x0b'*20,
data = b'Hi There',
hexdigests = {
hashlib.sha224: '896fb1128abbdf196832107cd49df33f'
'47b4b1169912ba4f53684b22',
hashlib.sha256: 'b0344c61d8db38535ca8afceaf0bf12b'
'881dc200c9833da726e9376c2e32cff7',
hashlib.sha384: 'afd03944d84895626b0825f4ab46907f'
'15f9dadbe4101ec682aa034c7cebc59c'
'faea9ea9076ede7f4af152e8b2fa9cb6',
hashlib.sha512: '87aa7cdea5ef619d4ff0b4241a1d6cb0'
'2379f4e2ce4ec2787ad0b30545e17cde'
'daa833b7d6b8a702038b274eaea3f4e4'
'be9d914eeb61f1702e696c203a126854',
})
# 4.3. Test Case 2
hmactest(key = b'Jefe',
data = b'what do ya want for nothing?',
hexdigests = {
hashlib.sha224: 'a30e01098bc6dbbf45690f3a7e9e6d0f'
'8bbea2a39e6148008fd05e44',
hashlib.sha256: '5bdcc146bf60754e6a042426089575c7'
'5a003f089d2739839dec58b964ec3843',
hashlib.sha384: 'af45d2e376484031617f78d2b58a6b1b'
'9c7ef464f5a01b47e42ec3736322445e'
'8e2240ca5e69e2c78b3239ecfab21649',
hashlib.sha512: '164b7a7bfcf819e2e395fbe73b56e0a3'
'87bd64222e831fd610270cd7ea250554'
'9758bf75c05a994a6d034f65f8f0e6fd'
'caeab1a34d4a6b4b636e070a38bce737',
})
# 4.4. Test Case 3
hmactest(key = b'\xaa'*20,
data = b'\xdd'*50,
hexdigests = {
hashlib.sha224: '7fb3cb3588c6c1f6ffa9694d7d6ad264'
'9365b0c1f65d69d1ec8333ea',
hashlib.sha256: '773ea91e36800e46854db8ebd09181a7'
'2959098b3ef8c122d9635514ced565fe',
hashlib.sha384: '88062608d3e6ad8a0aa2ace014c8a86f'
'0aa635d947ac9febe83ef4e55966144b'
'2a5ab39dc13814b94e3ab6e101a34f27',
hashlib.sha512: 'fa73b0089d56a284efb0f0756c890be9'
'b1b5dbdd8ee81a3655f83e33b2279d39'
'bf3e848279a722c806b485a47e67c807'
'b946a337bee8942674278859e13292fb',
})
# 4.5. Test Case 4
hmactest(key = bytes(x for x in range(0x01, 0x19+1)),
data = b'\xcd'*50,
hexdigests = {
hashlib.sha224: '6c11506874013cac6a2abc1bb382627c'
'ec6a90d86efc012de7afec5a',
hashlib.sha256: '82558a389a443c0ea4cc819899f2083a'
'85f0faa3e578f8077a2e3ff46729665b',
hashlib.sha384: '3e8a69b7783c25851933ab6290af6ca7'
'7a9981480850009cc5577c6e1f573b4e'
'6801dd23c4a7d679ccf8a386c674cffb',
hashlib.sha512: 'b0ba465637458c6990e5a8c5f61d4af7'
'e576d97ff94b872de76f8050361ee3db'
'a91ca5c11aa25eb4d679275cc5788063'
'a5f19741120c4f2de2adebeb10a298dd',
})
# 4.7. Test Case 6
hmactest(key = b'\xaa'*131,
data = b'Test Using Larger Than Block-Siz'
b'e Key - Hash Key First',
hexdigests = {
hashlib.sha224: '95e9a0db962095adaebe9b2d6f0dbce2'
'd499f112f2d2b7273fa6870e',
hashlib.sha256: '60e431591ee0b67f0d8a26aacbf5b77f'
'8e0bc6213728c5140546040f0ee37f54',
hashlib.sha384: '4ece084485813e9088d2c63a041bc5b4'
'4f9ef1012a2b588f3cd11f05033ac4c6'
'0c2ef6ab4030fe8296248df163f44952',
hashlib.sha512: '80b24263c7c1a3ebb71493c1dd7be8b4'
'9b46d1f41b4aeec1121b013783f8f352'
'6b56d037e05f2598bd0fd2215d6a1e52'
'95e64f73f63f0aec8b915a985d786598',
})
# 4.8. Test Case 7
hmactest(key = b'\xaa'*131,
data = b'This is a test using a larger th'
b'an block-size key and a larger t'
b'han block-size data. The key nee'
b'ds to be hashed before being use'
b'd by the HMAC algorithm.',
hexdigests = {
hashlib.sha224: '3a854166ac5d9f023f54d517d0b39dbd'
'946770db9c2b95c9f6f565d1',
hashlib.sha256: '9b09ffa71b942fcb27635fbcd5b0e944'
'bfdc63644f0713938a7f51535c3a35e2',
hashlib.sha384: '6617178e941f020d351e2f254e8fd32c'
'602420feb0b8fb9adccebb82461e99c5'
'a678cc31e799176d3860e6110c46523e',
hashlib.sha512: 'e37b6a775dc87dbaa4dfa9f96e5e3ffd'
'debd71f8867289865df5a32d20cdc944'
'b6022cac3c4982b10d5eeb55c3e4de15'
'134676fb6de0446065c97440fa8c6a58',
})
def test_sha224_rfc4231(self):
self._rfc4231_test_cases(hashlib.sha224)
def test_sha256_rfc4231(self):
self._rfc4231_test_cases(hashlib.sha256)
def test_sha384_rfc4231(self):
self._rfc4231_test_cases(hashlib.sha384)
def test_sha512_rfc4231(self):
self._rfc4231_test_cases(hashlib.sha512)
def test_legacy_block_size_warnings(self):
class MockCrazyHash(object):
"""Ain't no block_size attribute here."""
def __init__(self, *args):
self._x = hashlib.sha1(*args)
self.digest_size = self._x.digest_size
def update(self, v):
self._x.update(v)
def digest(self):
return self._x.digest()
warnings.simplefilter('error', RuntimeWarning)
try:
try:
hmac.HMAC(b'a', b'b', digestmod=MockCrazyHash)
except RuntimeWarning:
pass
else:
self.fail('Expected warning about missing block_size')
MockCrazyHash.block_size = 1
try:
hmac.HMAC(b'a', b'b', digestmod=MockCrazyHash)
except RuntimeWarning:
pass
else:
self.fail('Expected warning about small block_size')
finally:
warnings.resetwarnings()
class ConstructorTestCase(unittest.TestCase): class ConstructorTestCase(unittest.TestCase):
@ -95,9 +251,8 @@ def test_withtext(self):
def test_withmodule(self): def test_withmodule(self):
# Constructor call with text and digest module. # Constructor call with text and digest module.
from hashlib import sha1
try: try:
h = hmac.HMAC(b"key", b"", sha1) h = hmac.HMAC(b"key", b"", hashlib.sha1)
except: except:
self.fail("Constructor call with hashlib.sha1 raised exception.") self.fail("Constructor call with hashlib.sha1 raised exception.")
@ -106,7 +261,6 @@ class SanityTestCase(unittest.TestCase):
def test_default_is_md5(self): def test_default_is_md5(self):
# Testing if HMAC defaults to MD5 algorithm. # Testing if HMAC defaults to MD5 algorithm.
# NOTE: this whitebox test depends on the hmac class internals # NOTE: this whitebox test depends on the hmac class internals
import hashlib
h = hmac.HMAC(b"key") h = hmac.HMAC(b"key")
self.assertEqual(h.digest_cons, hashlib.md5) self.assertEqual(h.digest_cons, hashlib.md5)