1# This file is dual licensed under the terms of the Apache License, Version 
    2# 2.0, and the BSD License. See the LICENSE file in the root of this repository 
    3# for complete details. 
    4 
    5from __future__ import annotations 
    6 
    7import abc 
    8 
    9from cryptography.hazmat.bindings._rust import openssl as rust_openssl 
    10from cryptography.utils import Buffer 
    11 
    12__all__ = [ 
    13    "MD5", 
    14    "SHA1", 
    15    "SHA3_224", 
    16    "SHA3_256", 
    17    "SHA3_384", 
    18    "SHA3_512", 
    19    "SHA224", 
    20    "SHA256", 
    21    "SHA384", 
    22    "SHA512", 
    23    "SHA512_224", 
    24    "SHA512_256", 
    25    "SHAKE128", 
    26    "SHAKE256", 
    27    "SM3", 
    28    "BLAKE2b", 
    29    "BLAKE2s", 
    30    "ExtendableOutputFunction", 
    31    "Hash", 
    32    "HashAlgorithm", 
    33    "HashContext", 
    34    "XOFHash", 
    35] 
    36 
    37 
    38class HashAlgorithm(metaclass=abc.ABCMeta): 
    39    @property 
    40    @abc.abstractmethod 
    41    def name(self) -> str: 
    42        """ 
    43        A string naming this algorithm (e.g. "sha256", "md5"). 
    44        """ 
    45 
    46    @property 
    47    @abc.abstractmethod 
    48    def digest_size(self) -> int: 
    49        """ 
    50        The size of the resulting digest in bytes. 
    51        """ 
    52 
    53    @property 
    54    @abc.abstractmethod 
    55    def block_size(self) -> int | None: 
    56        """ 
    57        The internal block size of the hash function, or None if the hash 
    58        function does not use blocks internally (e.g. SHA3). 
    59        """ 
    60 
    61 
    62class HashContext(metaclass=abc.ABCMeta): 
    63    @property 
    64    @abc.abstractmethod 
    65    def algorithm(self) -> HashAlgorithm: 
    66        """ 
    67        A HashAlgorithm that will be used by this context. 
    68        """ 
    69 
    70    @abc.abstractmethod 
    71    def update(self, data: Buffer) -> None: 
    72        """ 
    73        Processes the provided bytes through the hash. 
    74        """ 
    75 
    76    @abc.abstractmethod 
    77    def finalize(self) -> bytes: 
    78        """ 
    79        Finalizes the hash context and returns the hash digest as bytes. 
    80        """ 
    81 
    82    @abc.abstractmethod 
    83    def copy(self) -> HashContext: 
    84        """ 
    85        Return a HashContext that is a copy of the current context. 
    86        """ 
    87 
    88 
    89Hash = rust_openssl.hashes.Hash 
    90HashContext.register(Hash) 
    91 
    92XOFHash = rust_openssl.hashes.XOFHash 
    93 
    94 
    95class ExtendableOutputFunction(metaclass=abc.ABCMeta): 
    96    """ 
    97    An interface for extendable output functions. 
    98    """ 
    99 
    100 
    101class SHA1(HashAlgorithm): 
    102    name = "sha1" 
    103    digest_size = 20 
    104    block_size = 64 
    105 
    106 
    107class SHA512_224(HashAlgorithm):  # noqa: N801 
    108    name = "sha512-224" 
    109    digest_size = 28 
    110    block_size = 128 
    111 
    112 
    113class SHA512_256(HashAlgorithm):  # noqa: N801 
    114    name = "sha512-256" 
    115    digest_size = 32 
    116    block_size = 128 
    117 
    118 
    119class SHA224(HashAlgorithm): 
    120    name = "sha224" 
    121    digest_size = 28 
    122    block_size = 64 
    123 
    124 
    125class SHA256(HashAlgorithm): 
    126    name = "sha256" 
    127    digest_size = 32 
    128    block_size = 64 
    129 
    130 
    131class SHA384(HashAlgorithm): 
    132    name = "sha384" 
    133    digest_size = 48 
    134    block_size = 128 
    135 
    136 
    137class SHA512(HashAlgorithm): 
    138    name = "sha512" 
    139    digest_size = 64 
    140    block_size = 128 
    141 
    142 
    143class SHA3_224(HashAlgorithm):  # noqa: N801 
    144    name = "sha3-224" 
    145    digest_size = 28 
    146    block_size = None 
    147 
    148 
    149class SHA3_256(HashAlgorithm):  # noqa: N801 
    150    name = "sha3-256" 
    151    digest_size = 32 
    152    block_size = None 
    153 
    154 
    155class SHA3_384(HashAlgorithm):  # noqa: N801 
    156    name = "sha3-384" 
    157    digest_size = 48 
    158    block_size = None 
    159 
    160 
    161class SHA3_512(HashAlgorithm):  # noqa: N801 
    162    name = "sha3-512" 
    163    digest_size = 64 
    164    block_size = None 
    165 
    166 
    167class SHAKE128(HashAlgorithm, ExtendableOutputFunction): 
    168    name = "shake128" 
    169    block_size = None 
    170 
    171    def __init__(self, digest_size: int): 
    172        if not isinstance(digest_size, int): 
    173            raise TypeError("digest_size must be an integer") 
    174 
    175        if digest_size < 1: 
    176            raise ValueError("digest_size must be a positive integer") 
    177 
    178        self._digest_size = digest_size 
    179 
    180    @property 
    181    def digest_size(self) -> int: 
    182        return self._digest_size 
    183 
    184 
    185class SHAKE256(HashAlgorithm, ExtendableOutputFunction): 
    186    name = "shake256" 
    187    block_size = None 
    188 
    189    def __init__(self, digest_size: int): 
    190        if not isinstance(digest_size, int): 
    191            raise TypeError("digest_size must be an integer") 
    192 
    193        if digest_size < 1: 
    194            raise ValueError("digest_size must be a positive integer") 
    195 
    196        self._digest_size = digest_size 
    197 
    198    @property 
    199    def digest_size(self) -> int: 
    200        return self._digest_size 
    201 
    202 
    203class MD5(HashAlgorithm): 
    204    name = "md5" 
    205    digest_size = 16 
    206    block_size = 64 
    207 
    208 
    209class BLAKE2b(HashAlgorithm): 
    210    name = "blake2b" 
    211    _max_digest_size = 64 
    212    _min_digest_size = 1 
    213    block_size = 128 
    214 
    215    def __init__(self, digest_size: int): 
    216        if digest_size != 64: 
    217            raise ValueError("Digest size must be 64") 
    218 
    219        self._digest_size = digest_size 
    220 
    221    @property 
    222    def digest_size(self) -> int: 
    223        return self._digest_size 
    224 
    225 
    226class BLAKE2s(HashAlgorithm): 
    227    name = "blake2s" 
    228    block_size = 64 
    229    _max_digest_size = 32 
    230    _min_digest_size = 1 
    231 
    232    def __init__(self, digest_size: int): 
    233        if digest_size != 32: 
    234            raise ValueError("Digest size must be 32") 
    235 
    236        self._digest_size = digest_size 
    237 
    238    @property 
    239    def digest_size(self) -> int: 
    240        return self._digest_size 
    241 
    242 
    243class SM3(HashAlgorithm): 
    244    name = "sm3" 
    245    digest_size = 32 
    246    block_size = 64