def edit_func(offset, newtext): assert offset <= len(ciphertext) new_p = plaintext[:offset] + newtext + plaintext[offset+len(newtext):] #print "New plaintext: %s" % new_p return aes_ctr(k, new_p, nonce)
def challenge_26_encrypt(string_in): to_return = 'comment1=cooking%20MCs;userdata=' + string_in.replace( '=', '%3d').replace( ';', '%3b') + ';comment2=%20like%20a%20pound%20of%20bacon' to_return = str.encode(to_return) return aes_ctr(to_return, challenge_26_aes_key)
def break_ctr_api(plaintext, ctr_key=None): ''' Imagine the "edit" function was exposed to attackers by means of an API call that didn't reveal the key or the original plaintext; the attacker has the ciphertext and controls the offset and "new text". Recover the original plaintext. ciphera = a_plaintext xor keystream cipherb = b_plaintext xor keystream ciphera xor cipherb = a_plaintext xor keystream xor b_plaintext xor keystream ciphera xor cipherb xor b_plaintext = a_plaintext ''' if ctr_key is None: ctr_key = generate_random_key() ciphertext = aes_ctr(plaintext, ctr_key) def api(offset, newtext): return edit_ctr_cipher(ciphertext, ctr_key, offset, newtext) a_cipher = ciphertext b_plaintext = b'A' * len(ciphertext) b_cipher = api(0, b_plaintext) return bytes( [a ^ b ^ c for a, b, c in zip(a_cipher, b_cipher, b_plaintext)])
def check_ctr_bitflip(k, ciphertext, nonce): plaintext = aes_ctr(k, ciphertext, nonce) print "decrypted: ", repr(plaintext) pieces = plaintext.split(';') for p in pieces: if p == 'admin=true': return True return False
def aes_ctr_oracle(k, plaintext, nonce): s1 = "comment1=cooking%20MCs;userdata=" s2 = ";comment2=%20like%20a%20pound%20of%20bacon" # strip ';' and '=' from plaintext plaintext = plaintext.replace(';','') plaintext = plaintext.replace('=','') return aes_ctr(k, s1 + plaintext + s2, nonce)
def aes_ctr_get_edit_func(plaintext): k = os.urandom(16) nonce = os.urandom(8) ciphertext = aes_ctr(k, plaintext, nonce) def edit_func(offset, newtext): assert offset <= len(ciphertext) new_p = plaintext[:offset] + newtext + plaintext[offset+len(newtext):] #print "New plaintext: %s" % new_p return aes_ctr(k, new_p, nonce) return ciphertext, edit_func
def test_challenge19(): b64strings = [ 'SSBoYXZlIG1ldCB0aGVtIGF0IGNsb3NlIG9mIGRheQ==', 'Q29taW5nIHdpdGggdml2aWQgZmFjZXM=', 'RnJvbSBjb3VudGVyIG9yIGRlc2sgYW1vbmcgZ3JleQ==', 'RWlnaHRlZW50aC1jZW50dXJ5IGhvdXNlcy4=', 'SSBoYXZlIHBhc3NlZCB3aXRoIGEgbm9kIG9mIHRoZSBoZWFk', 'T3IgcG9saXRlIG1lYW5pbmdsZXNzIHdvcmRzLA==', 'T3IgaGF2ZSBsaW5nZXJlZCBhd2hpbGUgYW5kIHNhaWQ=', 'UG9saXRlIG1lYW5pbmdsZXNzIHdvcmRzLA==', 'QW5kIHRob3VnaHQgYmVmb3JlIEkgaGFkIGRvbmU=', 'T2YgYSBtb2NraW5nIHRhbGUgb3IgYSBnaWJl', 'VG8gcGxlYXNlIGEgY29tcGFuaW9u', 'QXJvdW5kIHRoZSBmaXJlIGF0IHRoZSBjbHViLA==', 'QmVpbmcgY2VydGFpbiB0aGF0IHRoZXkgYW5kIEk=', 'QnV0IGxpdmVkIHdoZXJlIG1vdGxleSBpcyB3b3JuOg==', 'QWxsIGNoYW5nZWQsIGNoYW5nZWQgdXR0ZXJseTo=', 'QSB0ZXJyaWJsZSBiZWF1dHkgaXMgYm9ybi4=', 'VGhhdCB3b21hbidzIGRheXMgd2VyZSBzcGVudA==', 'SW4gaWdub3JhbnQgZ29vZCB3aWxsLA==', 'SGVyIG5pZ2h0cyBpbiBhcmd1bWVudA==', 'VW50aWwgaGVyIHZvaWNlIGdyZXcgc2hyaWxsLg==', 'V2hhdCB2b2ljZSBtb3JlIHN3ZWV0IHRoYW4gaGVycw==', 'V2hlbiB5b3VuZyBhbmQgYmVhdXRpZnVsLA==', 'U2hlIHJvZGUgdG8gaGFycmllcnM/', 'VGhpcyBtYW4gaGFkIGtlcHQgYSBzY2hvb2w=', 'QW5kIHJvZGUgb3VyIHdpbmdlZCBob3JzZS4=', 'VGhpcyBvdGhlciBoaXMgaGVscGVyIGFuZCBmcmllbmQ=', 'V2FzIGNvbWluZyBpbnRvIGhpcyBmb3JjZTs=', 'SGUgbWlnaHQgaGF2ZSB3b24gZmFtZSBpbiB0aGUgZW5kLA==', 'U28gc2Vuc2l0aXZlIGhpcyBuYXR1cmUgc2VlbWVkLA==', 'U28gZGFyaW5nIGFuZCBzd2VldCBoaXMgdGhvdWdodC4=', 'VGhpcyBvdGhlciBtYW4gSSBoYWQgZHJlYW1lZA==', 'QSBkcnVua2VuLCB2YWluLWdsb3Jpb3VzIGxvdXQu', 'SGUgaGFkIGRvbmUgbW9zdCBiaXR0ZXIgd3Jvbmc=', 'VG8gc29tZSB3aG8gYXJlIG5lYXIgbXkgaGVhcnQs', 'WWV0IEkgbnVtYmVyIGhpbSBpbiB0aGUgc29uZzs=', 'SGUsIHRvbywgaGFzIHJlc2lnbmVkIGhpcyBwYXJ0', 'SW4gdGhlIGNhc3VhbCBjb21lZHk7', 'SGUsIHRvbywgaGFzIGJlZW4gY2hhbmdlZCBpbiBoaXMgdHVybiw=', 'VHJhbnNmb3JtZWQgdXR0ZXJseTo=', 'QSB0ZXJyaWJsZSBiZWF1dHkgaXMgYm9ybi4=' ] ciphertexts = [ set3.aes_ctr(base64.b64decode(s), constants.key) for s in b64strings ] set3.challenge19(ciphertexts)
def challenge26_isadmin(ciphertext): return b';admin=true;' in set3.aes_ctr(ciphertext, constants.key)
def challenge26_encrypt(user_input): user_input = user_input.replace(b';', b'%3B') user_input = user_input.replace(b'=', b'%3D') plaintext = b'comment1=cooking%20MCs;userdata=' + user_input plaintext += b';comment2=%20like%20a%20pound%20of%20bacon' return set3.aes_ctr(plaintext, constants.key)
def challenge25_edit(ciphertext, offset, newtext): plaintext = set3.aes_ctr(ciphertext, constants.key) return set3.aes_ctr(plaintext[:offset] + newtext, constants.key)
def challenge_26_detect_admin(cipher): decrypted = aes_ctr(cipher, challenge_26_aes_key) return decrypted.count(b";admin=true") > 0
def test_challenge25(): with open('25.txt') as file: plaintexts = [base64.b64decode(line.strip().encode()) for line in file] for plaintext in plaintexts: ciphertext = set3.aes_ctr(plaintext, constants.key) assert set4.challenge25(ciphertext) == plaintext
def test_challenge18(): ct = b'L77na/nrFsKvynd6HzOoG7GHTLXsTVu9qvY/2syLXzhPweyyMTJULu/6/kXX0KSvoOLSFQ==' result = set3.aes_ctr(base64.b64decode(ct), b'YELLOW SUBMARINE') assert result == b"Yo, VIP Let's kick it Ice, Ice, baby Ice, Ice, baby "