def encrypt_aes_128_cbc(key, iv, plainbuf): block_size = 16 if len(key) != 16: print "key must be 16 bytes long" return if len(iv) != block_size: print "iv must be %d bytes long" % block_size return encbuf = [] last_enc_block = iv for i in range(0, len(plainbuf), block_size): plain_block = plainbuf[i:i + block_size] if len(plain_block) != block_size: print "plain_block requires %d bytes of padding" % ( block_size - len(plain_block)) return round1 = challenge5.repeating_xor(plain_block, last_enc_block) aes = AES.new(key) enc_block = aes.encrypt(round1) encbuf.append(enc_block) last_enc_block = enc_block encbuf = "".join(encbuf) return encbuf
def print_plaintexts(ciphertexts, key_stream, marker=None): plaintexts = [] for i, ciphertext in enumerate(ciphertexts): plaintext = challenge5.repeating_xor(ciphertext, key_stream) plaintexts.append(plaintext) if marker is not None: plaintext = plaintext[:marker] + "|||" + plaintext[marker:] print "%d: %s" % (i, repr(plaintext)) return plaintexts
def aes_cbc_decrypt(key, iv, stream): fail_msg = "stream should be a multiple of %d, size actually: %d" \ % (BLOCK_SIZE_IN_BYTES, len(stream)) assert len(stream) % BLOCK_SIZE_IN_BYTES == 0, fail_msg blocks = block_split(stream) last_block = None result = [] for idx, ct_block in enumerate(blocks): if idx == 0: last_block = iv pt_block = repeating_xor(last_block, aes_ecb_decrypt(key, ct_block)) last_block = ct_block result.append(pt_block) return bytes().join(result)
def aes_cbc_encrypt(key, iv, stream): fail_msg = "stream should be a multiple of %d, size actually: %d" \ % (BLOCK_SIZE_IN_BYTES, len(stream)) assert len(stream) % BLOCK_SIZE_IN_BYTES == 0, fail_msg blocks = block_split(stream) result = [] for idx, pt_block in enumerate(blocks): last_block = iv if idx == 0 else result[-1] # pad block if its too small... # TODO: should only be needed on the last block if len(pt_block) < BLOCK_SIZE_IN_BYTES: pt_block = pkcs7_pad(pt_block, BLOCK_SIZE_IN_BYTES) ct_block = aes_ecb_encrypt(key, repeating_xor(last_block, pt_block)) result.append(ct_block) return bytes().join(result)
def break_vigenere(x): # find the key size by taking the minimum edit distance edit_dsts = [] for key_sz in KEY_SZS: ct_chunks = chunk(x, key_sz) paired_ct_chunks = [(ct_chunks[i], ct_chunks[i + 1]) for i in range(0, len(ct_chunks), 2) if i + 1 < len(ct_chunks)] edit_dst = 0.0 for x_1, x_2 in paired_ct_chunks: edit_dst += float(edit_dist(x_1, x_2)) / key_sz edit_dst = edit_dst / len(paired_ct_chunks) edit_dsts.append(edit_dst) min_edit_dst = min(edit_dsts) guessed_key_sz = KEY_SZS[edit_dsts.index(min_edit_dst)] print(f"[*] Guessed key size: {guessed_key_sz}") ct_chunks = chunk(x, guessed_key_sz) # transpose the blocks ct_chunks_t = transpose_blks(ct_chunks) # solve each block as a single-character XOR key = bytearray([]) for ct_chunk_t in ct_chunks_t: c, _ = bruteforce_single_byte(bytes_to_hex(ct_chunk_t)) key += bytearray([ord(c)]) # get the key print(f"[*] Key found: {key}") # get the plaintext (hopefully!) pt_hex = repeating_xor(x, key) pt = hex_to_bytearray(pt_hex) return key, pt
def decrypt_message() -> None: decrypt_key = get_decrypt_key() message = repeating_xor(cipher, decrypt_key) print(message.decode())
import challenge18 def get_ciphertexts(plaintexts): rand_key = challenge11.get_rand_bytes(16) ciphertexts = [] for plaintext in plaintexts: aes_128_ctr = challenge18.AES128CTR(key=rand_key, nonce=0, counter=0) ciphertext = aes_128_ctr.crypt(base64.b64decode(plaintext)) ciphertexts.append(ciphertext) return ciphertexts if __name__ == "__main__": fp = open("20.txt", "rb") lines = fp.readlines() fp.close() lines = [l.strip() for l in lines] ciphertexts = get_ciphertexts(lines) smallest_len = min([len(c) for c in ciphertexts]) truncated_ciphertexts = [c[:smallest_len] for c in ciphertexts] concatenated_ciphertexts = "".join(truncated_ciphertexts) key = challenge6.get_probable_key(concatenated_ciphertexts, smallest_len, smallest_len+1) concatenated_plaintexts = challenge5.repeating_xor(concatenated_ciphertexts, key) print concatenated_plaintexts
if score >= high_score: high_score = score single_byte_key = test_key probable_key.append(chr(single_byte_key)) probable_key = "".join(probable_key) print "probable key: %s" % repr(probable_key) return probable_key if __name__ == "__main__": # test hamming_distance if hamming_distance("this is a test", "wokka wokka!!!") != 37: print "bad hamming distance func" sys.exit(1) # break repeating xor key fp = open("6.txt", "rb") data = fp.read() fp.close() data = data.strip("\n") round1 = base64.b64decode(data) key = get_probable_key(round1, 2, 41) print print challenge5.repeating_xor(round1, key)