A Python port of the Invisible Internet Project (I2P)
at main 66 lines 2.2 kB view raw
1"""HMAC generators — HMAC-SHA256 computation. 2 3Ported from net.i2p.crypto.HMACGenerator and HMAC256Generator. 4Wraps Python's hmac module. 5""" 6 7import hmac as _hmac 8import hashlib 9 10from i2p_crypto.hash_data import Hash 11 12 13class HMACGenerator: 14 """Abstract base for HMAC computation.""" 15 16 def calculate(self, key: bytes, data: bytes, offset: int, length: int, 17 target: bytearray, target_offset: int) -> None: 18 raise NotImplementedError 19 20 def verify(self, key: bytes, data: bytes, offset: int, length: int, 21 orig_mac: bytes, orig_mac_offset: int, orig_mac_length: int) -> bool: 22 raise NotImplementedError 23 24 25class HMAC256Generator(HMACGenerator): 26 """HMAC-SHA256 generator. Thread-safe. 27 28 Ported from net.i2p.crypto.HMAC256Generator. 29 """ 30 31 _instance: "HMAC256Generator | None" = None 32 33 def __init__(self) -> None: 34 super().__init__() 35 36 @classmethod 37 def get_instance(cls) -> "HMAC256Generator": 38 if cls._instance is None: 39 cls._instance = HMAC256Generator() 40 return cls._instance 41 42 def calculate(self, key: bytes, data: bytes, offset: int = 0, length: int = -1, # type: ignore[override] 43 target: bytearray | None = None, target_offset: int = 0) -> bytes: 44 """Calculate HMAC-SHA256. 45 46 If target is provided, writes 32 bytes into target at target_offset. 47 Always returns the 32-byte MAC. 48 """ 49 if length < 0: 50 length = len(data) - offset 51 # Use first 32 bytes of key 52 k = key[:32] 53 mac = _hmac.new(k, data[offset : offset + length], hashlib.sha256).digest() 54 if target is not None: 55 target[target_offset : target_offset + 32] = mac 56 return mac 57 58 def verify(self, key: bytes, data: bytes, offset: int, length: int, 59 orig_mac: bytes, orig_mac_offset: int = 0, 60 orig_mac_length: int = 32) -> bool: 61 """Verify HMAC-SHA256 in constant time.""" 62 calc = self.calculate(key, data, offset, length) 63 return _hmac.compare_digest( 64 calc[:orig_mac_length], 65 orig_mac[orig_mac_offset : orig_mac_offset + orig_mac_length], 66 )