def hmac(key, message): padding_length = sha1.Sha1Hash.block_size - len(key) if padding_length > 0: key += '\x00' * padding_length else: key = sha1.Sha1Hash().update(key).digest() full_message = ( xor(key, '\x5c' * len(key)) + sha1.Sha1Hash().update(xor(key, '\x36' * len(key))).digest() + message) return sha1.Sha1Hash().update(full_message).digest()
def calculate_hmac(file_name, key): if len(key) > block_size: key = sha1.Sha1Hash().update(key).digest() elif len(key) < block_size: key += '\x00' * (block_size - len(key)) key = bytearray(key) o_key_pad = bytearray(len(key)) i_key_pad = bytearray(len(key)) for i in key: o_key_pad += bytearray([i ^ 0x5c]) i_key_pad += bytearray([i ^ 0x36]) i_key_hash = sha1.Sha1Hash().update(i_key_pad + file_name).digest() return sha1.Sha1Hash().update(o_key_pad + i_key_hash).digest()
def extend_sha1(old_digest, old_byte_length, extension): registers = tuple(int(old_digest[i:i + 8], 16) for i in xrange(0, len(old_digest), 8)) padding = compute_sha1_padding(old_byte_length) hasher = sha1.Sha1Hash() hasher._h = registers hasher._message_byte_length = old_byte_length + len(padding) hasher.update(extension) return (padding + extension, hasher.hexdigest())
def sha1_length_attack(message, mac, extension): registers = list(get_registers(mac)) for i in xrange(0, 40): padded_text = sha1_pad(("A" * i) + message) forged_mac = sha1.Sha1Hash(h=registers, message_byte_length=len(padded_text)).update(extension).hexdigest() extended_message = padded_text[i:] + extension if validate_mac(extended_message, key, forged_mac) is True: return i, forged_mac return -1, ""
def main(): sha1.Sha1Hash().update(b"a" * (64 * 2 - 1)).hexdigest() key = b"abc123" msg = b"green cup soup chef" correct = keyed_mac(key, msg) assert correct == "4860e61b1152e72910ab41f776df5c38940931a7" assert keyed_mac(b"abc124", msg) != correct assert keyed_mac(key, b"green cup soup chefs") != correct
def keyed_mac(key: bytes, msg: bytes) -> str: h0 = sha1.Sha1Hash() h0.update(key + msg) h1 = hashlib.sha1() h1.update(key + msg) d0 = h0.hexdigest() d1 = h1.hexdigest() assert d0 == d1 return d0
def length_extension_attack(original_message: bytes, existing_hash: str, guessed_length: int): extra = b";admin=true" glue_padding = compute_glue_padding(original_message, guessed_length) new_msg = original_message + glue_padding + extra prefix_length = guessed_length + len(original_message) + len(glue_padding) assert prefix_length % 64 == 0 registers = to_registers(existing_hash) h = sha1.Sha1Hash(initial=registers) h._message_byte_length = prefix_length forged = h.update(extra).hexdigest() return forged, new_msg
def make_sha1_clone(hex_digest, known_suffix, est_len=None): ''' Given hex_digest and estimated length, clone SHAv1 hash. Important to note that state is only updated with each round of full 64 bytes of message. ''' # Instantiate clone clone = sha1.Sha1Hash() # State is output of digest. clone._h = tuple([int(hex_digest[i:i+8], 16) for i in range(0, len(hex_digest), 8)]) # Set estimated length of message; I figure most secret prefixes are 128 # bit or less; there is some potential for edgecase problems here. That # can be controlled by manually setting len_state +/- 64 bytes. if not est_len: likely_len_state = (len(known_suffix) + 16) // 64 likely_len_state = (likely_len_state * 64) + 64 clone._message_byte_length = likely_len_state return clone
def test_challenge29(self): secret_key = os.urandom(random.randint(1, 20)) # Server returns the message and mac to the attacker message = 'comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20pound%20of%20bacon' mac = crypto.sha1_keyed_mac(secret_key, message) raw = convert.hex_to_bytes(mac) state = ( bitops.from_bytes_be(raw[0:4]), bitops.from_bytes_be(raw[4:8]), bitops.from_bytes_be(raw[8:12]), bitops.from_bytes_be(raw[12:16]), bitops.from_bytes_be(raw[16:20]), ) for guessed_key_length in xrange(1, 100): orig_message_length = guessed_key_length + len(message) padding = crack.sha1_padding(orig_message_length) # Attacker sets up a sha1 hash that is in the same state after # hashing secret_key + message + padding hasher = sha1.Sha1Hash() hasher._h = state hasher._message_byte_length = orig_message_length + len(padding) suffix = ';user=admin' falsified_mac = hasher.update(suffix).hexdigest() falsified_data = message + padding + suffix try: # Check to see if the server accepts the falsified data and MAC validate_mac(secret_key, falsified_data, falsified_mac, crypto.sha1_keyed_mac) break except ValueError: # Guessed key length was wrong. Keep going... pass self.assertEqual(len(secret_key), guessed_key_length)
def test_associativity(self): """ Test SHA-1 associativity Tests the fact that sha1(ab) is equivalent to sha1(a) updated with b. """ print('\n>>> running: test_associativity') msg1 = bytearray(get_random_bytes()) msg2 = bytearray(get_random_bytes()) first_digest = sha1.sha1(bytes(msg1) + bytes(msg2)) sha = sha1.Sha1Hash() sha.update(msg1) sha.update(msg2) second_digest = sha.hexdigest() print('... test_associativity: checking for identical digests') self.assertEqual(first_digest, second_digest) print('... test_associativity: success')
def validate_mac(message, key, mac): output_mac = sha1.Sha1Hash().update(key + message).hexdigest() if output_mac == mac: return True else: return False
# Pad the string until it is a multiple of 64 bytes with 2 words open padding += '\x00' * ((56 - (len(message) + 1) % 64) % 64) # Append the length of the bitstring in number of bits, big endian style padding += struct.pack(">Q", (len(message) * 8)) return message + padding def get_registers(mac): return struct.unpack(">IIIII", mac) def sha1_length_attack(message, mac, extension): registers = list(get_registers(mac)) for i in xrange(0, 40): padded_text = sha1_pad(("A" * i) + message) forged_mac = sha1.Sha1Hash(h=registers, message_byte_length=len(padded_text)).update(extension).hexdigest() extended_message = padded_text[i:] + extension if validate_mac(extended_message, key, forged_mac) is True: return i, forged_mac return -1, "" if __name__ == "__main__": message = "comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20pound%20of%20bacon" mac = sha1.Sha1Hash().update(key + message).digest() key_len, forged_mac = sha1_length_attack(message, mac, ";admin=true") print("The key length is {} with a forged MAC of {}".format(key_len, forged_mac))
def authenticate(key, msg): return sha1.Sha1Hash().update(key + msg).digest()
import hashlib import sha1 from util import keygen def authenticate(key, msg): return sha1.Sha1Hash().update(key + msg).digest() if __name__ == '__main__': sha = sha1.Sha1Hash().update('hello') print 'my implementation', sha.hexdigest() print 'expected', hashlib.sha1('hello').hexdigest() key = keygen() print authenticate(key, 'oh my gourd')
def auth(mac, message): if sha1.Sha1Hash().update(pkcs7(secret+message)).hexdigest() == mac: return True return False
def hash(ct, key): h = sha1.Sha1Hash() h.update(key+ct) return h.digest()