Example #1
0
def break_cbc_single_blk(
        cipher_blk1: bytes,
        cipher_blk2: bytes,
        padding_oracle: Callable[[bytes, bytes], bool]) \
        -> bytes:
    """
    params:
        cipher_blk1: encrypted block prior to `cipher_blk2` or IV if
                     `cipher_blk2` was the first encrypted block
        cipher_blk2: block to be decrypted
        padding_oracle: `valid_padding()`
    returns:
        decryption of `cipher_blk2`
    """
    intermediate_blk2 = b''
    plain_blk2 = b''

    for i in range(1, 17):
        target_byte = i.to_bytes(1, byteorder=sys.byteorder)
        atk_blk_prefix = rand_bytes_gen(16 - i)
        atk_blk_suffix = b''
        for k in range(len(intermediate_blk2)):
            atk_blk_suffix += xor(target_byte,
                                  get_byte_n(intermediate_blk2, k))
        for j in range(256):
            atk_byte = j.to_bytes(1, byteorder=sys.byteorder)
            if valid_padding(cipher_blk2,
                             atk_blk_prefix + atk_byte + atk_blk_suffix):
                break
        intermediate_blk2 = xor(atk_byte, target_byte) + intermediate_blk2
        plain_blk2 = xor(intermediate_blk2, get_byte_n(cipher_blk1,
                                                       -i)) + plain_blk2

    return plain_blk2
Example #2
0
def recover_key(ciphertext: bytes,
                ascii_oracle: Callable[[bytes], None],
                blksize: int = 16) \
                -> bytes:
    """
    params:
        ciphertext: encrypted using `encryption_method()` must be at least
                    three blocks long
        ascii_oracle: `validate_ascii()`
        blksize: blocksize used by encryption
    returns:
        key used by encryption, or None if less than three bytes were given
    """
    ciphertext_blocks = [block for block in blocks(ciphertext, blksize)]
    if len(ciphertext_blocks) < 3:
        return None

    # append last two blocks to maintain valid padding
    attack_ciphertext = ciphertext_blocks[0] + bytes(blksize) + \
        ciphertext_blocks[0] + ciphertext_blocks[-2] + ciphertext_blocks[-1]

    decrypted = ascii_oracle(attack_ciphertext)
    if decrypted:
        return xor(get_block_n(decrypted, blksize, 0),
                   get_block_n(decrypted, blksize, 2))
    return None
Example #3
0
    def test_xor_bytes_of_different_length_only_xors_up_to_smallest_length(
            self):
        bytes1 = b'\xD4\x1D\x28'
        bytes2 = b'\x9C\x78\x51'
        expected_bytes = b'Hey'

        actual_bytes = xor(bytes1, bytes2)

        self.assertEqual(expected_bytes, actual_bytes)
Example #4
0
    def test_xor_cryptopals_case(self):
        hex1 = '1c0111001f010100061a024b53535009181c'
        bytes1 = bytes.fromhex(hex1)
        hex2 = '686974207468652062756c6c277320657965'
        bytes2 = bytes.fromhex(hex2)
        expected_hex = '746865206b696420646f6e277420706c6179'
        expected_bytes = bytes.fromhex(expected_hex)

        actual_bytes = xor(bytes1, bytes2)

        self.assertEqual(expected_bytes, actual_bytes)
Example #5
0
def break_rand_access_ctr(
        ciphertext: bytes,
        edit_oracle: Callable[[bytes, int, bytes], bytes]) \
        -> bytes:
    """
    params:
        ciphertext: encrypted using AES-128
        edit_oracle: `edit_oracle()` from `gen_edit_oracle()`
    returns:
        plaintext
    """
    key_cipher = bytes(len(ciphertext))
    key_cipher = edit_oracle(ciphertext, 0, key_cipher)[:len(key_cipher)]
    return xor(ciphertext, key_cipher)
