if i == 0: guesses[c] = guesses[c] + chr(c) guesses[c] = guesses[c] + chr(ord(ciphertexts[i][15]) ^ c) # for j in range(len(guesses)): # print [guesses[j]] # After finding the first 16 bytes of keystream, I easily deduced the # full text from Google. Now I can deduce the whole keystream from the # longest line, and then decrypt as follows: line00 = "I have met them at close of day" line04 = "I have passed with a nod of the head" line37 = "He, too, has been changed in his turn," print "guesses:" print[xor_str(ciphertexts[0][0:len(line00)], line00)] print[xor_str(ciphertexts[4][0:len(line04)], line04)] print[xor_str(ciphertexts[37][0:len(line37)], line37)] keystream = xor_str(ciphertexts[37][0:len(line37)], line37) plaintexts = [""] * len(ciphertexts) for i in range(len(ciphertexts)): for j in range(len(ciphertexts[i])): plaintexts[i] = plaintexts[i] + xor_str(ciphertexts[i][j], keystream[j]) print '\n'.join(plaintexts) #### tests ####
#!/usr/bin/env python # chal25.py - Break random access read/write CTR # # Copyright (C) 2015 Andrew J. Zimolzak <*****@*****.**>, # and licensed under GNU GPL version 3. Full notice is found in # the file 'LICENSE' in the same directory as this file. from cryptopals import warn, xor_str from fakeserver import ctr_ciphertext, edit_public, ctr_cheat # test editing edited = edit_public(ctr_ciphertext, 4, 'COOL') lines = ctr_cheat(edited).splitlines()[0:4] # use editing to get keystream & thus plaintext keystream = edit_public(ctr_ciphertext, 0, "\x00" * len(ctr_ciphertext)) print xor_str(keystream, ctr_ciphertext) #### tests, if any #### assert lines[0] == "I'm COOL and I'm ringin' the bell " warn("Passed assertions:", __file__)
print print "==== Analysis ====" blocksize = 16 c0 = ciphertext[0:blocksize] c4_end = ciphertext[4 * blocksize:] mod_ciphertext = c0 + ("\x00" * blocksize) + c0 + c4_end try: check_ciphertext(mod_ciphertext) except BadCharacter as badchar_obj: mod_decrypt = str(badchar_obj) p0 = mod_decrypt[0:blocksize] p2 = mod_decrypt[2 * blocksize:3 * blocksize] key_recovered = xor_str(p0, p2) print "Found that key is", key_recovered att_cipher = AES.new(key_recovered, AES.MODE_CBC, IV=key_recovered) admin = """ THE BEARER OF THIS TOKEN IS A GENUINE AND AUTHORIZED ADMIN. So please Treat Ver Right. GOOD FOREVER. """ admin = pad_multiple(admin, blocksize) att_ctext = att_cipher.encrypt(admin) modified_is_admin = check_ciphertext(att_ctext) #### tests, if any ####
def xor_char_str(c,s): cc = c * len(s) return xor_str(cc, s)
from cryptopals import warn, xor_str from fakeserver import * adm_string = ";admin=true" benign = site_profile_token("hello") nice_try = site_profile_token(adm_string) #### Analysis starts here get_keystream = site_profile_token("\x00" * (len(adm_string))) ciphertext = get_keystream[0] altered = [] for i in range(len(ciphertext) - len(adm_string)): head = "\x00" * i tail = "\x00" * (len(ciphertext) - i - len(adm_string)) altered_ciphertext = xor_str(ciphertext, head + adm_string + tail) altered = [altered_ciphertext, get_keystream[1]] if profile_is_admin(altered): print "Success at offset", i break if len(altered) > 0: print "Success with the following ciphertext:" print_profile(altered) print "Decrypts to:" print profile_token_cheat(altered) #### tests, if any #### assert len(altered) > 0 assert profile_is_admin(altered) assert 'hello' in profile_token_cheat(benign)
from cryptopals import warn, xor_str from fakeserver import * adm_string = ";admin=true" benign = site_profile_token("hello") nice_try = site_profile_token(adm_string) #### Analysis starts here get_keystream = site_profile_token("\x00" * (len(adm_string))) ciphertext = get_keystream[0] altered = [] for i in range(len(ciphertext) - len(adm_string)): head = "\x00" * i tail = "\x00" * (len(ciphertext) - i - len(adm_string)) altered_ciphertext = xor_str(ciphertext, head+adm_string+tail) altered = [altered_ciphertext, get_keystream[1]] if profile_is_admin(altered): print "Success at offset", i break if len(altered) > 0: print "Success with the following ciphertext:" print_profile(altered) print "Decrypts to:" print profile_token_cheat(altered) #### tests, if any #### assert len(altered) > 0 assert profile_is_admin(altered) assert 'hello' in profile_token_cheat(benign)
if i == 0: guesses[c] = guesses[c] + chr(c) guesses[c] = guesses[c] + chr(ord(ciphertexts[i][15]) ^ c) # for j in range(len(guesses)): # print [guesses[j]] # After finding the first 16 bytes of keystream, I easily deduced the # full text from Google. Now I can deduce the whole keystream from the # longest line, and then decrypt as follows: line00 = "I have met them at close of day" line04 = "I have passed with a nod of the head" line37 = "He, too, has been changed in his turn," print "guesses:" print [xor_str(ciphertexts[0][0:len(line00)], line00)] print [xor_str(ciphertexts[4][0:len(line04)], line04)] print [xor_str(ciphertexts[37][0:len(line37)], line37)] keystream = xor_str(ciphertexts[37][0:len(line37)], line37) plaintexts = [""] * len(ciphertexts) for i in range(len(ciphertexts)): for j in range(len(ciphertexts[i])): plaintexts[i] = plaintexts[i] + xor_str(ciphertexts[i][j], keystream[j]) print '\n'.join(plaintexts) #### tests ####
print print "==== Analysis ====" blocksize = 16 c0 = ciphertext[0:blocksize] c4_end = ciphertext[4 * blocksize : ] mod_ciphertext = c0 + ("\x00" * blocksize) + c0 + c4_end try: check_ciphertext(mod_ciphertext) except BadCharacter as badchar_obj: mod_decrypt = str(badchar_obj) p0 = mod_decrypt[0:blocksize] p2 = mod_decrypt[2*blocksize : 3*blocksize] key_recovered = xor_str(p0, p2) print "Found that key is", key_recovered att_cipher = AES.new(key_recovered, AES.MODE_CBC, IV = key_recovered) admin = """ THE BEARER OF THIS TOKEN IS A GENUINE AND AUTHORIZED ADMIN. So please Treat Ver Right. GOOD FOREVER. """ admin = pad_multiple(admin,blocksize) att_ctext = att_cipher.encrypt(admin) modified_is_admin = check_ciphertext(att_ctext) #### tests, if any ####
blocksize = 16 # too lazy to determine this now plaintext = [""] * (len(ciph) / blocksize) for blocknum in range(len(ciph) / blocksize): if blocknum == 0: Ca = iv # There is smarter way, without the IF. else: Ca = ciph[blocksize * (blocknum - 1):blocksize * blocknum] Cb = ciph[blocksize * blocknum:blocksize * (blocknum + 1)] for n_bytes in range(1, blocksize + 1): guess = "" for charnum in range(2, 256): # Might be screwed if it is \x01 guess = chr(charnum) b = Ca[-(n_bytes):] g = guess + plaintext[blocknum] # p[b] will be incomplete x = chr(n_bytes) * (n_bytes) Cac = Ca[:-(n_bytes)] + cryptopals.xor_str( cryptopals.xor_str(b, g), x) if fakeserver.padding_is_valid(Cac + Cb, iv): break plaintext[blocknum] = guess + plaintext[blocknum] output = cryptopals.strip_padding(''.join(plaintext)) print output #### tests #### assert (cryptopals.strip_padding(fakeserver.cheat(ciph, iv)) == output) for i in range(100): [ciph, iv] = fakeserver.random_ciphertext_iv() assert (fakeserver.padding_is_valid(ciph, iv)) cryptopals.warn("Passed assertions (" + __file__ + ")")