def encrypt_mt19937(seed, plaintext): assert (seed < 2**16) key_stream = bytearray() r = random(seed) while len(key_stream) < len(plaintext): key_stream.extend(int.to_bytes(r.random(), 4, byteorder='big')) return xor_bytes(plaintext, key_stream)
def main(): key = random_bytes(16) nonce = 0 with open("inpChall20.txt") as f: secrets = f.readlines() secrets = [b64decode(secret) for secret in secrets] expected = secrets secrets = [ctr_encrypt(key, nonce, secret) for secret in secrets] min_length = min(len(secret) for secret in secrets) truncated = [secret[:min_length] for secret in secrets] concatenated = b"".join(truncated) keys = rank_xor_repeating_keys(concatenated, min_length) # found through analysis key_indices = { 0: 3, } key = bytes([keys[i][key_indices.get(i, 0)] for i in range(len(keys))]) plaintexts = [xor_bytes(secret, key) for secret in secrets] for i in range(len(expected)): print(plaintexts[i]) assert (expected[i].startswith(plaintexts[i]))
def ctr_encrypt(key, nonce, plaintext): nonce = nonce.to_bytes(8, byteorder='little') keystream = bytes() block_count = 0 while len(keystream) < len(plaintext): block = nonce + block_count.to_bytes(8, byteorder='little') keystream += aes_encrypt_block(key, block) block_count += 1 return xor_bytes(plaintext, keystream)
def cbc_decrypt(key, iv, ciphertext): assert (len(iv) == 16) blocks = get_blocks(ciphertext) plaintext = bytearray() for block in blocks: decrypted = aes_decrypt_block(key, block) plaintext.extend(xor_bytes(iv, decrypted)) iv = block return unpad(bytes(plaintext))
def cbc_encrypt(key, iv, plaintext): assert (len(iv) == 16) blocks = get_blocks(pad(plaintext)) ciphertext = bytearray() for block in blocks: encrypted = aes_encrypt_block(key, xor_bytes(iv, block)) ciphertext.extend(encrypted) iv = encrypted return bytes(ciphertext)
assert("%61" == escape("=")) assert("%59" == escape(";")) assert("%37" == escape("%")) assert("a%61b" == escape("a=b")) assert("a%3761b" == escape("a%61b")) # unescape tests assert("=" == unescape("%61")) assert(";" == unescape("%59")) assert("%" == unescape("%37")) assert("a=b" == unescape("a%61b")) assert("a%61b" == unescape("a%3761b")) # is_admin tests assert(not is_admin(get_token("a"))) assert(not is_admin(get_token(";admin=true"))) target = ";admin=true;".encode('ascii') original = "a" * len(target) token = get_token(original) to_modify = token[len(token_prefix):len(token_prefix) + len(original)] keystream = xor_bytes(to_modify, original.encode('ascii')) crafted = xor_bytes(keystream, target) crafted_token = (token[:len(token_prefix)] + crafted + token[len(token_prefix) + len(crafted):]) assert(is_admin(crafted_token))
from xor import xor_bytes s1 = "1c0111001f010100061a024b53535009181c" s2 = "686974207468652062756c6c277320657965" b1 = bytes.fromhex(s1) b2 = bytes.fromhex(s2) expected = "746865206b696420646f6e277420706c6179" xored = xor_bytes(b1, b2) print(xored.hex()) assert (xored.hex() == expected)
# escape tests assert ("%61" == escape("=")) assert ("%59" == escape(";")) assert ("%37" == escape("%")) assert ("a%61b" == escape("a=b")) assert ("a%3761b" == escape("a%61b")) # unescape tests assert ("=" == unescape("%61")) assert (";" == unescape("%59")) assert ("%" == unescape("%37")) assert ("a=b" == unescape("a%61b")) assert ("a%61b" == unescape("a%3761b")) # is_admin tests assert (not is_admin(get_token("a"))) assert (not is_admin(get_token(";admin=true"))) target = ";admin=true;".encode('ascii') original = "a" * len(target) token = get_token(original) to_modify = token[len(token_prefix):len(token_prefix) + len(original)] keystream = xor_bytes(to_modify, original.encode('ascii')) crafted = xor_bytes(keystream, target) crafted_token = (token[:len(token_prefix)] + crafted + token[len(token_prefix) + len(crafted):]) assert (is_admin(crafted_token))
from aes import ctr_encrypt, ctr_decrypt from xor import xor_bytes def edit(ciphertext, key, offset, newtext): key, nonce = key plaintext = ctr_decrypt(key, nonce, ciphertext) plaintext = plaintext[:offset] + newtext + plaintext[offset + len(newtext):] return ctr_encrypt(key, nonce, plaintext) with open("25.txt") as f: # not sure what we mean by the recovered plaintext from the ECB exercice, # but let's assume that this is our plaintext... secret = b64decode(f.read()) key = urandom(16) nonce = int.from_bytes(urandom(8), byteorder='big') ciphertext = ctr_encrypt(key, nonce, secret) # could do block per block, but let's do it all at once... edited = edit(ciphertext, (key, nonce), 0, bytes([0] * len(ciphertext))) # 0 ^ keystream gives us our keystream! keystream = edited plaintext = xor_bytes(keystream, ciphertext) assert (plaintext == secret)
assert (";" == unescape("%59")) assert ("%" == unescape("%37")) assert ("a=b" == unescape("a%61b")) assert ("a%61b" == unescape("a%3761b")) # is_admin tests assert (not is_admin(get_token("a"))) assert (not is_admin(get_token(";admin=true"))) # get a normal token with a filled block, we'll end up with the following: # (prefix)... (input) ...(suffix) # (32 bytes) |-----block----| (the rest, not important) token = get_token("a" * 16) target = ";admin=true;abc=".encode('ascii') current_block = token[32:32 + 16] next_block_plain = ";comment2=%20lik".encode('ascii') # decryption does: plaintext = next_block_pre_xor ^ current_block next_block_pre_xor = xor_bytes(next_block_plain, current_block) # craft a block with the bitflips that we want to produce on the next block # we want to craft a current_block so that decryption does: # target = next_block_pre_xor ^ crafted_block # so we isolated current_block and get: crafted_block = xor_bytes(target, next_block_pre_xor) assert (len(crafted_block) == 16) crafted_token = token[:32] + crafted_block + token[32 + 16:] assert (is_admin(crafted_token))
# After sorting the key bytes by their best picks, what index should we pick? # By default, 0. If there's a value in this map, it was found through analysis # of the plaintexts. key_bytes_index = { 0: 1, 30: 1, 33: 4, 34: 7, 35: 11, 36: 9, 37: 212, } keystream = bytearray() while max(len(s) for s in secrets) > len(keystream): index = len(keystream) chars = [s[index] for s in secrets if len(s) > index] keys = rank_xor_char_keys(chars) key_byte_index = key_bytes_index.get(index, 0) key_byte = keys[key_byte_index] keystream.append(key_byte) plaintexts = [xor_bytes(secret, keystream) for secret in secrets] assert (len(plaintexts) == len(expected)) for i in range(len(expected)): print(plaintexts[i]) assert (plaintexts[i] == expected[i]) assert (plaintexts == expected)
from xor import xor_bytes, rank_xor_repeating_keys key = urandom(16) nonce = 0 with open("20.txt") as f: secrets = f.readlines() secrets = [b64decode(secret) for secret in secrets] expected = secrets secrets = [ctr_encrypt(key, nonce, secret) for secret in secrets] min_length = min(len(secret) for secret in secrets) truncated = [secret[:min_length] for secret in secrets] concatenated = b"".join(truncated) keys = rank_xor_repeating_keys(concatenated, min_length) # found through analysis key_indices = { 0: 3, } key = bytes([keys[i][key_indices.get(i, 0)] for i in range(len(keys))]) plaintexts = [xor_bytes(secret, key) for secret in secrets] for i in range(len(expected)): print(plaintexts[i]) assert(expected[i].startswith(plaintexts[i]))
from xor import xor_bytes s1 = "1c0111001f010100061a024b53535009181c" s2 = "686974207468652062756c6c277320657965" b1 = bytes.fromhex(s1) b2 = bytes.fromhex(s2) expected = "746865206b696420646f6e277420706c6179" xored = xor_bytes(b1, b2) print(xored.hex()) assert(xored.hex() == expected)
def main(): secrets = """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=""".split() secrets = [b64decode(secret) for secret in secrets] expected = secrets key = random_bytes(16) nonce = 0 secrets = [ctr_encrypt(key, nonce, secret) for secret in secrets] key_bytes_index = { 0: 1, 30: 1, 33: 4, 34: 7, 35: 11, 36: 9, 37: 212, } keystream = bytearray() while max(len(s) for s in secrets) > len(keystream): index = len(keystream) chars = [s[index] for s in secrets if len(s) > index] keys = rank_xor_char_keys(chars) key_byte_index = key_bytes_index.get(index, 0) key_byte = keys[key_byte_index] keystream.append(key_byte) plaintexts = [xor_bytes(secret, keystream) for secret in secrets] assert(len(plaintexts) == len(expected)) for i in range(len(expected)): print(plaintexts[i].decode()) assert(plaintexts[i] == expected[i]) assert(plaintexts == expected)
# By default, 0. If there's a value in this map, it was found through analysis # of the plaintexts. key_bytes_index = { 0: 1, 30: 1, 33: 4, 34: 7, 35: 11, 36: 9, 37: 212, } keystream = bytearray() while max(len(s) for s in secrets) > len(keystream): index = len(keystream) chars = [s[index] for s in secrets if len(s) > index] keys = rank_xor_char_keys(chars) key_byte_index = key_bytes_index.get(index, 0) key_byte = keys[key_byte_index] keystream.append(key_byte) plaintexts = [xor_bytes(secret, keystream) for secret in secrets] assert(len(plaintexts) == len(expected)) for i in range(len(expected)): print(plaintexts[i]) assert(plaintexts[i] == expected[i]) assert(plaintexts == expected)