Пример #1
0
def hmac_sha256(key, message):
    """
    Creates an HMAC using SHA-256.

    Args:
        key: The HMAC key.
        message: The message to generate the MAC for.

    Returns:
        The HMAC for the message under the given key
    """
    # If the key is longer than the blocksize,
    # then truncate it by hashing it
    if (len(key) > 64):
        key = sha256(key).digest()

    # If the key is shorter than blocksize,
    # pad with 0s
    if (len(key) < 64):
        key = key + (b'\x00' * (64 - len(key)))

    o_pad = c2.xorstrs(key, b'\x5c'*64)
    i_pad = c2.xorstrs(key, b'\x36'*64)
    i_msg = i_pad + message
    o_msg = o_pad + sha256(i_msg).digest()
    return sha256(o_msg).digest()
Пример #2
0
def attack_byte(block, prev_block, byte_num, plaintext):
    """
    Attacks a single byte using the padding oracle attack. This function
    contains the real magic for the attack.

    Args:
        block: The block of ciphertext that is being attacked.
        prev_block: The previous block of ciphertext used to attack the current one.
        byte_num: The byte number of the block that we are getting.
        plaintext: The known plaintext so far.

    Returns:
        The byte of decoded byte of plaintext

    Raises:
        RuntimeException if no byte can be found
    """
    # Knownxor is super tricky. Read the link from the readme.
    # We want all the last values to be good padding.
    # To do this we xor the prev_block with the known plaintext with
    # the value we want to get for padding.
    knownxor = b''
    if (len(plaintext) > 0):
        knownxor = c2.xorstrs(prev_block[-len(plaintext):], plaintext)
        knownxor = c2.xorstrs(bytes([16-byte_num] * len(plaintext)), knownxor)
    # Test each byte, returning when the padding is valid.
    for i in range(1, 256):
        bad_prev_b = bytes([0]) * byte_num
        # The magic here will only allow for valid padding when i is
        # the same as the value of the original plaintext.
        bad_prev_b += bytes([i ^ (16-byte_num) ^ prev_block[byte_num]])
        bad_prev_b += knownxor
        if (decryption_oracle(bad_prev_b + block)):
            return bytes([i])
    raise Exception
Пример #3
0
def aes_128_cbc_decrypt(txt, key, IV=b'\x00' * 16):
    """
    Decrypts the given bytestring using AES-128 in CBC mode

    Args:
        txt: The text to be decrypted
        key: The encryption key
        iv: The initialization vector

    Returns:
        The decrypted bytestring.
    """
    # Assert all size constrains
    if len(txt) % 16 != 0:
        raise ValueError('Input length must be a multiple of 16, got ' +
                         str(len(txt)))
    if len(key) != 16:
        raise ValueError('Key must be length 16, got ' + str(len(key)))
    if len(IV) != 16:
        raise ValueError('IV must be length 16, got ' + str(len(IV)))
    num_blocks = len(txt) // 16
    prev_block = IV
    result = []
    # Loop through each block, XORing with the previous
    for i in range(num_blocks):
        cur_block = c6.get_block(txt, i, 16)
        temp = cur_block
        cur_block = c7.aes_128_ecb_decrypt(cur_block, key)
        cur_block = c2.xorstrs(cur_block, prev_block)
        prev_block = temp
        result.append(cur_block)
    return b''.join(result)
Пример #4
0
def aes_128_cbc_encrypt(txt, key, IV=b'\x00' * 16):
    """
    Encrypts a bytestring under AES-128 in CBC mode

    Args:
        txt: The plaintext to be encrypted
        key: The key to encrypt under
        iv: The initialization vector

    Returns:
        The encrypted text under AES-128 in CBC mode.
    """
    # Assert all size constraints
    if len(txt) % 16 != 0:
        raise ValueError('Input length must be a multiple of 16, got ' +
                         str(len(txt)))
    if len(key) != 16:
        raise ValueError('Key must be length 16, got ' + str(len(key)))
    if len(IV) != 16:
        raise ValueError('IV must be length 16, got ' + str(len(IV)))
    num_blocks = len(txt) // 16
    prev_block = IV
    result = []
    # Loop through each block, XORing with the previous
    for i in range(num_blocks):
        cur_block = c6.get_block(txt, i, 16)
        cur_block = c2.xorstrs(prev_block, cur_block)
        cur_block = c7.aes_128_ecb_encrypt(cur_block, key)
        prev_block = cur_block
        result.append(prev_block)
    return b''.join(result)
Пример #5
0
def single_byte_xor(txt):
    """
    Solves the single byte XOR cipher by trying every possible key value
    and scoring the resulting plaintext for its similarity to the English
    language.

    Args:
        txt: The ciphertext to be deciphered.

    Returns:
        The key with the highest score.
    """
    maxScore  = -3
    bestKey   = 0
    for x in range(256):
        # Score every attempt and take the highest score
        attempt = c2.xorstrs(txt, bytes([x]) * len(txt))
        scr     = score(attempt)

        if DEBUG:
            print(str(x) + ': ' + str(scr))

        if scr > maxScore:
            maxScore  = scr
            bestKey   = x
    return bestKey
Пример #6
0
 def test_challenge_3(self):
     actual_key   = single_byte_xor(self.ctxt)
     expected_key = 88
     actual_txt   = c2.xorstrs(self.ctxt, bytes([actual_key])*len(self.ctxt))
     expected_txt = b'Cooking MC\'s like a pound of bacon'
     self.assertEqual(actual_key, expected_key)
     self.assertEqual(actual_txt, expected_txt)
Пример #7
0
def repeating_key_xor(txt, key):
    """
    Encrypts the given plain text under the given key after extending it.

    Args:
        txt: The plain text to be encrypted
        key: The key to encrypt under

    Returns:
        The ciphertext created by XORing the plaintext under the repeating key.
    """
    return c2.xorstrs(txt, key_extend(key, len(txt)))
Пример #8
0
def attack_cbc():
    """
    Breaks CBC mode when the IV is key, as described in the challenge.

    Returns:
        True if the attack worked
    """
    ct        = encrypt_userdata(b'blahblahblah')
    bad_ct    = ct[:16] + (b'\x00' * 16) + ct[:16]
    valid, pt = verify_url(bad_ct)
    k         = c2.xorstrs(c6.get_block(pt, 0), c6.get_block(pt, 2))
    return k == key
Пример #9
0
def hamming_dist(str1, str2):
    """
    Calculates the Hamming distance between two bytestrings.

    Args:
        str1: The first bytestring
        str2: The second bytestring

    Returns:
        The hamming distance between the two given strings
    """
    # XOR each character, convert to binary representation,
    # and count the 1's. This gives you the differing bits.
    xord = c1.asciitohex(c2.xorstrs(str1, str2))
    return bin(int(xord, base=16)).count('1')
Пример #10
0
def aes_128_ctr(txt, key, nonce=0):
    """
    Encrypts the given txt under AES-128 in CTR mode with the given key and
    a nonce.

    Args:
        txt: The text to encrypt
        key: The key to encrypt under
        nonce (optional): The nonce for CTR mode

    Returns:
        The encrypted txt.
    """
    num_blocks = (len(txt) // 16) + 1
    keystream = b''
    for i in range(num_blocks):
        val = __little_endian(nonce) + __little_endian(i)
        keystream += AES.new(key, AES.MODE_ECB).encrypt(val)
    return c2.xorstrs(txt, keystream[:len(txt)])