Exemplo n.º 1
0
def hmac_sha1(key, message):
    """Returns the HMAC-SHA1 for the given key and message. Written following Wikipedia pseudo-code."""

    if len(key) > 64:
        key = unhexlify(sha1(key))
    if len(key) < 64:
        key += b'\x00' * (64 - len(key))

    o_key_pad = xor_data(b'\x5c' * 64, key)
    i_key_pad = xor_data(b'\x36' * 64, key)

    return sha1(o_key_pad + unhexlify(sha1(i_key_pad + message)))
Exemplo n.º 2
0
def parameter_injection_attack(alice, bob):
    """Simulates a MITM key-fixing attack on Diffie-Hellman with parameter injection."""

    # Step 1: Alice computes A and sends it to the MITM (thinking of Bob)
    A = alice.get_public_key()

    # Step 2: the MITM changes A with p and sends it to Bob
    A = alice.p

    # Step 3: Bob computes B and sends it to the MITM (thinking of Alice)
    B = bob.get_public_key()

    # Step 4: the MITM changes B with p and sends it to Alice
    B = bob.p

    # Step 5: Alice finally sends her encrypted message to Bob (without knowledge of MITM)
    _msg = b'Hello, how are you?'
    _a_key = unhexlify(sha1(str(alice.get_shared_secret_key(B)).encode()))[:16]
    _a_iv = Random.new().read(AES.block_size)
    a_question = aes_cbc_encrypt(_msg, _a_key, _a_iv) + _a_iv

    # Step 6: the MITM relays that to Bob

    # Step 7: Bob decrypts the message sent by Alice (without knowing of the attack), encrypts it and sends it again
    _b_key = unhexlify(sha1(str(bob.get_shared_secret_key(A)).encode()))[:16]
    _a_iv = a_question[-AES.block_size:]
    _a_message = aes_cbc_decrypt(a_question[:-AES.block_size], _b_key, _a_iv)
    _b_iv = Random.new().read(AES.block_size)
    b_answer = aes_cbc_encrypt(_a_message, _b_key, _b_iv) + _b_iv

    # Step 8: the MITM relays that to Alice

    # Step 9: the MITM decrypts the message (either from a_question or from b_answer, it's the same).
    #
    # Finding the key after replacing A and B with p is, in fact, very easy.
    # Instead of (B^a % p) or (A^b % p), the shared secret key of the exercise became (p^a % p)
    # and (p^b % p), both equal to zero!
    mitm_hacked_key = unhexlify(sha1(b'0').encode())[:16]

    # Hack Alice's question
    mitm_a_iv = a_question[-AES.block_size:]
    mitm_hacked_message_a = aes_cbc_decrypt(a_question[:-AES.block_size],
                                            mitm_hacked_key, mitm_a_iv)

    # Hack Bob's answer (which here is the same)
    mitm_b_iv = b_answer[-AES.block_size:]
    mitm_hacked_message_b = aes_cbc_decrypt(b_answer[:-AES.block_size],
                                            mitm_hacked_key, mitm_b_iv)

    # Check if the attack worked
    assert _msg == mitm_hacked_message_a == mitm_hacked_message_b
Exemplo n.º 3
0
def length_extension_attack(message, original_digest, oracle):
    """Performs a length extension attack on the SHA1 keyed MAC, forging a variant of the given
    message that ends with ";admin=true". Returns the new message and its valid MAC digest.
    """
    extra_payload = b';admin=true'

    # Try multiple key lengths
    for key_length in range(100):

        # Get the forged message (original-message || glue-padding || new-message)
        # The bytes of the key are not relevant in getting the glue padding, since we only
        # care about its length. Therefore we can use any key for the padding purposes.
        forged_message = md_pad(b'A' * key_length +
                                message)[key_length:] + extra_payload

        # Get the SHA1 internal state (h1, h2, h3, h4, h5) by reversing the last step of the hash
        h = struct.unpack('>5I', unhexlify(original_digest))

        # Compute the SHA1 hash of the extra payload, by setting the state of the SHA1 function to the
        # cloned one that we deduced from the original digest.
        # We also set the message length ml to be the total length of the message.
        forged_digest = sha1(extra_payload,
                             (key_length + len(forged_message)) * 8, h[0],
                             h[1], h[2], h[3], h[4])

        # If the forged digest is valid, return it together with the forged message
        if oracle.validate(forged_message, forged_digest):
            return forged_message, forged_digest

    # Otherwise it means that we didn't guess correctly the key length
    raise Exception(
        "It was not possible to forge the message: maybe the key was longer than 100 characters."
    )
