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)