• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
11import hmac
12
13from scapy.layers.tls.crypto.hash import _tls_hash_algs
14from scapy.compat import bytes_encode
15
16_SSLv3_PAD1_MD5 = b"\x36" * 48
17_SSLv3_PAD1_SHA1 = b"\x36" * 40
18_SSLv3_PAD2_MD5 = b"\x5c" * 48
19_SSLv3_PAD2_SHA1 = b"\x5c" * 40
20
21_tls_hmac_algs = {}
22
23
24class _GenericHMACMetaclass(type):
25    """
26    HMAC classes are automatically registered through this metaclass.
27    Furthermore, their name attribute is extracted from their class name.
28
29    Note that, when used with TLS, the HMAC key length equates the output of
30    the associated hash function (see RFC 5246, appendix C).
31    Also, we do not need to instantiate the associated hash function.
32    """
33    def __new__(cls, hmac_name, bases, dct):
34        hash_name = hmac_name[5:]               # remove leading "Hmac_"
35        if hmac_name != "_GenericHMAC":
36            dct["name"] = "HMAC-%s" % hash_name
37            dct["hash_alg"] = _tls_hash_algs[hash_name]
38            dct["hmac_len"] = _tls_hash_algs[hash_name].hash_len
39            dct["key_len"] = dct["hmac_len"]
40        the_class = super(_GenericHMACMetaclass, cls).__new__(cls, hmac_name,
41                                                              bases, dct)
42        if hmac_name != "_GenericHMAC":
43            _tls_hmac_algs[dct["name"]] = the_class
44        return the_class
45
46
47class HMACError(Exception):
48    """
49    Raised when HMAC verification fails.
50    """
51    pass
52
53
54class _GenericHMAC(metaclass=_GenericHMACMetaclass):
55    def __init__(self, key=None):
56        if key is None:
57            self.key = b""
58        else:
59            self.key = bytes_encode(key)
60
61    def digest(self, tbd):
62        if self.key is None:
63            raise HMACError
64        tbd = bytes_encode(tbd)
65        return hmac.new(self.key, tbd, self.hash_alg.hash_cls).digest()
66
67    def digest_sslv3(self, tbd):
68        if self.key is None:
69            raise HMACError
70
71        h = self.hash_alg()
72        if h.name == "SHA":
73            pad1 = _SSLv3_PAD1_SHA1
74            pad2 = _SSLv3_PAD2_SHA1
75        elif h.name == "MD5":
76            pad1 = _SSLv3_PAD1_MD5
77            pad2 = _SSLv3_PAD2_MD5
78        else:
79            raise HMACError("Provided hash does not work with SSLv3.")
80
81        return h.digest(self.key + pad2 +
82                        h.digest(self.key + pad1 + tbd))
83
84
85class Hmac_NULL(_GenericHMAC):
86    hmac_len = 0
87    key_len = 0
88
89    def digest(self, tbd):
90        return b""
91
92    def digest_sslv3(self, tbd):
93        return b""
94
95
96class Hmac_MD4(_GenericHMAC):
97    pass
98
99
100class Hmac_MD5(_GenericHMAC):
101    pass
102
103
104class Hmac_SHA(_GenericHMAC):
105    pass
106
107
108class Hmac_SHA224(_GenericHMAC):
109    pass
110
111
112class Hmac_SHA256(_GenericHMAC):
113    pass
114
115
116class Hmac_SHA384(_GenericHMAC):
117    pass
118
119
120class Hmac_SHA512(_GenericHMAC):
121    pass
122
123
124def Hmac(key, hashtype):
125    """
126    Return Hmac object from Hash object and key
127    """
128    return _tls_hmac_algs[f"HMAC-{hashtype.name}"](key=key)
129