def test_challenge2(self): hex_input1 = '1c0111001f010100061a024b53535009181c' hex_input2 = '686974207468652062756c6c277320657965' xor_result = xor(hex_to_bytes(hex_input1), hex_to_bytes(hex_input2)) self.assertEquals( '746865206b696420646f6e277420706c6179', bytes_to_hex(xor_result) )
def test_challenge5(self): source_text = 'Burning \'em, if you ain\'t quick and nimble\nI go crazy when I hear a cymbal' key = 'ICE' cipher = repeating_key_xor(source_text, key) encoded = bytes_to_hex(cipher) self.assertEquals( '0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f', encoded )
def hmac_test(path, hmac_bytes): hmac_hex = convert.bytes_to_hex(hmac_bytes) start = time.time() response = requests.get('http://localhost:8080/test', params={ 'file': path, 'signature': hmac_hex }) elapsed_seconds = time.time() - start return response, elapsed_seconds
def test_challenge31(self): # This test relies on having the web server running on port 8080: # python leak.py # HMAC-sha1 produces a 160 bit (20 byte) hash expected_hmac_length = 20 path = utils.abs_path('10.txt') signature = '\x00' * expected_hmac_length for i in range(expected_hmac_length): print '{}: {}'.format(i, convert.bytes_to_hex(signature)) outlier_score = 0.0 while outlier_score < 2.0: all_candidates = (chr(v) for v in range(256)) timings = generate_timings(path, signature, i, all_candidates) print 'timings: {}'.format([(convert.bytes_to_hex(t), v) for t, v in timings[:5]]) # The byte that produces the slowest response from the server # is likely the correct one. All of the incorrect bytes should # have the same response time (N). The correct byte should be # a little bit slower (N + x). # # However, there is some variance in the server response times # so check again if the calculated value of x is not # significantly larger than the next difference between two # incorrect bytes. If so, try again. most_likely, elapsed_time = timings[0] _, second_slowest_elapsed_time = timings[1] _, third_slowest_elapsed_time = timings[2] outlier_score = ( (elapsed_time - second_slowest_elapsed_time) / (second_slowest_elapsed_time - third_slowest_elapsed_time)) print 'outlier_score: {}'.format(outlier_score) signature = signature[:i] + most_likely + signature[i + 1:] response, _ = hmac_test(path, signature) self.assertEquals(200, response.status_code)
def test_challenge30(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.md4_keyed_mac(secret_key, message) raw = convert.hex_to_bytes(mac) state = [ bitops.from_bytes_le(raw[0:4]), bitops.from_bytes_le(raw[4:8]), bitops.from_bytes_le(raw[8:12]), bitops.from_bytes_le(raw[12:16]), ] for guessed_key_length in xrange(1, 100): orig_message_length = guessed_key_length + len(message) padding = crack.md4_padding(orig_message_length) # Attacker sets up a md4 hash that is in the same state after # hashing secret_key + message + padding hasher = md4.MD4() hasher.h = list(state) hasher.count = (orig_message_length + len(padding)) / 64 suffix = ';user=admin' falsified_mac = convert.bytes_to_hex(hasher.add(suffix).finish()) 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.md4_keyed_mac) break except ValueError: # Guessed key length was wrong. Keep going... pass self.assertEqual(len(secret_key), guessed_key_length)
def md4_keyed_mac(key, message): hasher = md4.MD4() hasher.add(key + message) return convert.bytes_to_hex(hasher.finish())