def modified_xor_brute(ciphertext): """ Bruteforce XOR keys to decrypt ciphertext We assume the plaintext is english text """ MAX_BYTE = 2**8 - 1 decryptions = [] for key in range(MAX_BYTE): key_extended = bytearray([key] * len(ciphertext)) try: plaintext = binascii.unhexlify(xor(ciphertext, key_extended)).decode('utf-8') except UnicodeDecodeError: continue else: if not is_printable(plaintext): continue # Due to the limitations of ChiSquared we need to make the plaintext uppercase and without whitespace + punctuation score = ChiSquared(frequency.english.unigrams)(remove( plaintext, string.whitespace + string.punctuation).upper()) decryption = Decryption(plaintext, key, score) # This is a (flaw?) in lantern that punct + whitespace is removed when scoring, however because the score # calculation is based on length, this means that incorrect strings full of punctuation can out score # correct decryptions with mostly letters. Therefore, we modify the score by how many characters were # removed during scoring. I should probably fix this in latern decryption.score /= len( remove(plaintext, string.whitespace + string.punctuation)) / len(plaintext) decryptions.append(decryption) return sorted(decryptions, reverse=True)
def repeating_xor(x, k): len_x = len(x) len_k = len(k) key = ba(k * math.ceil(float(len_x) / len_k)) x = ba(x) return bytes_to_hex(ba(xor(x, key)))
def _score_key(byte_string, key): dif_score = 0 xored = xor(byte_string, binascii.b2a_hex(key)) rel_freqs = get_char_freqs(xored) for k in rel_freqs.keys(): dif_score += abs(rel_freqs[k]-REL_ENG_CHAR_FREQS[k])**2 return dif_score
def aes_cbc_decrypt(ct, key, iv): ct_chunks = chunk(ct, BLK_SZ) ct_chunks.insert(0, iv) pt = [] for i in range(len(ct_chunks) - 1): # get ct block ct_blk = ct_chunks[i + 1] # decrypt dct_blk = decrypt_aes_ecb(ct_blk, key) # prev blk prev_blk = ct_chunks[i] # xor with previous block pt_blk = xor(dct_blk, prev_blk) # append to pt pt.append(pt_blk) pt_s = functools.reduce(lambda a, b: a + b, pt) # unpad return pkcs7_unpad(pt_s)
def vigenereCipher(msg, key): if type(msg) != bytes: raise TypeError("message defined as bytes not %s" %type(msg)) n = len(msg) KEY = KeyExpansion(key, n) return xor(msg, KEY)
def guess_single_key(encrypted_bytes): best_score = 0 best_key = None for n in range(255): this_score = score(xor(encrypted_bytes, [n])) if this_score > best_score: best_score = this_score best_key = chr(n) return best_key
def break_repkey_xor(ciphertext): """ :param ciphertext: ciphertext as bytes encrypted with repeating key xor :return: decrypted ciphertext as bytes """ smallest = determine_keysize(ciphertext) keysize = smallest[1] key = determine_key(keysize, ciphertext) return challenge2.xor(ciphertext, key), key
def bruteforce_single_byte(x): x = hex_to_bytearray(x) len_x = len(x) results = [] for i in range(256): test = bytearray([i for _ in range(len_x)]) xored_str = xor(x, test) try: xored_str = xored_str.decode('utf-8') except: results.append(100 * len(x)) continue test_score = l1_english_dist(xored_str) results.append(test_score) min_result = min(results) min_char_idx = results.index(min_result) min_char = chr(min_char_idx) return min_char, xor(x, bytearray([min_char_idx for _ in range(len_x)]))
def encrypt(self, msg): n = self._blocksize count = self._count ciphertext = b"" blocks = [msg[i:i + n] for i in range(0, len(msg), n)] for b in blocks: form = struct.pack("Q", self._nonce) + struct.pack("Q", count) print("ALGORITHM", form) keystream = self._cipher.encrypt(form) if self._inc: count += 1 if len(b) % n == 0: ciphertext += challenge2.xor(keystream, b) else: end = len(b) ciphertext += challenge2.xor(keystream[:end], b) return ciphertext
def cbc_dec(ciphertext, iv, key): blocksize = 16 if len(iv) != blocksize: raise ValueError plaintext = b"" prevBlock = iv for i in range(0, len(ciphertext), blocksize): decBlock = aes128ecb_dec(ciphertext[i:i + blocksize], key) plaintext += xor(prevBlock, decBlock) prevBlock = ciphertext[i:i + blocksize] return plaintext
def cbc_encrypt(message: bytes, key: bytes, iv: bytes, block_size: int = 16) -> bytes: assert len(message) % block_size == 0 blocks = [ message[x:x + block_size] for x in range(0, len(message), block_size) ] cipher = b"" for block in blocks: intermediate = xor(block, iv) cipher_block = ecb_encrypt(intermediate, key) cipher += cipher_block iv = cipher_block return cipher
def hit(linebytes): """ :param linebytes: hex string to brute force :return: best brute force hit """ best = (0.000, b'', b'') # (score, text, key) for i in range(255): xord = challenge2.xor(linebytes, [i]) score = etaoin_shrdlu(xord) if best[0] < score: best = (score, xord, i) return best
def cbc_enc(inputBytes, iv, key): blocksize = 16 if len(iv) != blocksize: raise ValueError ciphertext = b"" prevBlock = iv for i in range(0, len(inputBytes), blocksize): nextBlock = inputBytes[i:i + blocksize] a = xor(nextBlock, prevBlock) print(a) prevBlock = aes128ecb_enc(a, key) ciphertext += prevBlock return ciphertext
def freq_analysis_get_key(ciphertext): scores = {} for k in all_possible_keys: kstr = k*(len(ciphertext)//2) plaintext_candidate = xor(kstr, ciphertext) pc_chunked = [plaintext_candidate[i:i+2] for i in range(0, len(plaintext_candidate), 2)] score = score_chunk(pc_chunked) scores[k] = score lowest_score = sys.maxsize lowest_key = "" for k,v in scores.items(): if float(v) < lowest_score: lowest_key = k lowest_score = v return lowest_key, lowest_score
def cbc_decrypt(cipher_text: bytes, key: bytes, iv: bytes, block_size: int = 16) -> bytes: assert len(cipher_text) % block_size == 0 blocks = [ cipher_text[x:x + block_size] for x in range(0, len(cipher_text), block_size) ] message = b"" for block in blocks: intermediate = ecb_decrypt(block, key) plain = xor(intermediate, iv) iv = block message += plain return message
def main(): BLOCK = 3 key = os.urandom(16) oracle = AsciiOracle(key) # assume we know the oracle will add these to our text prefix = b"userdata=" postfix = b";comment2=bacon" """ ATTACK """ pad = BLOCK * 16 - (len(prefix) + len(postfix)) message = b"A" * (pad - 1) # subtract one to prevent extra padding ciphertext = oracle.encrypt(message) c0 = ciphertext[:16] dummytext = c0 + b"\x00" * 16 + c0 corrupt = oracle.decrypt(dummytext) iv = challenge2.xor(corrupt[:16], corrupt[-16:]) print("[*] Recovered key:", binascii.hexlify(iv))
def aes_cbc_encrypt(pt, key, iv): # pad if needed pt_padded = pkcs7_pad(pt, BLK_SZ) pt_chunks = chunk(pt_padded, BLK_SZ) prev_blk = iv ct_blks = [] for pt_blk in pt_chunks: # xor with prev blk pt_xored = xor(prev_blk, pt_blk) # ECB encrypt ct_blk = encrypt_aes_ecb(pt_xored, key) ct_blks.append(ct_blk) # store as prev blk prev_blk = ct_blk ct_s = functools.reduce(lambda a, b: a + b, ct_blks) return ct_s
def breakSingleXOR(ciphertext): msg = "" highScore = -1 k = -1 n = len(ciphertext) # possible = [] for key in range(256): KEY = KeyExpansion(chr(key).encode(), n) plaintext = xor(ciphertext, KEY).decode(errors="ignore") # possible.append(plaintext) try: if plaintext[0] in "ABCDEFGHIJKLMNOPQRSTUVWXYZ": score = commonLetterScore(plaintext) if score > highScore: highScore = score msg = plaintext k = chr(key) except: pass return (msg, k, highScore)
from binascii import hexlify from itertools import cycle import challenge2 important_work = b"""Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal""" key = b'ICE' should_come_to = '0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f' assert hexlify(challenge2.xor(important_work, key)).decode() == should_come_to
def encrypt_rep_xor(plaintext, key): key_to_use = extend_key(plaintext,key) chunked_pt = [hex(ord(a))[2:4] if len(hex(ord(a))[2:4]) == 2 else "0"+hex(ord(a))[2:4] for a in plaintext] chunked_key = [hex(ord(k))[2:4] for k in key_to_use] encrypted = xor("".join(chunked_key), "".join(chunked_pt)) return encrypted