def cbc_iv_equals_key_attack(): ciphertext = cbc_encrypt() BLOCK_SIZE = 16 first_block_ciphertext = util.get_ith_block(ciphertext, 0, BLOCK_SIZE) constructed_ciphertext = first_block_ciphertext + bytes([0]*BLOCK_SIZE) + first_block_ciphertext + bytes([0]*BLOCK_SIZE*8) error, garbled_plaintext = cbc_decrypt(constructed_ciphertext) return util.xor(util.get_ith_block(garbled_plaintext, 0, BLOCK_SIZE), util.get_ith_block(garbled_plaintext, 2, BLOCK_SIZE))
def ecb_chosen_plaintext_attack(): #find block size BLOCK_SIZE = 16 #find length of prefix empty_ciphertext = ecb_encrypt_surround(b'') fixed_ciphertext = ecb_encrypt_surround(b'A') current_empty_block = util.get_ith_block(empty_ciphertext, 0, BLOCK_SIZE) current_fixed_block = util.get_ith_block(fixed_ciphertext, 0, BLOCK_SIZE) i = 0 while current_empty_block == current_fixed_block: i += 1 current_empty_block = util.get_ith_block(empty_ciphertext, i, BLOCK_SIZE) current_fixed_block = util.get_ith_block(fixed_ciphertext, i, BLOCK_SIZE) trans_index = i number_of_chars = 0 fixed_block = util.get_ith_block( ecb_encrypt_surround(b'A' * BLOCK_SIZE * 2), trans_index + 1, BLOCK_SIZE) for i in range(BLOCK_SIZE + 1, 2 * BLOCK_SIZE + 1): potential_fixed_block = util.get_ith_block( ecb_encrypt_surround(b'A' * i), trans_index + 1, BLOCK_SIZE) if potential_fixed_block == fixed_block: number_of_chars = i - BLOCK_SIZE break #decryption plaintext = b'' length = len(ecb_encrypt_surround(b'')) i = trans_index current_block = b'A' * BLOCK_SIZE while len(plaintext) < length: for j in range(BLOCK_SIZE): ciphertext_block = util.get_ith_block( ecb_encrypt_surround(b'A' * number_of_chars + b'A' * (BLOCK_SIZE - j - 1)), i + 1, BLOCK_SIZE) dictionary = {} for k in range(256): check_block = util.get_ith_block( ecb_encrypt_surround(b'A' * number_of_chars + current_block[1:BLOCK_SIZE] + bytes([k])), trans_index + 1, BLOCK_SIZE) dictionary[check_block] = bytes([k]) #deals with padding issues if not ciphertext_block in dictionary: return plaintext.decode('utf-8') k = dictionary[ciphertext_block] current_block = current_block[1:BLOCK_SIZE] + k plaintext += current_block i += 1 return plaintext.decode('utf-8')
def md_hash(message): h = initial_state M = length_padding(message) for i in range(len(M) // BLOCK_SIZE): Mi = util.get_ith_block(M, i, BLOCK_SIZE) h = util.ecb_encrypt(Mi, util.padding(h, BLOCK_SIZE))[0:STATE_LEN] return binascii.hexlify(h)
def ecb_chosen_plaintext_attack(): #first find the blocksize block_size = 0 for block_size in range(5, 40): block_1 = util.get_ith_block(ecb_encrypt_prepend(b'A' * block_size), 0, block_size) block_2 = util.get_ith_block( ecb_encrypt_prepend(b'A' * (block_size + 1)), 0, block_size) if block_1 == block_2: break if block_size == 0: return False #verify that it is ECB mode check_ecb = analysis.detect_ECB_mode( ecb_encrypt_prepend(b'A' * 4 * block_size)) if not check_ecb: return False #decryption plaintext = b'' length = len(ecb_encrypt_prepend(b'')) i = 0 current_block = b'A' * block_size while len(plaintext) < length: for j in range(block_size): ciphertext_block = util.get_ith_block( ecb_encrypt_prepend(b'A' * (block_size - j - 1)), i, block_size) dictionary = {} for k in range(256): check_block = util.get_ith_block( ecb_encrypt_prepend(current_block[1:block_size] + bytes([k])), 0, block_size) dictionary[check_block] = bytes([k]) #deals with padding issues if not ciphertext_block in dictionary: return plaintext.decode("utf-8") k = dictionary[ciphertext_block] current_block = current_block[1:block_size] + k plaintext += current_block i += 1 return plaintext.decode("utf-8")
def send_message_A(B): global s_A, a, p, B_A B_A = B s_A = pow(B_A, a, p) msg = MESSAGE key = hashes.SHA1(util.int_to_bytes(s_A)) key = util.get_ith_block(key, 0, BLOCK_SIZE) iv = util.random_byte_string(BLOCK_SIZE) return (util.cbc_encrypt(msg, key, iv), iv)
def send_message_B(ciphertext, iv): global s_B, A_B, b, p s_B = pow(A_B, b, p) key = hashes.SHA1(util.int_to_bytes(s_B)) key = util.get_ith_block(key, 0, BLOCK_SIZE) plaintext = util.cbc_decrypt(ciphertext, key, iv) assert plaintext == MESSAGE iv = util.random_byte_string(BLOCK_SIZE) return (util.cbc_encrypt(plaintext, key, iv), iv)
def cbc_padding_oracle_attack(): ciphertext = cbc_encrypt_special() BLOCK_SIZE = 16 num_blocks = len(ciphertext) // BLOCK_SIZE plaintext = b'' current_ciphertext_block = iv for b in range(0, num_blocks): current_plaintext_block = b'' failed = False wrong_g = b'' i = 1 while i < BLOCK_SIZE + 1: for g in range(256): if failed and i == 1 and g == wrong_g: continue mod_cipher_block = current_ciphertext_block[:BLOCK_SIZE - i] guess_current_plain_block = bytes([g ]) + current_plaintext_block for j in range(BLOCK_SIZE - i, BLOCK_SIZE): mod_cipher_block += bytes([ guess_current_plain_block[j - BLOCK_SIZE + i] ^ current_ciphertext_block[j] ^ i ]) trial_ciphertext = util.get_ith_block(ciphertext, b, BLOCK_SIZE) try: cbc_decrypt_special(trial_ciphertext, mod_cipher_block) current_plaintext_block = guess_current_plain_block break except PaddingError: pass if len(current_plaintext_block) != i: failed = True wrong_g = current_plaintext_block[-1] current_plaintext_block = b'' i -= 2 i += 1 plaintext += current_plaintext_block current_ciphertext_block = util.get_ith_block(ciphertext, b, BLOCK_SIZE) return util.unpadding(plaintext)
def md_hash(message, state_len = STATE_LEN, H = None): # initial state h = b''.join([util.int_to_bytes((37*i + 42) % 256) for i in range(state_len)]) if not H: H = h M = util.padding(message, AES_BLOCK_SIZE) for i in range(len(M)//AES_BLOCK_SIZE): Mi = util.get_ith_block(M, i, AES_BLOCK_SIZE) H = util.ecb_encrypt(Mi, util.padding(H, AES_BLOCK_SIZE))[0:state_len] return binascii.hexlify(H)
def get_intermediate_states(message, k): states = {} h = initial_state for i in range(len(message) // BLOCK_SIZE): block = util.get_ith_block(message, i, BLOCK_SIZE) h = md_hash_instrumented(block, h) # exclude intermediate states not in our expandable message regime if k <= i <= k + (1 << k) - 1: states[h] = i h = binascii.unhexlify(h) return states
def cbc_bitflipping_attack(): ciphertext = cbc_encrypt_surround(b'') BLOCK_SIZE = 16 num_blocks = len(ciphertext)//BLOCK_SIZE first_block_ciphertext = util.get_ith_block(ciphertext, 0, BLOCK_SIZE) second_block_plaintext = b'%20MCs;userdata=' desired_text = util.padding(b';admin=true;', BLOCK_SIZE) fixed_first_block = b'' for i in range(BLOCK_SIZE): fixed_first_block += bytes([second_block_plaintext[i]^first_block_ciphertext[i]^desired_text[i]]) fixed_ciphertext = fixed_first_block + ciphertext[BLOCK_SIZE:] print(cbc_decrypt_surround(fixed_ciphertext))
def construct_new_MAC(known_message, MAC, message_suffix, key_length=16): NUM_REGS = 5 original_byte_len = key_length + len(known_message) original_bit_len = original_byte_len * 8 init_regs = [ struct.unpack('>I', util.get_ith_block(MAC, i, 4))[0] for i in range(NUM_REGS) ] glue_padding = b'\x80' + b'\x00' * ( (56 - (original_byte_len + 1) % 64) % 64) + struct.pack( b'>Q', original_bit_len) new_message = known_message + glue_padding + message_suffix return new_message, hashes.SHA1(message_suffix, original_byte_len=key_length + len(new_message), init_state=init_regs)
def ctr_bitflipping_attack(): ciphertext = ctr_encrypt_surround(b'') BLOCK_SIZE = 16 num_blocks = len(ciphertext) // BLOCK_SIZE third_block_ciphertext = util.get_ith_block(ciphertext, 2, BLOCK_SIZE) third_block_plaintext = b';comment2=%20lik' desired_text = util.padding(b';admin=true;', BLOCK_SIZE) fixed_third_block = b'' for i in range(BLOCK_SIZE): fixed_third_block += bytes([ third_block_plaintext[i] ^ third_block_ciphertext[i] ^ desired_text[i] ]) fixed_ciphertext = ciphertext[ 0:2 * BLOCK_SIZE] + fixed_third_block + ciphertext[3 * BLOCK_SIZE:] print(ctr_decrypt_surround(fixed_ciphertext))
assert '&' not in email and '=' not in email return { 'email': email, 'uid': 10, 'role': 'user', } def encrypt_profile_for(email): plaintext = encode_profile(profile_for(email)).encode('utf-8') return util.ecb_encrypt(util.padding(plaintext, 16), PROFILE_KEY) def decrypt_profile(crypt): plaintext = util.ecb_decrypt(crypt, PROFILE_KEY) return decode_profile(util.unpadding(plaintext).decode('utf-8')) if __name__ == '__main__': BLOCK_SIZE = 16 admin = util.padding(b'admin', BLOCK_SIZE) admin_block = util.get_ith_block( encrypt_profile_for('A' * (BLOCK_SIZE - len('email=')) + admin.decode('utf-8')), 1, BLOCK_SIZE) first_block = util.get_ith_block(encrypt_profile_for('*****@*****.**'), 0, BLOCK_SIZE) second_block = util.get_ith_block(encrypt_profile_for('*****@*****.**'), 1, BLOCK_SIZE) admin_ciphertext = first_block + second_block + admin_block print(decrypt_profile(admin_ciphertext))
(ciphertext, iv) = dh.send_message_A(B_B) (ciphertext, iv) = dh.send_message_B(ciphertext, iv) print('Successfully executed DH Protocol') # Simulate MITM Attack on DH Protocol # by messing with the 'g' parameter # g = 1 (p, g, A_A) = dh.send_params_A() B_B = dh.send_params_B(p, 1, 1) (ciphertext, iv) = dh.send_message_A(B_B) (_, _) = dh.send_message_B(ciphertext, iv) s = 1 key = hashes.SHA1(util.int_to_bytes(s)) key = util.get_ith_block(key, 0, dh.BLOCK_SIZE) plaintext = util.cbc_decrypt(ciphertext, key, iv) assert plaintext == dh.MESSAGE # g = p (p, g, A_A) = dh.send_params_A() B_B = dh.send_params_B(p, p, 0) (ciphertext, iv) = dh.send_message_A(B_B) (_, _) = dh.send_message_B(ciphertext, iv) s = 0 key = hashes.SHA1(util.int_to_bytes(s)) key = util.get_ith_block(key, 0, dh.BLOCK_SIZE) plaintext = util.cbc_decrypt(ciphertext, key, iv) assert plaintext == dh.MESSAGE
def md_hash_instrumented(M, H=initial_state): for i in range(len(M) // BLOCK_SIZE): Mi = util.get_ith_block(M, i, BLOCK_SIZE) H = util.ecb_encrypt(Mi, util.padding(H, BLOCK_SIZE))[0:STATE_LEN] return binascii.hexlify(H)
global s_B, A_B, b, p s_B = pow(A_B, b, p) key = hashes.SHA1(util.int_to_bytes(s_B)) key = util.get_ith_block(key, 0, BLOCK_SIZE) plaintext = util.cbc_decrypt(ciphertext, key, iv) assert plaintext == MESSAGE iv = util.random_byte_string(BLOCK_SIZE) return (util.cbc_encrypt(plaintext, key, iv), iv) if __name__ == '__main__': # Simulate Diffie Hellman Protocol (p, g, A_A) = send_params_A() B_B = send_params_B(p, g, A_A) (ciphertext, iv) = send_message_A(B_B) (ciphertext, iv) = send_message_B(ciphertext, iv) print('Successfully executed DH Protocol') # Simulate MITM Attack on DH Protocol (p, g, A_A) = send_params_A() B_B = send_params_B(p, g, p) (ciphertext, iv) = send_message_A(p) (_, _) = send_message_B(ciphertext, iv) s = 0 key = hashes.SHA1(util.int_to_bytes(s)) key = util.get_ith_block(key, 0, BLOCK_SIZE) plaintext = util.cbc_decrypt(ciphertext, key, iv) assert plaintext == MESSAGE print('Successfully intercepted plaintext')