Source code for pycrypt.hash.sha.variants

from typing import override

from pycrypt.hash.sha.core import SHACore


[docs] class SHA1(SHACore): """SHA-1 cryptographic hash function. Implements the SHA-1 algorithm (160-bit digest) using the core SHA framework defined in :class:`SHACore`. Example: >>> sha = SHA1(b"hello world") >>> sha.hexdigest() '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed' >>> sha.update(b"!") >>> sha.hexdigest() '7c211433f02071597741e6ff5a8ea34789abbf43' """ BLOCK_SIZE: int = 64 #: Input block size in bytes. DIGEST_SIZE: int = 20 #: Output digest size in bytes. WORD_SIZE: int = 32 #: Word size in bits. _MASK: int = (1 << WORD_SIZE) - 1 #: Bitmask for 32-bit operations. # --- PRIVATE: Hashing Logic --- @override def _process_block(self, block: bytes): W = self._schedule_message(block) a, b, c, d, e = self._hash for t in range(80): if t <= 19: f = (b & c) | ((~b & self._MASK) & d) k = 0x5A827999 elif t <= 39: f = b ^ c ^ d k = 0x6ED9EBA1 elif t <= 59: f = (b & c) | (b & d) | (c & d) k = 0x8F1BBCDC else: f = b ^ c ^ d k = 0xCA62C1D6 temp = (self._rotr(a, -5) + f + e + k + W[t]) & self._MASK e = d d = c c = self._rotr(b, -30) b = a a = temp self._hash: list[int] = [ (x + y) & self._MASK for x, y in zip(self._hash, [a, b, c, d, e]) ] @override def _schedule_message(self, block: bytes) -> list[int]: W = [0] * 80 for i in range(16): W[i] = int.from_bytes(block[i * 4 : (i + 1) * 4], "big") for i in range(16, 80): W[i] = self._rotl(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1) return W # --- PRIVATE: Constants --- @override @classmethod def _init_hash(cls) -> list[int]: return [ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0, ] @override @classmethod def _get_constants(cls) -> list[int]: return [] # --- PRIVATE: Helper Bitwise Math Functions --- @classmethod def _rotr(cls, x: int, n: int, w: int = 32) -> int: n %= w return ((x >> n) | ((x << (w - n)) & cls._MASK)) & cls._MASK @classmethod def _rotl(cls, x: int, n: int, w: int = 32) -> int: n %= w return ((x << n) | (x >> (w - n))) & cls._MASK
[docs] class SHA256(SHACore): """SHA-256 cryptographic hash function. Implements the SHA-256 algorithm (256-bit digest) using the core SHA framework defined in :class:`SHACore`. Example: >>> sha = SHA256(b"hello world") >>> sha.hexdigest() 'b94d27b9934d3e08a52e52d7da7dabfade4b988' # truncated example >>> sha.update(b"!") >>> sha.hexdigest() '7f83b1657ff1fc53b92dc18148a1d65dfc2d4a' # truncated example """ BLOCK_SIZE: int = 64 #: Input block size in bytes. DIGEST_SIZE: int = 32 #: Output digest size in bytes. WORD_SIZE: int = 32 #: Word size in bits. _MASK: int = (1 << WORD_SIZE) - 1 #: Bitmask for 32-bit operations. # --- PRIVATE: Hashing Logic --- @override def _process_block(self, block: bytes): K = self._get_constants() W = self._schedule_message(block) a, b, c, d, e, f, g, h = self._hash for t in range(64): T1 = (h + self._Sigma_1(e) + self._ch(e, f, g) + K[t] + W[t]) & self._MASK T2 = (self._Sigma_0(a) + self._maj(a, b, c)) & self._MASK h, g, f, e, d, c, b, a = ( g, f, e, (d + T1) & self._MASK, c, b, a, (T1 + T2) & self._MASK, ) self._hash: list[int] = [ (x + y) & self._MASK for x, y in zip(self._hash, [a, b, c, d, e, f, g, h]) ] @override def _schedule_message(self, block: bytes) -> list[int]: W = [0] * 64 for i in range(64): if i < 16: W[i] = int.from_bytes(block[i * 4 : (i + 1) * 4], "big") else: W[i] = ( self._sigma_1(W[i - 2]) + W[i - 7] + self._sigma_0(W[i - 15]) + W[i - 16] ) & self._MASK return W # --- PRIVATE: Constants --- @override @classmethod def _init_hash(cls) -> list[int]: return [ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, ] @override @classmethod def _get_constants(cls) -> list[int]: # fmt: off return [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, ] # --- PRIVATE: Helper Bitwise Math Functions --- @classmethod def _rotr(cls, x: int, n: int, w: int = 32) -> int: n = n % w return (x >> n) | ((x << w - n) & cls._MASK) @classmethod def _shr(cls, x: int, n: int): return x >> n @classmethod def _ch(cls, x: int, y: int, z: int): # Ch(x, y, z) = (x AND y) XOR ((NOT x) AND z) return ((x & y) ^ ((~x & cls._MASK) & z)) & cls._MASK @classmethod def _maj(cls, x: int, y: int, z: int): # Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z) return ((x & y) ^ (x & z) ^ (y & z)) & cls._MASK @classmethod def _Sigma_0(cls, x: int): return (cls._rotr(x, 2) ^ cls._rotr(x, 13) ^ cls._rotr(x, 22)) & cls._MASK @classmethod def _Sigma_1(cls, x: int): return (cls._rotr(x, 6) ^ cls._rotr(x, 11) ^ cls._rotr(x, 25)) & cls._MASK @classmethod def _sigma_0(cls, x: int): return (cls._rotr(x, 7) ^ cls._rotr(x, 18) ^ cls._shr(x, 3)) & cls._MASK @classmethod def _sigma_1(cls, x: int): return (cls._rotr(x, 17) ^ cls._rotr(x, 19) ^ cls._shr(x, 10)) & cls._MASK