Skip to content

Commit d82944f

Browse files
authored
Merge pull request #355 from tomato42/fips-hmac
make HMAC work in strict FIPS mode
2 parents a328159 + 4c2659f commit d82944f

File tree

3 files changed

+87
-6
lines changed

3 files changed

+87
-6
lines changed

tlslite/mathtls.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
from .utils.cryptomath import *
1313
from .constants import CipherSuite
1414
from .utils import tlshashlib as hashlib
15-
16-
import hmac
15+
from .utils import tlshmac as hmac
1716

1817
# 1024, 1536, 2048, 3072, 4096, 6144, and 8192 bit groups
1918
# Formatted to match lines in RFC
@@ -629,7 +628,9 @@ def makeK(N, g):
629628

630629
def createHMAC(k, digestmod=hashlib.sha1):
631630
h = hmac.HMAC(k, digestmod=digestmod)
632-
h.block_size = digestmod().block_size
631+
if not hasattr(h, 'block_size'):
632+
h.block_size = digestmod().block_size
633+
assert h.block_size == digestmod().block_size
633634
return h
634635

635636
def createMAC_SSL(k, digestmod=None):

tlslite/utils/cryptomath.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
from .compat import compat26Str, compatHMAC, compatLong, b2a_hex
1919
from .codec import Writer
2020

21+
from . import tlshashlib as hashlib
22+
from . import tlshmac as hmac
23+
2124

2225
# **************************************************************************
2326
# Load Optional Modules
@@ -73,9 +76,6 @@ def getRandomBytes(howMany):
7376
# Simple hash functions
7477
# **************************************************************************
7578

76-
import hmac
77-
from . import tlshashlib as hashlib
78-
7979
def MD5(b):
8080
"""Return a MD5 digest of data"""
8181
return secureHash(b, 'md5')

tlslite/utils/tlshmac.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Author: Hubert Kario (c) 2019
2+
# see LICENCE file for legal information regarding use of this file
3+
4+
"""
5+
HMAC module that works in FIPS mode.
6+
7+
Note that this makes this code FIPS non-compliant!
8+
"""
9+
10+
# Because we are extending the hashlib module, we need to import all its
11+
# fields to suppport the same uses
12+
from . import tlshashlib
13+
from .compat import compatHMAC
14+
try:
15+
from hmac import compare_digest
16+
__all__ = ["new", "compare_digest", "HMAC"]
17+
except ImportError:
18+
__all__ = ["new", "HMAC"]
19+
20+
21+
class HMAC(object):
22+
"""Hacked version of HMAC that works in FIPS mode even with MD5."""
23+
24+
def __init__(self, key, msg=None, digestmod=None):
25+
"""
26+
Initialise the HMAC and hash first portion of data.
27+
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:
55+
self._context.update(compatHMAC(msg))
56+
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()
66+
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
76+
77+
78+
def new(*args, **kwargs):
79+
"""General constructor that works in FIPS mode."""
80+
return HMAC(*args, **kwargs)

0 commit comments

Comments
 (0)