1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
5# 2015, 2016 Maxence Tury
6
7"""
8HMAC classes.
9"""
10
11from scapy.config import conf
12from scapy.layers.tls.crypto.hash import _tls_hash_algs
13
14if conf.crypto_valid:
15 from cryptography.hazmat.backends import default_backend
16 from cryptography.hazmat.primitives.hmac import HMAC
17
18_SSLv3_PAD1_MD5 = b"\x36" * 48
19_SSLv3_PAD1_SHA1 = b"\x36" * 40
20_SSLv3_PAD2_MD5 = b"\x5c" * 48
21_SSLv3_PAD2_SHA1 = b"\x5c" * 40
22
23_tls_hmac_algs = {}
24
25
26class _GenericHMACMetaclass(type):
27 """
28 HMAC classes are automatically registered through this metaclass.
29 Furthermore, their name attribute is extracted from their class name.
30
31 Note that, when used with TLS, the HMAC key length equates the output of
32 the associated hash function (see RFC 5246, appendix C).
33 Also, we do not need to instantiate the associated hash function.
34 """
35
36 def __new__(cls, hmac_name, bases, dct):
37 hash_name = hmac_name[5:] # remove leading "Hmac_"
38 if hmac_name != "_GenericHMAC":
39 hash_alg = _tls_hash_algs[hash_name.lower()]
40 dct["name"] = "HMAC-%s" % hash_name
41 dct["hash_alg"] = hash_alg
42 dct["hmac_len"] = hash_alg.hash_len
43 dct["key_len"] = dct["hmac_len"]
44 the_class = super(_GenericHMACMetaclass, cls).__new__(
45 cls, hmac_name, bases, dct
46 )
47 if hmac_name != "_GenericHMAC":
48 _tls_hmac_algs[dct["name"]] = the_class
49 return the_class
50
51
52class HMACError(Exception):
53 """
54 Raised when HMAC verification fails.
55 """
56
57 pass
58
59
60class _GenericHMAC(metaclass=_GenericHMACMetaclass):
61 def __init__(self, key=None):
62 self.key = key or b""
63
64 def digest(self, tbd):
65 if self.key is None:
66 raise HMACError
67 hm = HMAC(self.key, self.hash_alg.hash_cls(), backend=default_backend())
68 hm.update(tbd)
69 return hm.finalize()
70
71 def digest_sslv3(self, tbd):
72 if self.key is None:
73 raise HMACError
74
75 h = self.hash_alg()
76 if h.name == "sha":
77 pad1 = _SSLv3_PAD1_SHA1
78 pad2 = _SSLv3_PAD2_SHA1
79 elif h.name == "md5":
80 pad1 = _SSLv3_PAD1_MD5
81 pad2 = _SSLv3_PAD2_MD5
82 else:
83 raise HMACError("Provided hash does not work with SSLv3.")
84
85 return h.digest(self.key + pad2 + h.digest(self.key + pad1 + tbd))
86
87
88class Hmac_NULL(_GenericHMAC):
89 hmac_len = 0
90 key_len = 0
91
92 def digest(self, tbd):
93 return b""
94
95 def digest_sslv3(self, tbd):
96 return b""
97
98
99class Hmac_MD4(_GenericHMAC):
100 pass
101
102
103class Hmac_MD5(_GenericHMAC):
104 pass
105
106
107class Hmac_SHA(_GenericHMAC):
108 pass
109
110
111class Hmac_SHA224(_GenericHMAC):
112 pass
113
114
115class Hmac_SHA256(_GenericHMAC):
116 pass
117
118
119class Hmac_SHA384(_GenericHMAC):
120 pass
121
122
123class Hmac_SHA512(_GenericHMAC):
124 pass
125
126
127def Hmac(key, hashtype):
128 """
129 Return Hmac object from Hash object and key
130 """
131 return _tls_hmac_algs[f"HMAC-{hashtype.name.upper()}"](key=key)