def byte_ecb_decrypt_hard(): output_dict = {} unknown = b'' while unknown == b'' or unknown[-1] != 1: pre, block_num = prepend_hard(unknown) for i in range(128): single_chr = bytes(chr(i), 'ascii') pt = pre + unknown + single_chr ct = list(set1_ch6.chunks(byte_ecb_encrypt_hard(pt, key), block_size))[block_num] output_dict[ct] = single_chr single_block = list(set1_ch6.chunks(byte_ecb_encrypt_hard(pre, key), block_size)) unknown += output_dict[single_block[block_num]] return unknown[:-1]
def byte_ecb_decrypt(): output_dict = {} # dictionary holding blocks with shortened byte and character unknown = b'' # uncovered secret string while unknown == b'' or unknown[-1] != 1: pre, block_num = prepend(unknown) for i in range(128): # every possible ascii character single_chr = bytes(chr(i), 'ascii') pt = pre + unknown + single_chr ct = list(set1_ch6.chunks(byte_ecb_encrypt(pt, key), block_size))[block_num] output_dict[ct] = single_chr # find matching chunk single_block = list(set1_ch6.chunks(byte_ecb_encrypt(pre, key), block_size)) unknown += output_dict[single_block[block_num]] return unknown[:-1]
def modify_ciphertext(encrypted): blocks = list(set1_ch6.chunks(encrypted, 16)) prev_block = list(blocks[1]) prev_block[4] ^= 1 # bit flip to make ';' prev_block[10] ^= 1 # bit flip to make '=' blocks[1] = bytes(prev_block) encrypted2 = b''.join(blocks) return encrypted2
def detect_prefix_len(): counter = 0 cipher = byte_ecb_encrypt_hard(b'A' * (counter + 32), key) blocks = list(set1_ch6.chunks(cipher, 16)) init_repeat = repeats = len(blocks) - len(set(blocks)) # increment num A's until there are duplicate ciphertext blocks while (init_repeat == repeats): counter += 1 cipher = byte_ecb_encrypt_hard(b'A' * (counter + 32), key) blocks = list(set1_ch6.chunks(cipher, 16)) repeats = len(blocks) - len(set(blocks)) # find which blocks are repeated repeat_block = 0 while repeat_block < len(blocks)-1 and blocks[repeat_block] != blocks[repeat_block+1]: repeat_block += 1 # return number of extra A's, and which block is repeated return counter, repeat_block
def detect_ECB(filename): unique = [] content = [] with open(filename, "rb") as file: for line in file: content.append(line) chunked = list(set1_ch6.chunks(line, 16)) unique.append(len(Counter(chunked))) # number of unique chunks AES_encrypted = np.argmin(unique) return AES_encrypted, content[AES_encrypted]
def cbc_encrypt(key, plaintext, iv): plaintext = set2_ch9.padding(plaintext, 16) blocks = list(set1_ch6.chunks(plaintext, 16)) prev_encrypt = iv ciphertext = [] for b in blocks: xored = set1_ch2.xor(b, prev_encrypt) prev_encrypt = set1_ch7.encrypt(key, xored) ciphertext.append(prev_encrypt) return b"".join(ciphertext)
def cbc_decrypt_wo_unpad(key, ciphertext, iv): blocks = list(set1_ch6.chunks(ciphertext, 16)) prev_block = iv plaintext = [] for b in blocks: decrypted = set1_ch7.decrypt(key, b) plaintext.append(set1_ch2.xor(decrypted, prev_block)) prev_block = b joined = b"".join(plaintext) return joined
def exploit_cbc_oracle(iv, ciphertext): blocks = [iv] + list(set1_ch6.chunks(ciphertext, 16)) message = b'' # decrypted message we are uncovering # decrypt by block for b_num in range(len(blocks)-1): guessed = bytearray([0] * 16) # guessed characters # start from end of block for b in range(15, -1, -1): padding = bytearray([0] * 16) padding[b:16] = [16-b] * (16-b) # xor prev block, padding block, and guessed block modified = set1_ch2.xor(set1_ch2.xor(blocks[b_num], padding), guessed) # try every possible character until padding is valid for i in range(256): r = bytearray([0] * 16) r[b] = i xored = set1_ch2.xor(modified,r) if padding_oracle(xored + blocks[b_num+1]): if not (16-b == 1 and i == 1): # check special case of actual padding guessed[b] = i message += codecs.decode(guessed, 'base64') return message
def detect_cipher(ciphertext): blocks = list(set1_ch6.chunks(ciphertext, 16)) return "CBC" if len(set(blocks)) == len(blocks) else "EBC"