def _run_tests(self, hash_type, reference_method): for i in range(hash_type().block_size // 8): for _ in range(100): key = Bytes.random(i * 8) in_bytes = Bytes.random(i * 32) samson_hash = HMAC(key=key, hash_obj=hash_type()) self.assertEqual( samson_hash.generate(in_bytes), pyhmac.HMAC(key, in_bytes, reference_method).digest())
def __init__(self, key: bytes, hash_obj: object = SHA1(), digits: int = 6, counter: object = IncrementingCounter(0)): """ Parameters: key (bytes): Shared key. hash_obj (object): Instantiated hash object. digits (int): Number of digits to generate. counter (int): Initial counter. """ self.hmac = HMAC(key, hash_obj) self.digits = digits self.counter = counter
def encrypt_and_auth(self, key: bytes, iv: bytes, plaintext: bytes, auth_data: bytes) -> (Bytes, Bytes): mac_key, enc_key = key.chunk(self.chunk_size) rij = Rijndael(enc_key) cbc = CBC(rij, iv=iv) ciphertext = cbc.encrypt(plaintext) hmac = HMAC( mac_key, self.hash_obj).generate(auth_data + iv + ciphertext + Bytes(len(auth_data) * 8).zfill(8))[:self.chunk_size] return ciphertext, hmac
def derive(self, key: bytes, salt: bytes, info: bytes = b'') -> Bytes: """ Derives a key. Parameters: key (bytes): Bytes-like object to key the internal HMAC. salt (bytes): Salt to tweak the output. info (bytes): Additional data to use as tweak. Returns: Bytes: Derived key. """ prk = HMAC(key=salt, hash_obj=self.hash_obj).generate(key) hmac = HMAC(key=prk, hash_obj=self.hash_obj) new_key = b'' t = b'' for i in range( math.ceil(self.desired_len / (self.hash_obj.digest_size // 8))): t = hmac.generate(t + info + bytes([i + 1])) new_key += t return new_key[:self.desired_len]
def decrypt(self, key: bytes, iv: bytes, ciphertext: bytes, auth_data: bytes, auth_tag: bytes) -> Bytes: mac_key, enc_key = key.chunk(self.chunk_size) hmac = HMAC( mac_key, self.hash_obj).generate(auth_data + iv + ciphertext + Bytes(len(auth_data) * 8).zfill(8))[:self.chunk_size] assert RUNTIME.compare_bytes(hmac, auth_tag) rij = Rijndael(enc_key) cbc = CBC(rij, iv=iv) return cbc.decrypt(ciphertext)
def _run_tests(self, hash_type, reference_method): hash_fn = lambda password, salt: HMAC(password, hash_type()).generate( salt) for i in range(hash_type().block_size // 8): for _ in range(5): password = Bytes.random(i * 8).zfill((i + 1) * 8) salt = Bytes.random(i * 2) desired_len = max(1, Bytes.random(1).int()) num_iters = Bytes.random(1).int() % 256 + 1 pbkdf2 = PBKDF2(hash_fn=hash_fn, desired_len=desired_len, num_iters=num_iters) self.assertEqual( pbkdf2.derive(password, salt), hashlib.pbkdf2_hmac(reference_method, password, salt, num_iters, desired_len))
def oracle_func(h, r): h = h.cache_mul(h.curve.cardinality().bit_length()) K = bob_key.derive_key(h) hmac = HMAC(key=K, hash_obj=sha256) mac = hmac.generate(m) for i in range(r): eve_ecdhe.d = i eve_hmac = HMAC(key=eve_ecdhe.derive_key(h), hash_obj=sha256) if eve_hmac.generate(m) == mac: return i raise Exception(f'Residue not found for {r}!')
class HOTP(object): """ HMAC-based One-Time Password (https://tools.ietf.org/html/rfc4226) """ def __init__(self, key: bytes, hash_obj: object = SHA1(), digits: int = 6, counter: object = IncrementingCounter(0)): """ Parameters: key (bytes): Shared key. hash_obj (object): Instantiated hash object. digits (int): Number of digits to generate. counter (int): Initial counter. """ self.hmac = HMAC(key, hash_obj) self.digits = digits self.counter = counter def __repr__(self): return f"<HOTP: hmac={self.hmac}, digits={self.digits}, counter={self.counter}>" def __str__(self): return self.__repr__() def generate(self) -> str: """ Generates an OTP code as string of numbers (zero padded). Returns: str: OTP code. """ ctr_hash = self.hmac.generate( Bytes.wrap(self.counter.get_value()).zfill(8)) offset = ctr_hash[-1] & 0x0F code = ((ctr_hash[offset + 0] & 0x7F) << 24 | (ctr_hash[offset + 1] & 0xFF) << 16 | (ctr_hash[offset + 2] & 0xFF) << 8 | (ctr_hash[offset + 3] & 0xFF)) return str(code % (10**self.digits)).zfill(self.digits)
def __init__(self, desired_len: int, cost: int, parallelization_factor: int, block_size_factor: int = 8, hash_fn: FunctionType = lambda passwd, msg: HMAC( passwd, SHA256()).generate(msg)): """ Parameters: desired_len (int): Desired output length. cost (int): Cost (usually a power of two). block_size_factor (int): `r` from the RFC. hash_fn (func): Function that takes in bytes and returns them hashed. """ self.block_size = block_size_factor * 128 self.hash_fn = hash_fn self.pbkdf2 = PBKDF2(hash_fn, self.block_size * parallelization_factor, 1) self.desired_len = desired_len self.cost = cost self.block_size_factor = block_size_factor self.parallelization_factor = parallelization_factor
def sign(self, key: bytes, data: bytes) -> Bytes: return HMAC(hash_obj=self.hash_obj, key=key).generate(data)
def __init__(self, hash_obj: object): self.hash_obj = hash_obj self.hash_fn = lambda key, msg: HMAC(key, self.hash_obj).generate(msg) self._underlying_cipher = JWA_AKW()