def decrypt_by_crt(messages, public_key): """ Requires that messages is an array of tuples of the form (ciphertext_i, n_i), where ciphertext_i for each i is the same message message m that is encrypted by m^public_key mod n_i. Attempts an attack based on the Chinese Remainder theorem to compute m^public_key_key mod (n_1 * n_2 * ...). Here the hope is that m^public_key is not large compared to (n_1 * n_2 * ...) so that we can recover the original message by just taking (ciphertext_i - n_i * k)^(1/public_key) where k is fairly small. Of course this attack only works if (ciphertext_i, n_i) are all encryptions of the same original message (with identical padding), encrypted with the same (small) public. Returns None if unable to decrypt the messages. """ print("Attempting decryption using CRT") crt_system = [(bits_to_int(string_to_bits(message[0])), message[1]) for message in messages] crt_solution = solve_crt_system(crt_system) # Recover the original message by taking the public_key root MAX_CRT_ROOT_TRIES = 10 for i in range(MAX_CRT_ROOT_TRIES): root_result = gmpy2.iroot( gmpy2.mpz(crt_solution[0] + crt_solution[1] * i), public_key) if root_result[1]: oaep_padded_plaintext_int = root_result[0] return remove_oaep_from_plaintext(oaep_padded_plaintext_int, crt_system[0][1]) return None
def decrypt_by_crt(messages, public_key): """ Requires that messages is an array of tuples of the form (ciphertext_i, n_i), where ciphertext_i for each i is the same message message m that is encrypted by m^public_key mod n_i. Attempts an attack based on the Chinese Remainder theorem to compute m^public_key_key mod (n_1 * n_2 * ...). Here the hope is that m^public_key is not large compared to (n_1 * n_2 * ...) so that we can recover the original message by just taking (ciphertext_i - n_i * k)^(1/public_key) where k is fairly small. Of course this attack only works if (ciphertext_i, n_i) are all encryptions of the same original message (with identical padding), encrypted with the same (small) public. Returns None if unable to decrypt the messages. """ print("Attempting decryption using CRT") crt_system = [(bits_to_int(string_to_bits(message[0])), message[1]) for message in messages] crt_solution = solve_crt_system(crt_system) # Recover the original message by taking the public_key root MAX_CRT_ROOT_TRIES = 10 for i in range(MAX_CRT_ROOT_TRIES): root_result = gmpy2.iroot(gmpy2.mpz(crt_solution[0] + crt_solution[1] * i), public_key) if root_result[1]: oaep_padded_plaintext_int = root_result[0] return remove_oaep_from_plaintext(oaep_padded_plaintext_int, crt_system[0][1]) return None
def decrypt(ciphertext, n, private_key, g, h): """ Decrypts the specified ciphertext. Assumes that ciphertext was obtained by applying OAEP padding to a message (using parameters g and h), and then RSA-encrypted with parameter n and public key corresponding to the specified private_key. """ ciphertext_int = bits_to_int(ciphertext) plaintext_int = pow(ciphertext_int, private_key, n) return decode_oaep(plaintext_int + n, g, h)
def deliver_hint(recipient, hint_str): """ Establish an encrypted session with the specified recipient and send hint_str. """ initialization_response = initialize(recipient[0]) session_token = initialization_response['token'] pg = get_pg() p = int(pg['p'], 16) g = int(pg['g'], 16) eve_key_response_int = pow(g, X_EVE, p) eve_key_response = hex(eve_key_response_int)[2:] # chop off the "0x" key_received_response = send_key(recipient[0], session_token, eve_key_response, "Eve") (ctr_key, ctr_nonce) = get_ctr_info(X_EVE, int(initialization_response['public'], 16)) initial_message = receive_msg(recipient[0], session_token) decrypted_message = counter_mode_encrypt(initial_message['msg'], ctr_key, initial_message['iv'], ctr_nonce) decrypted_message_str = bits_to_string(decrypted_message) print("decrypted_message_str", decrypted_message_str) hint_hex = hex(bits_to_int(string_to_bits(hint_str)))[2:] encrypted_hint = counter_mode_encrypt(hint_hex, ctr_key, initial_message['iv'], ctr_nonce) encrypted_hint_hex = hex(bits_to_int(encrypted_hint))[2:] response = send_msg(recipient[0], session_token, encrypted_hint_hex, initial_message['iv']) decrypted_message = counter_mode_encrypt(response['reply']['msg'], ctr_key, response['reply']['iv'], ctr_nonce) decrypted_message_str = bits_to_string(decrypted_message) print("decrypted_message_str", decrypted_message_str)
def retrieve_plaintext(ciphertext, private_key, n): """ Given the specified ciphertext string encrypted using the specified private_key and n value, returns the decrypted plaintext. Removes oaep if necessary. """ ciphertext_bits = pad_bits(string_to_bits(ciphertext), MESSAGE_CHARS * ASCII_BITS) ciphertext_int = bits_to_int(ciphertext_bits) padded_plaintext_int = pow(ciphertext_int, private_key, n) # If the message wasn't padded, we'll detect that here. padded_plaintext_bits = pad_bits(convert_to_bits(padded_plaintext_int), len(ciphertext_bits)) plaintext_string = bits_to_string(padded_plaintext_bits).strip('\x00') if is_valid_message(plaintext_string): return plaintext_string else: return remove_oaep_from_plaintext(padded_plaintext_int, n)
def decrypt_by_public_key_root(public_key, n, ciphertext): ciphertext_bits = string_to_bits(ciphertext) ciphertext_int = bits_to_int(ciphertext_bits) PUBLIC_KEY_ROOT_ATTEMPTS = 10 for i in range(PUBLIC_KEY_ROOT_ATTEMPTS): plaintext_root_result = gmpy2.iroot(gmpy2.mpz(ciphertext_int + i * n), public_key) if plaintext_root_result[1]: plaintext_int = int(plaintext_root_result[0]) assert pow(plaintext_int, public_key) == ciphertext_int + i * n print("Found integer root of message") plaintext_bits = pad_bits(convert_to_bits(plaintext_int), MESSAGE_CHARS * ASCII_BITS) plaintext_string = bits_to_string(plaintext_bits).strip('\x00') assert is_valid_message(plaintext_string) return plaintext_string else: print("Root result is non-integer") print("Unable to decrypt by taking private key root") return None
def create_bill_message(i, bill_amount, nonce): bill = create_bill(i, bill_amount) bill_int = bits_to_int(string_to_bits(bill)) t = blind_msg(bill_int, nonce, BANK_PUBLIC_KEY[0], BANK_PUBLIC_KEY[1]) return t
def run_mitm_session(first, second): """ Run a message exchange between the specified parties, but perform a MITM attack using a known private key for the exchange with each in order to snoop on the contents of the messages. """ first_initialization_response = initialize(first[0]) first_session_token = first_initialization_response['token'] second_initialization_response = initialize(second[0]) second_session_token = second_initialization_response['token'] pg = get_pg() p = int(pg['p'], 16) g = int(pg['g'], 16) eve_key_response_int = pow(g, X_EVE, p) eve_key_response = hex(eve_key_response_int)[2:] # chop off the "0x" first_key_received_response = send_key(first[0], first_session_token, eve_key_response, second[1]) second_key_received_response = send_key(second[0], second_session_token, eve_key_response, first[1]) (first_ctr_key, first_ctr_nonce) = get_ctr_info(X_EVE, int(first_initialization_response['public'], 16)) (second_ctr_key, second_ctr_nonce) = get_ctr_info(X_EVE, int(second_initialization_response['public'], 16)) first_person_message = receive_msg(first[0], first_session_token) first_person_decrypted_message = counter_mode_encrypt(first_person_message['msg'], first_ctr_key, first_person_message['iv'], first_ctr_nonce) first_person_decrypted_message_str = bits_to_string(first_person_decrypted_message) first_person_decrypted_message_hex = hex(bits_to_int(first_person_decrypted_message))[2:] test_encrypted_message_bits = counter_mode_encrypt(first_person_decrypted_message_hex, first_ctr_key, first_person_message['iv'], first_ctr_nonce) test_encrypted_message_str = hex(bits_to_int(test_encrypted_message_bits))[2:] assert test_encrypted_message_str == first_person_message['msg'] # Set up the message to be sent through the MITM session with second person first_re_encrypted_message_bits = counter_mode_encrypt(first_person_decrypted_message_hex, second_ctr_key, first_person_message['iv'], second_ctr_nonce) first_re_encrypted_message_str = hex(bits_to_int(first_re_encrypted_message_bits))[2:] response = send_msg(second[0], second_session_token, first_person_message['msg'], first_person_message['iv']) recipient, sender = first, second recipient_session_token, sender_session_token = first_session_token, second_session_token recipient_ctr_key, sender_ctr_key = first_ctr_key, second_ctr_key recipient_ctr_nonce, sender_ctr_nonce = first_ctr_nonce, second_ctr_nonce while 'reply' in response and 'iv' in response['reply'] and len(response['reply']['iv']) > 0: decrypted_response = counter_mode_encrypt(response['reply']['msg'], sender_ctr_key, response['reply']['iv'], sender_ctr_nonce) decrypted_response_str = bits_to_string(decrypted_response) print(sender[1], "decrypted_response_str", decrypted_response_str) response = send_msg(recipient[0], recipient_session_token, response['reply']['msg'], response['reply']['iv']) # Switch places recipient, sender = sender, recipient recipient_session_token, sender_session_token = sender_session_token, recipient_session_token recipient_ctr_key, sender_ctr_key = sender_ctr_key, recipient_ctr_key recipient_ctr_nonce, sender_ctr_nonce = sender_ctr_nonce, recipient_ctr_nonce
# http://forums.udacity.com/cs387-april2012/questions/2814/hw4-6-challenge-question-discussion # # If you want to use functions from unit4_util, make sure to set the ASCII_BITS = 8 # import unit4_util # unit4_util.ASCII_BITS = 8 # # unit4_util code: http://pastebin.com/Te2AmDre from unit4_util import bits_to_int, string_to_bits, bits_to_string, convert_to_bits, pad_bits ################ e0 = 65537 n0 = 116436872704204817262873499608558046190724591466716177557829773662807162485791977636521167560986434993048860346504247233074117974671540999410485959711510256117299326339754889488213509449940603119123994148576130959569697235313003024809821145961963221161561975123663333322412762102191502543834949106445222007561 cipher0 = "<\xad\xdd\xedg\x8b\x12\x0b\x00y\xa2\xf0\x86\xcbF\xf0\x8f\xb4~\xbd\x04\xd9\xac6iwxk\xcfi\xc4Z1p\\\x14\xa4rL\x9a#\x9f\xbf~\xec[\x8d\xfc(\x82\xc2s\xb9\x0e\xec(\xd9.}\xc5\xdf\xa8'`\xa5\xdb\x18\xf1Z\xff\x82xQJa\x11\x98/x&{\x0b\x17\xb9\xb1\x88\x8f\x85B\x7fH\xdbX\x9aV\x9a\xaf\x0fKc+\xf7?\xb8\xb4\x1fo\x0eeI\xa9\x90\x11\x83\xb8\xfdaMwM\xc7\xb48&-\xe8\xf1C" c0 = bits_to_int(string_to_bits(cipher0)) m0 = ''#YOUR ANSWER HERE ################ ################ e1 = 3 n1 = 131776503472993446247578652375782286463851826883886018427615607890323792437218636575447994626809806013420405963813337101556738852432247872506699457038044621191649758706817663135648397013226104530751563478671698441687437700125203966101608457556637550910814187779205610883544935666685906870199595346450733709263 cipher1 = '\x04\xacq#E/\xf4X\x126\xef\xc6\xb1\xfc\x10p*\x98P\xde\x089K\x16y0\xfa\xde\x9f\x05\x15+\xa3\x0f\xbc3\xd1t\xe7\x9a\x1b\x04m\xa1\x12\x96\x18Y\xf9\xc95\xce\x19 E\xfa\xe1\xb5\x8a\xd5\xf2\x99\xa6"<\xcb\x1a\xd0\xce=\x91\xfbw\t\xb5' c1 = bits_to_int(string_to_bits(cipher1)) m1 = 'Chinese Remainder Theorem'#YOUR ANSWER HERE ################ ################ e2 = 3 n2 = 65659232975830381768328338666607829001259240689809015666589078261348261561917417083788447204534665997091584936794919521220643455263371034991817572752104164283083678838816431044389236958346474896965382016943200300407371205608596328649170408446414718769422147103617311701247139971805834487439320773304455320217 cipher2 = '\x04\xe97r\x13\x99\xf7\x80m\x19\xe3f\x1a\x92]u!\x17\xdf\xa8\xfd\xd4\xd0\xbea\xe8\x1f\xefc\xd6\xc7\xbf\xce\xa4q\xfe\xa4S\xff\xaf\x1aX\xc13g\xeb\x12\xadw\x17T\x05\x1c\x8e\xd8\xea\x1bkc\xd3\xfctQt\x8e\xf6d\x1a\x98\xbc}\x08\x1d%\xc7\xd2K\xb4\xa8\x96\xcf\x98D\x8a\xbd\xa7\xd2\xcc\x861$\xd1\x1b\xdd\xa0h\x83\xdan\xcbm\xa4\xf9\xef\x96\x12\x9c|\xc9\xd7\t\x9b\x0f:\x9e\xe0\xa1\xb2\t\x8b\x9d\x18\x07\x8e]\x8c\x13\xa2'
def run_mitm_session(first, second): """ Run a message exchange between the specified parties, but perform a MITM attack using a known private key for the exchange with each in order to snoop on the contents of the messages. """ first_initialization_response = initialize(first[0]) first_session_token = first_initialization_response['token'] second_initialization_response = initialize(second[0]) second_session_token = second_initialization_response['token'] pg = get_pg() p = int(pg['p'], 16) g = int(pg['g'], 16) eve_key_response_int = pow(g, X_EVE, p) eve_key_response = hex(eve_key_response_int)[2:] # chop off the "0x" first_key_received_response = send_key(first[0], first_session_token, eve_key_response, second[1]) second_key_received_response = send_key(second[0], second_session_token, eve_key_response, first[1]) (first_ctr_key, first_ctr_nonce) = get_ctr_info( X_EVE, int(first_initialization_response['public'], 16)) (second_ctr_key, second_ctr_nonce) = get_ctr_info( X_EVE, int(second_initialization_response['public'], 16)) first_person_message = receive_msg(first[0], first_session_token) first_person_decrypted_message = counter_mode_encrypt( first_person_message['msg'], first_ctr_key, first_person_message['iv'], first_ctr_nonce) first_person_decrypted_message_str = bits_to_string( first_person_decrypted_message) first_person_decrypted_message_hex = hex( bits_to_int(first_person_decrypted_message))[2:] test_encrypted_message_bits = counter_mode_encrypt( first_person_decrypted_message_hex, first_ctr_key, first_person_message['iv'], first_ctr_nonce) test_encrypted_message_str = hex( bits_to_int(test_encrypted_message_bits))[2:] assert test_encrypted_message_str == first_person_message['msg'] # Set up the message to be sent through the MITM session with second person first_re_encrypted_message_bits = counter_mode_encrypt( first_person_decrypted_message_hex, second_ctr_key, first_person_message['iv'], second_ctr_nonce) first_re_encrypted_message_str = hex( bits_to_int(first_re_encrypted_message_bits))[2:] response = send_msg(second[0], second_session_token, first_person_message['msg'], first_person_message['iv']) recipient, sender = first, second recipient_session_token, sender_session_token = first_session_token, second_session_token recipient_ctr_key, sender_ctr_key = first_ctr_key, second_ctr_key recipient_ctr_nonce, sender_ctr_nonce = first_ctr_nonce, second_ctr_nonce while 'reply' in response and 'iv' in response['reply'] and len( response['reply']['iv']) > 0: decrypted_response = counter_mode_encrypt(response['reply']['msg'], sender_ctr_key, response['reply']['iv'], sender_ctr_nonce) decrypted_response_str = bits_to_string(decrypted_response) print(sender[1], "decrypted_response_str", decrypted_response_str) response = send_msg(recipient[0], recipient_session_token, response['reply']['msg'], response['reply']['iv']) # Switch places recipient, sender = sender, recipient recipient_session_token, sender_session_token = sender_session_token, recipient_session_token recipient_ctr_key, sender_ctr_key = sender_ctr_key, recipient_ctr_key recipient_ctr_nonce, sender_ctr_nonce = sender_ctr_nonce, recipient_ctr_nonce
def encrypt(message, n, public_key, nonce, g, h): oaep = oaep_pad(message, nonce, g, h) m_int = bits_to_int(oaep) return convert_to_bits(pow(m_int, public_key, n))