Source code for pycrypt.hash.sha.hmac

from pycrypt.hash.sha.variants import SHA256
from pycrypt.utils import xor_bytes


[docs] def hmac(key: bytes, message: bytes, hash=SHA256) -> bytes: """Compute HMAC (Hash-based Message Authentication Code) for a message. HMAC combines a secret key with a cryptographic hash function to produce a message authentication code, which can be used for integrity and authenticity checks. Example: >>> key = b"secret" >>> msg = b"hello world" >>> hmac(key, msg).hex() '...' # 64-character hex for SHA-256 Args: key (bytes): Secret key. message (bytes): Input message to authenticate. hash (class, optional): Hash function class (default is SHA256). Returns: bytes: The HMAC digest. """ B = hash.BLOCK_SIZE ipad = b"\x36" * B opad = b"\x5c" * B if len(key) > B: key = hash(key).digest() else: key = key + b"\x00" * (B - len(key)) return hash( xor_bytes(key, opad) + hash(xor_bytes(key, ipad) + message).digest() ).digest()
[docs] def hkdf( ikm: bytes, length: int, salt: bytes = b"", info: bytes = b"", hash=SHA256 ) -> bytes: """Derive cryptographic keys using HKDF (HMAC-based Key Derivation Function). HKDF extracts a pseudorandom key from input keying material and expands it to the desired output length using HMAC. Example: >>> ikm = b"input key material" >>> hkdf(ikm, 32).hex() '...' # 64-character hex for 32-byte derived key Args: ikm (bytes): Input keying material. length (int): Desired length of output keying material in bytes. salt (bytes, optional): Optional salt value (default is empty). info (bytes, optional): Context/application-specific info (default is empty). hash (class, optional): Hash function class (default is SHA256). Returns: bytes: Derived key of specified length. """ prk = _hkdf_extract(ikm, salt, hash) return _hkdf_expand(prk, info, length, hash)
def _hkdf_extract(ikm: bytes, salt: bytes = b"", hash=SHA256) -> bytes: hlen = hash.DIGEST_SIZE if not salt: salt = b"\x00" * hlen return hmac(salt, ikm) def _hkdf_expand(prk: bytes, info: bytes, length: int, hash=SHA256): hlen = hash.DIGEST_SIZE if length > 255 * hlen: raise ValueError(f"length of output keying material should be <={255 * hlen}") okm = b"" t = b"" counter = 1 while len(okm) < length: t = hmac(prk, t + info + bytes([counter])) okm += t counter += 1 return okm[:length]