Example #6
0
def main():
    """
    encrypt base64 encoded strings from file with consistent nonce
    break decryption by using `break_repeat_xor()` to get as much of the key
    as possible
    fix key by XORing encrypted messages with the decryption that has been made
    apparent
    """
    encrypted_lines = []
    key = b"YELLOW SUBMARINE"
    nonce = bytes(8)

    input_filename = os.path.join(pathlib.Path(__file__).parent, "input")
    with open(input_filename, "r") as input_file:
        for line in input_file:
            encrypted_lines.append(ctr_encrypt_b64(line, key, nonce))

    repeat_xor_cipher = b''
    blksize = 31
    for line in encrypted_lines:
        if len(line) >= blksize:
            repeat_xor_cipher += line[:blksize]

    res = break_repeat_xor(repeat_xor_cipher, blksize)
    key = res["key"]

    max_len = max([len(line) for line in encrypted_lines])

    key = xor(b"I have met them at close of day", encrypted_lines[0])
    key += bytes(max_len - len(key))
    key = xor(b"I have passed with a nod of the head", encrypted_lines[4])
    key += bytes(max_len - len(key))
    key = xor(b"He, too, has been changed in his turn,", encrypted_lines[37])
    key += bytes(max_len - len(key))

    for line in encrypted_lines:
        print(xor(key, line).decode())
Example #7
0
def main():
    """
    insert ";admin=true;" string inside encrypted message using only
    `encryption_oracle()`
    """
    encryption_oracle = gen_encryption_oracle()

    # `encryption_oracle()` prepends exactly two blocks
    # add two blocks of our own, the first block will be used to mutate the
    # second one to our desired string
    plain2 = bytes(16)
    plain3 = bytes(16)
    hack_enc = encryption_oracle(plain2 + plain3)
    hack_enc_blocks = [b for b in blocks(hack_enc, 16)]

    # knowing the blocks that are getting encrypted (we just picked them above)
    # we can figure out the AES decryption of the second block we added
    decrypted_block3 = xor(hack_enc_blocks[2], plain3)

    # the AES decryption of our block will get XORed with the previous block
    # (i.e. the first block we added)
    # simply XOR decrypted and desired to figure out what first block we need
    # to use to mutate the second block as desired
    desired_block = b"\x00\x00\x00\x00;admin=true;"
    encrypted2 = xor(decrypted_block3, desired_block)

    # remix the encrypted message by replacing the encrypted block of the first
    # block we added with the block that will give us the required mutation
    # all other blocks can remain the same as changing one block will only
    # mutate the decryption of the next one and won't change the ones further
    # down (i.e. not risk of ruining the padding down the line)
    encrypted = hack_enc_blocks[0] + hack_enc_blocks[1] + encrypted2
    for i in range(3, len(hack_enc_blocks)):
        encrypted += hack_enc_blocks[i]

    print(is_admin(encrypted))
Example #8
0
    def encrypt(self: CTRMode, plaintext: bytes) -> bytes:
        """
        Use cipher to encrypt combination of nonce and block counter,
        then XORs the result with the block
        """
        ciphertext = b''

        i = 0
        for blk_count in self.counter():
            curr_blk = get_block_n(plaintext, self.blksize, i)
            if curr_blk == b'':
                break
            counter_blk = self.combine(self.nonce, blk_count, self.blksize)
            ciphertext += xor(curr_blk, self.encrypt_blk(counter_blk))
            i += 1

        return ciphertext
Example #9
0
def single_xor(b: bytes, s: bytes) -> bytes:
    """
    params:
        b: bytes to be XORed
        s: single byte used for encryption
    returns:
        result of XORing every byte of `b` with `s`
        if `s` is more than one byte, only first byte is used
    raises:
        TypeError if `b` is None
    """
    if not s:
        return b

    operand = b''
    for i in range(len(b)):
        operand += s[0].to_bytes(1, byteorder=sys.byteorder)
    return xor(b, operand)
Example #10
0
def repeat_xor(b: bytes, key: bytes) -> bytes:
    """
    params:
        b: bytes to be XORed
        key: key used for encryption
    returns:
        result of XORing bytes of `b` with bytes of `key` by cycling through
        the `key`
    """
    if not key:
        return b

    operand = b''
    j = 0
    key_len = len(key)
    for i in range(len(b)):
        operand += key[j].to_bytes(1, byteorder=sys.byteorder)
        j = (j + 1) % key_len
    return xor(b, operand)
Example #11
0
    def decrypt(self: CBCMode, ciphertext: bytes) -> bytes:
        """
        decrypts each block, then XORs with cipher of the previous block
        (or IV if first block)
        raises:
            ValueError: if size of `plaintext` is not divisible by
                        `self.blksize`
        """
        if len(ciphertext) % self.blksize != 0:
            raise ValueError("ciphertext is not %s-bit padded" % self.blksize)

        plaintext = b''

        prev_cipherblk = self.iv
        for block in blocks(ciphertext, self.blksize):
            plaintext += xor(self.decrypt_blk(block), prev_cipherblk)
            prev_cipherblk = block

        return plaintext