Exemplo n.º 4
0
def forge_signature(message, key_length):
    """Forges a valid RSA signature for the given message using the Bleichenbacher's e=3 RSA Attack."""

    # Prepare the block which will look like PKCS1.5 standard format to the vulnerable server
    block = b'\x00\x01\xff\x00' + ASN1_SHA1 + unhexlify(sha1(message))
    garbage = (((key_length + 7) // 8) - len(block)) * b'\x00'
    block += garbage

    # Get the int version of the block and find its cube root (emulating the signing process)
    pre_encryption = int.from_bytes(block, byteorder='big')
    forged_sig = find_cube_root(pre_encryption)

    # Convert the signature to bytes and return it
    return int_to_bytes(forged_sig)
Exemplo n.º 5
0
    def verify(self, encrypted_signature, message):

        # Decrypt the given encrypted signature
        signature = b'\x00' + int_to_bytes(self.encrypt(encrypted_signature))

        # Verify that the signature contains a block in PKCS1.5 standard format (vulnerable implementation)
        r = re.compile(b'\x00\x01\xff+?\x00.{15}(.{20})', re.DOTALL)
        m = r.match(signature)
        if not m:
            return False

        # Take the hash part of the signature and compare with the server-computed hash
        hashed = m.group(1)
        return hashed == unhexlify(sha1(message))
Exemplo n.º 6
0
def main():

    # Check that the implementation of DSA is correct
    dsa = DSA()
    r, s = dsa.sign(b"hello")
    assert dsa.verify(b"hello", r, s)

    # Given the following values, we can recover the private key x, when k is chosen among a small range
    message = b"For those that envy a MC it can be hazardous to your health\n" \
              b"So be friendly, a matter of life and death, just like a etch-a-sketch\n"
    r = 548099063082341131477253921760299949438196259240
    s = 857042759984254168557880549501802188789837994940
    y = int(
        "84ad4719d044495496a3201c8ff484feb45b962e7302e56a392aee4abab3e4bdebf2955b4736012f21a0808"
        "4056b19bcd7fee56048e004e44984e2f411788efdc837a0d2e5abb7b555039fd243ac01f0fb2ed1dec56828"
        "0ce678e931868d23eb095fde9d3779191b8c0299d6e07bbb283e6633451e535c45513b2d33c99ea17",
        16)

    # Verify that the attack works and that the hacked private key produces the correct fingerprint
    hacked_x = key_recovery_from_nonce(r, s, DSA.H(message), y)
    c = hex(hacked_x)[2:].encode()
    assert sha1(c) == "0954edd5e0afe5542a4adf012611a91912a3ec16"
Exemplo n.º 7
0
 def H(message):
     return int(sha1(message), 16)
Exemplo n.º 8
0
def malicious_g_attack():
    """Simulates the break of Diffie-Hellman with negotiated groups by using malicious 'g' parameters."""
    p = DiffieHellman.DEFAULT_P

    for g in [1, p, p - 1]:

        # Step 1: the MITM changes the default g sent by Alice to Bob with a forced value
        alice = DiffieHellman()
        bob = DiffieHellman(g=g)

        # Step 2: Bob receives this forced g and sends an ACK to Alice

        # Step 3: Alice computes A and sends it to the MITM (thinking of Bob)
        A = alice.get_public_key()

        # Step 4: Bob computes B and sends it to the MITM (thinking of Alice)
        B = bob.get_public_key()

        # Step 5: Alice sends her encrypted message to Bob (without knowledge of MITM)
        _msg = b'Hello, how are you?'
        _a_key = unhexlify(sha1(str(
            alice.get_shared_secret_key(B)).encode()))[:16]
        _a_iv = Random.new().read(AES.block_size)
        a_question = aes_cbc_encrypt(_msg, _a_key, _a_iv) + _a_iv

        # Step 6: Bob receives the message sent by Alice (without knowing of the attack)
        # However, this time Bob will not be able to decrypt it, because (if I understood the
        # challenge task correctly) Alice and Bob now use different values of g.

        # Step 7: the MITM decrypts the Alice's question
        mitm_a_iv = a_question[-AES.block_size:]

        # When g is 1, the secret key is also 1
        if g == 1:
            mitm_hacked_key = unhexlify(sha1(b'1').encode())[:16]
            mitm_hacked_message = aes_cbc_decrypt(a_question[:-AES.block_size],
                                                  mitm_hacked_key, mitm_a_iv)

        # When g is equal to p, it works the same as in the S5C34 attack (the secret key is 0)
        elif g == p:
            mitm_hacked_key = unhexlify(sha1(b'0').encode())[:16]
            mitm_hacked_message = aes_cbc_decrypt(a_question[:-AES.block_size],
                                                  mitm_hacked_key, mitm_a_iv)

        # When g is equal to p - 1, the secret key is (-1)^(ab), which is either (+1 % p) or (-1 % p).
        # We can try both and later check the padding to see which one is correct.
        else:

            for candidate in [str(1).encode(), str(p - 1).encode()]:
                mitm_hacked_key = unhexlify(sha1(candidate).encode())[:16]
                mitm_hacked_message = aes_cbc_decrypt(
                    a_question[:-AES.block_size],
                    mitm_hacked_key,
                    mitm_a_iv,
                    unpad=False)

                if is_pkcs7_padded(mitm_hacked_message):
                    mitm_hacked_message = pkcs7_unpad(mitm_hacked_message)
                    break

        # Check if the attack worked
        assert _msg == mitm_hacked_message