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 aes_encode(block, key): block = pad_bits_append(block, len(key)) # the pycrypto library expects the key and block in 8 bit ascii # encoded strings so we have to convert from the bit array block = bits_to_string(block) key = bits_to_string(key) ecb = AES.new(key.encode("latin-1"), AES.MODE_ECB) return string_to_bits(str(ecb.encrypt(block.encode("latin-1")), encoding="latin-1"))
def aes_encode(block, key): block = pad_bits_append(block, len(key)) # the pycrypto library expects the key and block in 8 bit ascii # encoded strings so we have to convert from the bit array block = bits_to_string(block) key = bits_to_string(key) ecb = AES.new(key.encode("latin-1"), AES.MODE_ECB) return string_to_bits( str(ecb.encrypt(block.encode("latin-1")), encoding="latin-1"))
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 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 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 hash(input_, length): h = sha512(bits_to_string(input_)).digest() return string_to_bits(h)[:length]
# 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'
import lfsr import binascii import unit4_util given_prng = [0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0] def xor(word1, word2): key = [] for i in xrange(0, len(word1)): key.append(word1[i] ^ word2[i]) return key message = '8d801f00c7554d3980b0c4f400c1ebc572d86f57f48d322b8e7c3a1f01c531dbe772b77be5acd34bf1979b70089615ace253c4b01350f36f82215f164b7934fdd48a30' m_bytes = binascii.unhexlify(message) message_bits = unit4_util.string_to_bits(m_bytes) # Use LFSR_A51_1 to generate another 200 bits for the PRNG lfsr = lfsr.LFSR_A51_1(given_prng[1000-19:]) new_prng = given_prng[0:1000-19] for _ in range(0, 2000): new_prng.append(lfsr.next_output_bit()) # Loop through each 2000 bit range of the PRNG and use it to try and decrypt the # message. Examine each output message visually to find the interesting one # (which is message 1000 incidentally) for i in range(0, 2000): otp = new_prng[i:len(message_bits) + i] plaintext = xor(message_bits, otp) print i, unit4_util.bits_to_string(plaintext)
def hash(input_, length): input_string = bits_to_string(input_).encode(encoding='latin-1') h = sha512(input_string).digest() return string_to_bits(h)[:length]
def oaep_pad(message, nonce, g, h): mm = message + [0] * (g - len(message)) G = xor(mm, hash(nonce, g)) H = xor(nonce, hash(G, h)) return G + H 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)) ################## # ciphertext was created by calling # `encrypt` where message and nonce are secret ciphertext = string_to_bits("\x98WRQ5\xf4\xe5L$a\xf4\xbf\xecV\\\xb1\xe4\x18\xf1It\x01\xca\xdc\xd0@\xc8\xf6\x97\xf9K\xb8\x1b\x9a\x17\x89\xa9\xcap\x9a\xb5\xb4\x12\xf6\x01\x9avd\xedc*\xcbELRi\xf7.?\x82H\xd3Ci\xd7\xaea7\xbc\x00+\xf04\x13>\xe6q\xf3\xedg\xc4VWB\x8a\x9f\xdf%-8\xf3\x08\xc59\x84\xec\xf8G\xbe\xd2Ub\xf9K4\xa0\xa4(\xeaI\x19T\x1fM\xa6+\x81\xb0\x8d\x04\x99<%o3C-\xc6") plaintext = "Where is the ANY key? -Homer Simpson" # YOUR ANSWER HERE 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 decode_oaep(oaep_padded_int, g, h):