Example #12
0
    def encrypt(self: CBCMode, plaintext: bytes) -> bytes:
        """
        XORs each block with the cipher of the previous block (or the IV if
        first block), then encrypts
        raises:
            ValueError: if size of `plaintext` is not divisible by
                        `self.blksize`
        """
        if len(plaintext) % self.blksize != 0:
            raise ValueError("plaintext is not %s-bit padded" % self.blksize)

        ciphertext = b''

        prev_cipherblk = self.iv
        for block in blocks(plaintext, self.blksize):
            prev_cipherblk = self.encrypt_blk(xor(block, prev_cipherblk))
            ciphertext += prev_cipherblk

        return ciphertext
Example #13
0
def main():
    """
    insert ";admin=true;" string inside encrypted message using only
    `encryption_oracle()`
    """
    encryption_oracle = gen_encryption_oracle()

    desired_plaintext = b";admin=true;"

    # `encryption_oracle()` prepends exactly two blocks
    # feed some zeroes to figure out the key-cipher for the third block
    encrypted = encryption_oracle(bytes(len(desired_plaintext)))
    keycipher_block3 = get_block_n(encrypted, 16, 2)

    # knowing the key cipher it's easy to figure out what input we should feed
    # to get the decryption we desire
    attack_block = xor(desired_plaintext, keycipher_block3)

    attack_encrypted = encrypted[:32] + attack_block + \
        encrypted[32+len(desired_plaintext):]

    print(is_admin(attack_encrypted))
Example #14
0
 def test_xor_none_input_raises_typeerror(self):
     with self.assertRaises(TypeError):
         xor(None, None)
Example #15
0
def main():
    """
    encrypt base64 encoded strings from file with consistent nonce
    break decryption by using `break_repeat_xor()` to get as much of the key
    as possible
    fix key by XORing encrypted messages with the decryption that has been made
    apparent
    """
    encrypted_lines = []
    key = b"YELLOW SUBMARINE"
    nonce = bytes(8)

    input_filename = os.path.join(pathlib.Path(__file__).parent, "input")
    with open(input_filename, "r") as input_file:
        for line in input_file:
            encrypted_lines.append(ctr_encrypt_b64(line, key, nonce))

    repeat_xor_cipher = b''

    longest_line = max(encrypted_lines, key=len)
    blksize = len(longest_line)
    for line in encrypted_lines:
        repeat_xor_cipher += line + longest_line[len(line):]

    res = break_repeat_xor(repeat_xor_cipher, blksize)
    key = res["key"]

    key = xor(
        (b'I\'m rated "R"...this is a warning, ya better void / Poets are '
         b'paranoid, DJ<s/D-s\';;y\'%................................'),
        encrypted_lines[0])
    key += bytes(blksize - len(key))
    key = xor((b"Worse than a nightmare, you don't have to sleep a wink / "
               b"The pain's a migraine e%,&yb5...................."),
              encrypted_lines[12])
    key += bytes(blksize - len(key))
    key = xor(
        (b"Cuz I came back to attack others in spite- / Strike like lightnin',"
         b" It's quite frighteningv..........................."),
        encrypted_lines[1])
    key += bytes(blksize - len(key))
    key = xor(
        (b"The fiend of a rhyme on the mic that you know / It's only one "
         b"capable, breaks-the unbreakable......................."),
        encrypted_lines[17])
    key += bytes(blksize - len(key))
    key = xor(
        (b"For those that oppose to be level or next to this / I ain't a devil"
         b" and this ain't the Exorcist...................."),
        encrypted_lines[11])
    key += bytes(blksize - len(key))
    key = xor(
        (b"Worse than a nightmare, you don't have to sleep a wink / The pain's"
         b" a migraine every time ya think.................."),
        encrypted_lines[12])
    key += bytes(blksize - len(key))
    key = xor(
        (b'You want to hear some sounds that not only pounds but please your '
         b'eardrums; / I sit back and observe the whole s'
         b'cenery'), encrypted_lines[26])
    key += bytes(blksize - len(key))

    for i, line in enumerate(encrypted_lines):
        print(xor(key, line).decode())
Example #16
0
 def mock_fun(self, b: bytes) -> bytes:
     operand = b''
     for i in range(len(b)):
         operand += i.to_bytes(1, byteorder=sys.byteorder)
     return xor(b, operand)
Example #17
0
 def test_xor_empty_input_returns_empty_bytes(self):
     self.assertEqual(xor(b'', b''), b'')