def discover_secret_length(block_size, padding_length): if padding_length % block_size == 0: pad_for_padding = "" else: pad_for_padding = "X" * (block_size - padding_length % block_size) assert len(pad_for_padding) < block_size tried = "A" * block_size * 2 plaintext = string_to_bytearray(pad_for_padding + tried) ciphertext = encryption_oracle_ecb(plaintext) initial_length = len(ciphertext) # first two controlled blocks are identical padding_ciphertext_length = padding_length + len(pad_for_padding) controlled_ciphertext = ciphertext[padding_ciphertext_length:] assert controlled_ciphertext[0:block_size] == controlled_ciphertext[ block_size:block_size * 2] # detect when there is a change in ciphertext length length_detected = False while not length_detected: tried += "B" plaintext = string_to_bytearray(tried) ciphertext_length = len(encryption_oracle_ecb(plaintext)) if ciphertext_length > initial_length: length_detected = True payload_length_at_change = len(tried) new_length = ciphertext_length # padding used is block_size return new_length - payload_length_at_change - block_size - padding_length
def discover_block_size_in_bytes(): tried = "" plaintext = string_to_bytearray(tried) initial_length = len(encryption_oracle_ecb(plaintext)) # detect when there is a change in ciphertext length length_detected = False while not length_detected: tried += "A" plaintext = string_to_bytearray(tried) ciphertext_length = len(encryption_oracle_ecb(plaintext)) if ciphertext_length > initial_length: length_detected = True payload_length_at_change = len(tried) new_length = ciphertext_length # find the block size block_size_detected = False while not block_size_detected: tried += "A" plaintext = string_to_bytearray(tried) ciphertext_length = len(encryption_oracle_ecb(plaintext)) if ciphertext_length > new_length: block_size_detected = True return len(tried) - payload_length_at_change
def test_aes_ecb(): # sanity check for encryption/decryption test_key = string_to_bytearray("A"*16) test_text = string_to_bytearray("12345678"*2) enc = encrypt_aes_128_ecb(test_text, test_key) if decrypt_aes_128_ecb(enc, test_key) != test_text: raise Exception("aes ecb is not working properly !!!")
def main(): block = string_to_bytearray("YELLOW SUBMARINE") expected_pad_20 = string_to_bytearray("YELLOW SUBMARINE\x04\x04\x04\x04") padded = pkcs7_pad(block, 20) if padded == expected_pad_20: print("challenge 2.9 completed.") else: print("challenge 2.9 failed.")
def test_aes_cbc(): # sanity check for encryption/decryption test_key = string_to_bytearray("A" * 16) test_text = string_to_bytearray("12345678" * 4) test_iv = string_to_bytearray("B" * 16) encrypted = encrypt_aes_cbc(test_text, test_key, test_iv) decrypted = decrypt_aes_cbc(encrypted, test_key, test_iv) if decrypted != test_text: raise Exception("aes cbc is not working properly !!!")
def ctr_bitflip(): user_input = "AadminZtrueZ" desired = ";admin=true;" ciphertext = encrypt_params(user_input) ciphertext_user_input = ciphertext[32:32 + len(user_input)] delta = xor(string_to_bytearray(user_input), string_to_bytearray(desired)) new_ciphertext_flipped = xor(ciphertext_user_input, delta) new_ciphertext = ciphertext[:32] + new_ciphertext_flipped + ciphertext[ 32 + len(user_input):] return new_ciphertext
def encrypt_user_data_cbc(user_data): user_data = user_data.replace(";", "") user_data = user_data.replace("=", "") plaintext = "comment1=cooking%20MCs;userdata=" + user_data + ";comment2=%20like%20a%20pound%20of%20bacon" to_encrypt = pad_to_mod_16(string_to_bytearray(plaintext)) return encrypt_aes_cbc(to_encrypt, oracle_key, iv)
def break_mt19937_stream_cipher(ciphertext): for key_candidate in range(0, 2**16 - 1): message = cipher_decrypt(ciphertext, key_candidate) if message[len(message) - 14:] == string_to_bytearray("A" * 14): return key_candidate raise Exception('key not found')
def encrypt_params(user_input): user_input_stripped = user_input.replace(";", "").replace("=", "") prefix = "comment1=cooking%20MCs;userdata=" suffix = ";comment2=%20like%20a%20pound%20of%20bacon" message = string_to_bytearray(prefix + user_input_stripped + suffix) return encrypt_aes_ctr(message, KEY, NONCE)
def main(): message = string_to_bytearray( "comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20pound%20of%20bacon" ) append = string_to_bytearray(";admin=true") signature = sign(message) assert verify_signature(signature, message) forge_signature_candidates = forge_signature(message, signature, append) forged = [(f, m) for (f, m) in forge_signature_candidates if verify_signature_admin(f, m)] if len(forged) > 0: print("challenge 4.29 completed.") else: print("challenge 4.29 failed.")
def discover_padding_length(block_size): magic_blocks_number = 5 tried = "A" * block_size * magic_blocks_number plaintext = string_to_bytearray(tried) ciphertext = encryption_oracle_ecb(plaintext) r = _check_magic_blocks_number(magic_blocks_number, ciphertext, block_size) i = 0 while r is None: i += 1 plaintext = string_to_bytearray(i * "B" + tried) ciphertext = encryption_oracle_ecb(plaintext) r = _check_magic_blocks_number(magic_blocks_number, ciphertext, block_size) # we "padded" the padding padding_length = r * block_size - i return padding_length
def main(): test_aes_ecb() with open("7.txt", "r") as f: ciphertext_b64 = f.read().replace("\n", "") ciphertext_bt = base64_to_bytearray(ciphertext_b64) key = string_to_bytearray("YELLOW SUBMARINE") message = decrypt_aes_128_ecb(ciphertext_bt, key) assert b"I'm back and I'm ringin' the bell" in message print("challenge 1.7 completed.")
def main(): key = crypto_random_bytes(16) message = string_to_bytearray("Commitment") h1 = sha1_keyed_mac(key, message) h2 = sha1_keyed_mac(key, message + b"X") if h1 and h2 and h1 != h2: print("challenge 4.28 completed.") else: print("challenge 4.28 failed.")
def main(): test_aes_ctr() ciphertext_b64 = 'L77na/nrFsKvynd6HzOoG7GHTLXsTVu9qvY/2syLXzhPweyyMTJULu/6/kXX0KSvoOLSFQ==' ciphertext_bt = base64_to_bytearray(ciphertext_b64) key = string_to_bytearray("YELLOW SUBMARINE") nonce = bytearray([0] * 8) message = decrypt_aes_ctr(ciphertext_bt, key, nonce) #print message assert b"VIP Let's kick it" in message print("challenge 3.18 completed.")
def main(): test_aes_cbc() with open("10.txt", "r") as f: ciphertext_b64 = f.read().replace("\n", "") ciphertext_bt = base64_to_bytearray(ciphertext_b64) key = string_to_bytearray("YELLOW SUBMARINE") iv = bytearray([0] * 16) message = decrypt_aes_cbc(ciphertext_bt, key, iv) assert b"I'm back and I'm ringin' the bell" in message print("challenge 2.10 completed.")
def encrypt_user_data_cbc(user_data): user_data = user_data.replace(";", "") user_data = user_data.replace("=", "") prefix = "comment1=cooking%20MCs;userdata=" suffix = ";comment2=%20like%20a%20pound%20of%20bacon" plaintext = string_to_bytearray(prefix + user_data + suffix) to_encrypt = pad_to_mod_16(plaintext) ciphertext = encrypt_aes_cbc(to_encrypt, oracle_key, iv) return ciphertext
def discover_secret_length(block_size): tried = "A" * block_size * 2 plaintext = string_to_bytearray(tried) ciphertext = encryption_oracle_ecb(plaintext) initial_length = len(ciphertext) # first two blocks are identical assert ciphertext[0:block_size] == ciphertext[block_size:block_size * 2] # detect when there is a change in ciphertext length length_detected = False while not length_detected: tried += "B" plaintext = string_to_bytearray(tried) ciphertext_length = len(encryption_oracle_ecb(plaintext)) if ciphertext_length > initial_length: length_detected = True payload_length_at_change = len(tried) new_length = ciphertext_length # padding used is block_size return new_length - payload_length_at_change - block_size
def hmac(key, message): if (len(key) > BLOCKSIZE): key = bytearray(sha1(key).decode( 'hex')) # keys longer than BLOCKSIZE are shortened if (len(key) < BLOCKSIZE): # keys shorter than BLOCKSIZE are zero-padded (where + is concatenation) key = key + bytearray([0x00] * (BLOCKSIZE - len(key))) # Where * is repetition. o_key_pad = xor(bytearray([0x5c] * BLOCKSIZE), key) i_key_pad = xor(bytearray([0x36] * BLOCKSIZE), key) h1 = sha1(i_key_pad + string_to_bytearray(message)) return sha1(o_key_pad + hexstr2bytearray(h1))
def find_secret(block_size, secret_length): discovered_so_far = bytearray([]) for i in range(secret_length): blocks_to_craft = len(discovered_so_far) // block_size + 1 padding_str = "A" * (blocks_to_craft * block_size - 1 - len(discovered_so_far)) padding = string_to_bytearray(padding_str) assert (len(padding) + len(discovered_so_far) + 1) % block_size == 0 found = find_one_byte(padding, discovered_so_far) discovered_so_far.append(found) return discovered_so_far
def main(): s1 = string_to_bytearray("ICE ICE BABY\x04\x04\x04\x04") s2 = string_to_bytearray("ICE ICE BABY\x05\x05\x05\x05") s3 = string_to_bytearray("ICE ICE BABY\x01\x02\x03\x04") assert valid_pkcs7_padding(s1) == True assert valid_pkcs7_padding(s2) == False assert valid_pkcs7_padding(s3) == False unpad_pkcs7(s1) try: unpad_pkcs7(s2) raise Exception("challenge 2.15 failed.") except ValueError as e: pass try: unpad_pkcs7(s3) raise Exception("challenge 2.15 failed.") except ValueError as e: pass print("challenge 2.15 completed.")
def main(): true_modes = [] detected_modes = [] for trial in range(0, 100): crafted_plaintext = string_to_bytearray("A" * 64) ciphertext, true_mode = encryption_oracle_ecb_cbc(crafted_plaintext) detected_mode = detection_oracle(ciphertext) true_modes.append(true_mode) detected_modes.append(detected_mode) if detected_modes == true_modes: print("challenge 2.11 completed.") else: print("challenge 2.11 failed.")
def break_little_harder_way(): newtext = string_to_bytearray('FIXED VALUE') chunk_length = len(newtext) chunks = unequal_chunks(ciphertext, chunk_length) keystream = bytearray([]) for ix, chunk in enumerate(chunks): start = ix * chunk_length end = start + len(chunk) new_ciphertext = edit(start, newtext)[start:end] keystream_chunk = xor(new_ciphertext, newtext[:len(new_ciphertext)]) keystream.extend(keystream_chunk) return xor(ciphertext, keystream)
def find_secret(block_size, padding_length, secret_length): if padding_length % block_size == 0: pad_for_padding = "" else: pad_for_padding = "X" * (block_size - padding_length % block_size) assert len(pad_for_padding) < block_size discovered_so_far = bytearray([]) for i in range(secret_length): blocks_to_craft = len(discovered_so_far) // block_size + 1 controlled_str = pad_for_padding + "A" * ( blocks_to_craft * block_size - 1 - len(discovered_so_far)) controlled = string_to_bytearray(controlled_str) assert (padding_length + len(controlled) + len(discovered_so_far) + 1) % block_size == 0 uninteresting_junk_length = padding_length + len(pad_for_padding) found = find_one_byte(controlled, uninteresting_junk_length, len(pad_for_padding), discovered_so_far) discovered_so_far.append(found) return discovered_so_far
from utils import string_to_bytearray, xor, bytearray_to_hex_string text = "Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal" message = string_to_bytearray(text) key_string = "ICE" key = string_to_bytearray(key_string) expected = "0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272\ a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f" def encrypt_repeating_key(m, k): key_multiplier = len(m) // len(k) key_candidate = k * key_multiplier key_candidate += k[:len(m)-len(key_candidate)] xored = xor(m, key_candidate) return xored def main(): xored = encrypt_repeating_key(message, key) if bytearray_to_hex_string(xored) == expected: print("challenge 1.5 completed.") else: print("challenge 1.5 failed.") if __name__ == '__main__': main()
def encrypt_profile_for(email): profile = string_to_bytearray(profile_for(email)) to_encrypt = pad_to_mod_16(profile) return encrypt_aes_128_ecb(to_encrypt, oracle_key)
def detect_ecb_mode(block_size): crafted_payload = string_to_bytearray("A" * block_size * 3) ciphertext = encryption_oracle_ecb(crafted_payload) return detection_oracle(ciphertext)
import sys sys.path.insert(0, '../set_1_basics') sys.path.insert(0, '../set_2_block_crypto') sys.path.insert(0, '../set_3_block_stream_crypto') from utils import unequal_chunks, xor, string_to_bytearray from aes_ctr_mode import encrypt_aes_ctr, decrypt_aes_ctr with open('25.txt', 'r') as f: message = string_to_bytearray(f.read().replace("\n", "")) KEY = string_to_bytearray("YELLOW SUBMARINE") NONCE = bytearray([0] * 8) ciphertext = encrypt_aes_ctr(message, KEY, NONCE) def edit(offset, newtext): m = decrypt_aes_ctr(ciphertext, KEY, NONCE) m[offset:offset + len(newtext)] = newtext return encrypt_aes_ctr(m, KEY, NONCE) def break_easy_way(): total_length = len(ciphertext) newtext = bytearray([0] * total_length) offset = 0 keystream = edit(offset, newtext) return xor(ciphertext, keystream)
def hkdf(self): ss = string_to_bytearray(str(self.shared_secret)) return hex_string_to_bytearray(sha1(ss))[:16]
from utils import base64_to_bytearray, hamming_distance, string_to_bytearray, unequal_chunks from single_byte_xor_cipher import break_xor_cipher from utils import alpha_and_printable_heuristic from itertools import zip_longest from repeating_key_xor import encrypt_repeating_key from operator import itemgetter assert hamming_distance(string_to_bytearray("this is a test"), string_to_bytearray("wokka wokka!!!")) == 37 # block contains a || b def normalized_edit_distance(block, key_size): a = block[0:key_size] b = block[key_size:(key_size * 2)] edit_distance = hamming_distance(a, b) return 1.0 * edit_distance / key_size def find_key_length(ciphertext): results = [] for key_size in range(2, 40): block_length = 2 * key_size nblocks = len(ciphertext) // block_length blocks = unequal_chunks(ciphertext, block_length) distances = [normalized_edit_distance(i, key_size) for i in blocks] average = sum(distances) / nblocks results.append((average, key_size))
import sys sys.path.insert(0, '../set_1_basics') sys.path.insert(0, '../set_2_block_crypto') sys.path.insert(0, '../set_3_block_stream_crypto') from utils import unequal_chunks, xor, string_to_bytearray from aes_ctr_mode import encrypt_aes_ctr, decrypt_aes_ctr KEY = string_to_bytearray("YELLOW SUBMARINE") NONCE = bytearray([0] * 8) def encrypt_params(user_input): user_input_stripped = user_input.replace(";", "").replace("=", "") prefix = "comment1=cooking%20MCs;userdata=" suffix = ";comment2=%20like%20a%20pound%20of%20bacon" message = string_to_bytearray(prefix + user_input_stripped + suffix) return encrypt_aes_ctr(message, KEY, NONCE) def check_admin(ciphertext): message = decrypt_aes_ctr(ciphertext, KEY, NONCE) return b";admin=true;" in message def ctr_bitflip(): user_input = "AadminZtrueZ" desired = ";admin=true;" ciphertext = encrypt_params(user_input)