コード例 #1
0
def test_aes_cbc_encrypt():
    key = "YELLOW SUBMARINE".encode("utf-8")
    plaintext = "test".encode("utf-8")
    iv = bytes([0]) * BLOCK_SIZE

    ciphertext = aes_cbc_encrypt(key, plaintext, iv, BLOCK_SIZE)

    computed_plaintext = aes_cbc_decrypt(key, ciphertext, iv, BLOCK_SIZE)

    assert plaintext == computed_plaintext
コード例 #2
0
 def decrypt(self, ciphertext, iv, blocksize=16) -> bool:
     plaintext = block.aes_cbc_decrypt(ciphertext,
                                       self.key,
                                       iv,
                                       remove_padding=False)
     padding_char = plaintext[-1]
     if padding_char > blocksize or padding_char < 1:
         return False
     for i in range(padding_char):
         if plaintext[-i - 1] != padding_char:
             return False
     return True
コード例 #3
0
def test_cbc_recover_key_with_iv_eq_key():
    # Set 4, challenge 27: Recover the key from CBC with IV=Key
    key = gen_random_block()
    plaintext = "comment1=cooking%20MCs;userdata=1234567890123456"

    # Verify each byte of the plaintext for ASCII compliance
    # (ie, look for high-ASCII values). Noncompliant messages
    # should raise an exception or return an error that includes
    # the decrypted plaintext.
    def verify_plaintext(plaintext: bytes):
        # Check for high-ASCII (bytes 127 or higher)
        for b in plaintext:
            assert b in range(32, 126)

    verify_plaintext(plaintext.encode("utf8"))
    ciphertext = aes_cbc_encrypt(key, plaintext.encode("utf8"), key)
    block_1 = ciphertext[:BLOCK_SIZE]
    block_4 = ciphertext[BLOCK_SIZE * 3:]
    all_zero = b"\x00" * BLOCK_SIZE

    # Modify the message (you are now the attacker):
    # C_1, C_2, C_3 -> C_1, 0, C_1
    new_ciphertext = block_1 + all_zero + block_1 + block_4

    # This will raise BadPaddingValidation on block_4
    decrypted_plaintext = aes_cbc_decrypt(key,
                                          new_ciphertext,
                                          key,
                                          remove_padding=False)
    try:
        verify_plaintext(decrypted_plaintext)
    except AssertionError:  # And this will happen as the attacker tampered with the ciphertext!
        pass

    # As the attacker, recovering the plaintext from the error, extract the key
    # P'_1 XOR P'_3

    p_1_prime = decrypted_plaintext[:BLOCK_SIZE]
    p_3_prime = decrypted_plaintext[BLOCK_SIZE * 2:BLOCK_SIZE * 3]
    reconstructed_key = b""
    for x, y in zip(p_1_prime, p_3_prime):
        byte = bytes([x ^ y])
        reconstructed_key += byte

    # Check we reconstructed the key successfully
    for x, y in zip(key, reconstructed_key):
        assert x == y
コード例 #4
0
def test_cbc_bitflip_attack():
    # Set 2, challenge 16 CBC Bitflipping
    # Note: I did this assuming the prepended text was known by the attacker.

    block_size = BLOCK_SIZE
    key = gen_random_block()
    iv = gen_random_block()

    prepend = "comment1=cooking%20MCs;userdata="
    append = ";comment2=%20like%20a%20pound%20of%20bacon"

    # Make sure ; and = are quoted
    # Selecting user controlled value exactly twice the target text
    plaintext = "123456789012123456789012".replace(";", "").replace("=", "")
    full_plaintext = prepend + plaintext + append
    ciphertext = cbc_encrypt_prepend_and_append(
        key,
        iv,
        plaintext.encode("utf-8"),
        append.encode("utf-8"),
        prepend.encode("utf-8"),
    )

    modified_ciphertext = b""
    target_text = ";admin=true;"
    edit_start_position = 0
    edit_stop_position = len(target_text)

    # Now tweak the bytes in the first ciphertext (comment field) such that the change
    # is introduced in the second plaintext.
    for ind, by in enumerate(ciphertext):
        if ind in range(edit_start_position, edit_stop_position):
            new_value = bytes([
                int.from_bytes(
                    target_text[edit_start_position + ind].encode("utf-8"),
                    "big") ^ ciphertext[ind]
                ^ int.from_bytes(
                    full_plaintext[ind + block_size].encode("utf-8"), "big")
            ])

            modified_ciphertext = modified_ciphertext + new_value
        else:
            modified_ciphertext = modified_ciphertext + bytes([by])

    decrypted_plaintext = aes_cbc_decrypt(key, modified_ciphertext, iv)

    assert target_text.encode("utf-8") in decrypted_plaintext
コード例 #5
0
def test_aes_cbc_decrypt():
    # Set 2, challenge 10: Implement CBC mode

    path_to_data = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                "data/10.txt")

    with open(path_to_data, "r") as f:
        base64_ciphertext = f.read()

    ciphertext = base64_to_bytes(base64_ciphertext)

    key = "YELLOW SUBMARINE".encode("utf-8")

    iv = bytes([0]) * BLOCK_SIZE

    plaintext = aes_cbc_decrypt(key, ciphertext, iv, remove_padding=False)

    assert "Vanilla's on the mike, man I'm not lazy." in plaintext.decode(
        "utf-8")
    assert "I'm back and I'm ringin' the bell" in plaintext.decode("utf-8")
コード例 #6
0
def bitflipping_oracle_decrypt(ciphertext, aes_key, iv: bytes) -> bool:
    plaintext = block.aes_cbc_decrypt(ciphertext, aes_key, iv)
    print(plaintext)
    return b';admin=true;' in plaintext
コード例 #7
0
from cryptopals import block
import base64

BLOCK_SIZE = 16

if __name__ == '__main__':
    with open('./10.txt') as f:
        ciphertext = base64.b64decode(f.read())
    key = b'YELLOW SUBMARINE'
    iv = b'\x00' * BLOCK_SIZE
    plaintext = block.aes_cbc_decrypt(ciphertext, key, iv, remove_padding=True)
    print(plaintext.decode())

    # We'll silently test to make sure encryption works correctly too.
    candidate_ciphertext = block.aes_cbc_encrypt(plaintext, key, iv)
    if candidate_ciphertext != ciphertext:
        print('Encryption is not working correctly.')