Skip to content

Commit 693bc32

Browse files
committed
use built-in HMAC, if it allows MD5
1 parent c52b72b commit 693bc32

File tree

1 file changed

+61
-53
lines changed

1 file changed

+61
-53
lines changed

tlslite/utils/tlshmac.py

Lines changed: 61 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,64 +17,72 @@
1717
except ImportError:
1818
__all__ = ["new", "HMAC"]
1919

20+
try:
21+
from hmac import HMAC, new
22+
# if we can calculate HMAC on MD5, then use the built-in HMAC
23+
# implementation
24+
_val = HMAC(b'some key', b'msg', 'md5')
25+
_val.digest()
26+
del _val
27+
except Exception:
28+
# fallback only when MD5 doesn't work
29+
class HMAC(object):
30+
"""Hacked version of HMAC that works in FIPS mode even with MD5."""
2031

21-
class HMAC(object):
22-
"""Hacked version of HMAC that works in FIPS mode even with MD5."""
32+
def __init__(self, key, msg=None, digestmod=None):
33+
"""
34+
Initialise the HMAC and hash first portion of data.
2335
24-
def __init__(self, key, msg=None, digestmod=None):
25-
"""
26-
Initialise the HMAC and hash first portion of data.
36+
msg: data to hash
37+
digestmod: name of hash or object that be used as a hash and be cloned
38+
"""
39+
self.key = key
40+
if digestmod is None:
41+
digestmod = 'md5'
42+
if callable(digestmod):
43+
digestmod = digestmod()
44+
if not hasattr(digestmod, 'digest_size'):
45+
digestmod = tlshashlib.new(digestmod)
46+
self.block_size = digestmod.block_size
47+
self.digest_size = digestmod.digest_size
48+
self.digestmod = digestmod
49+
if len(key) > self.block_size:
50+
k_hash = digestmod.copy()
51+
k_hash.update(compatHMAC(key))
52+
key = k_hash.digest()
53+
if len(key) < self.block_size:
54+
key = key + b'\x00' * (self.block_size - len(key))
55+
key = bytearray(key)
56+
ipad = bytearray(b'\x36' * self.block_size)
57+
opad = bytearray(b'\x5c' * self.block_size)
58+
i_key = bytearray(i ^ j for i, j in zip(key, ipad))
59+
self._o_key = bytearray(i ^ j for i, j in zip(key, opad))
60+
self._context = digestmod.copy()
61+
self._context.update(compatHMAC(i_key))
62+
if msg:
63+
self._context.update(compatHMAC(msg))
2764

28-
msg: data to hash
29-
digestmod: name of hash or object that be used as a hash and be cloned
30-
"""
31-
self.key = key
32-
if digestmod is None:
33-
digestmod = 'md5'
34-
if callable(digestmod):
35-
digestmod = digestmod()
36-
if not hasattr(digestmod, 'digest_size'):
37-
digestmod = tlshashlib.new(digestmod)
38-
self.block_size = digestmod.block_size
39-
self.digest_size = digestmod.digest_size
40-
self.digestmod = digestmod
41-
if len(key) > self.block_size:
42-
k_hash = digestmod.copy()
43-
k_hash.update(compatHMAC(key))
44-
key = k_hash.digest()
45-
if len(key) < self.block_size:
46-
key = key + b'\x00' * (self.block_size - len(key))
47-
key = bytearray(key)
48-
ipad = bytearray(b'\x36' * self.block_size)
49-
opad = bytearray(b'\x5c' * self.block_size)
50-
i_key = bytearray(i ^ j for i, j in zip(key, ipad))
51-
self._o_key = bytearray(i ^ j for i, j in zip(key, opad))
52-
self._context = digestmod.copy()
53-
self._context.update(compatHMAC(i_key))
54-
if msg:
65+
def update(self, msg):
5566
self._context.update(compatHMAC(msg))
5667

57-
def update(self, msg):
58-
self._context.update(compatHMAC(msg))
59-
60-
def digest(self):
61-
i_digest = self._context.digest()
62-
o_hash = self.digestmod.copy()
63-
o_hash.update(compatHMAC(self._o_key))
64-
o_hash.update(compatHMAC(i_digest))
65-
return o_hash.digest()
68+
def digest(self):
69+
i_digest = self._context.digest()
70+
o_hash = self.digestmod.copy()
71+
o_hash.update(compatHMAC(self._o_key))
72+
o_hash.update(compatHMAC(i_digest))
73+
return o_hash.digest()
6674

67-
def copy(self):
68-
new = HMAC.__new__(HMAC)
69-
new.key = self.key
70-
new.digestmod = self.digestmod
71-
new.block_size = self.block_size
72-
new.digest_size = self.digest_size
73-
new._o_key = self._o_key
74-
new._context = self._context.copy()
75-
return new
75+
def copy(self):
76+
new = HMAC.__new__(HMAC)
77+
new.key = self.key
78+
new.digestmod = self.digestmod
79+
new.block_size = self.block_size
80+
new.digest_size = self.digest_size
81+
new._o_key = self._o_key
82+
new._context = self._context.copy()
83+
return new
7684

7785

78-
def new(*args, **kwargs):
79-
"""General constructor that works in FIPS mode."""
80-
return HMAC(*args, **kwargs)
86+
def new(*args, **kwargs):
87+
"""General constructor that works in FIPS mode."""
88+
return HMAC(*args, **kwargs)

0 commit comments

Comments
 (0)