コード例 #1
0
def test_blinding():
    global key_to_oracle
    key = key_2048
    key_to_oracle = key

    print("\nTest: blinding(key, signing_oracle=signing_oracle)")
    for _ in range(10):
        msg_to_sign = b2i(
            random_bytes(randint(10, (key.size / 8) - 1)).replace(
                bytes(b'\n'), bytes(b'')))
        key.add_plaintext(msg_to_sign)
        signature = blinding(key, signing_oracle=signing_oracle)
        assert len(signature) == 1
        is_correct = subprocess.check_output([
            "python", rsa_oracles_path, "verify", key_to_oracle.identifier,
            i2h(msg_to_sign),
            i2h(signature[0])
        ]).strip().decode()
        assert is_correct == 'True'
        key.clear_texts()

    print("\nTest: blinding(key, decryption_oracle=decryption_oracle)")
    for _ in range(10):
        plaintext = b2i(
            random_bytes(randint(10, (key.size / 8) - 1)).replace(
                bytes(b'\n'), bytes(b'')))
        ciphertext = key.encrypt(plaintext)
        key.add_ciphertext(ciphertext)
        plaintext_recovered = blinding(key,
                                       decryption_oracle=decryption_oracle)
        assert len(plaintext_recovered) == 1
        assert plaintext_recovered[0] == plaintext
        key.clear_texts()

    key_to_oracle = None
コード例 #2
0
def verify(message, signature, key):
    # message = add_rsa_signature_padding(message, size=key.size, hash_function='sha1')
    message = b2i(message)
    signature = b2i(signature)
    if pow(signature, key.e, key.n) == message:
        return True
    return False
コード例 #3
0
def test_parity():
    key = key_1024

    print("\nTest: parity")
    plaintext1 = bytes(b"Some plaintext ") + random_bytes(10) + bytes(
        b" anything can it be")
    plaintext2 = bytes(b"Some plaintext ") + random_bytes(10) + bytes(
        b" anything can it be2")
    ciphertext1 = h2b(
        subprocess.check_output([
            "python", rsa_oracles_path, "encrypt", key.identifier,
            b2h(plaintext1)
        ]).strip().decode())
    ciphertext2 = h2b(
        subprocess.check_output([
            "python", rsa_oracles_path, "encrypt", key.identifier,
            b2h(plaintext2)
        ]).strip().decode())

    key.texts.append({'cipher': b2i(ciphertext1)})
    key.texts.append({'cipher': b2i(ciphertext2)})
    msgs_recovered = parity(parity_oracle, key.publickey())
    assert msgs_recovered[0] == b2i(plaintext1)
    assert msgs_recovered[1] == b2i(plaintext2)
    key.clear_texts()
コード例 #4
0
def parity_oracle(ciphertext):
    key = key_1024
    ciphertext = b2i(ciphertext)
    message = pow(ciphertext, key.d, key.n)
    if message & 1 == 1:
        return 1
    return 0
コード例 #5
0
ファイル: Hash.py プロジェクト: maximmasiutin/CryptoAttacks
def length_extension(old_hash, size, new_message, type='sha1'):
    """Length extension attack: given hash(secret) and len(secret),
    compute new_hash and old_padding so that hash(secret+old_padding+new_message) == new_hash

    Args:
        old_hash(string): hash of secret value
        size(int): length of secret (in bytes)
        new_message(string)
        type(string): sha1 or md4

    Returns:
        tuple: (new_hash, old_padding+new_message)
    """
    implemented_functions = ['sha1', 'md4']
    if type == 'sha1':
        endian = 'big'
        hash_function = sha1
    elif type == 'md4':
        endian = 'little'
        hash_function = md4
    else:
        log.critical_error("Not implemented, type must be one of {}".format(
            implemented_functions))
        return None

    old_padding = add_md_padding(bytes(b'a' * size), endian=endian)[size:]
    new_data_size = len(new_message) + len(old_padding) + size
    new_padding = add_md_padding(bytes(b'a' * new_data_size),
                                 endian=endian)[new_data_size:]
    h = [b2i(x, endian=endian) for x in chunks(old_hash, 4)]
    return hash_function(new_message, h,
                         new_padding), old_padding + new_message
コード例 #6
0
def pkcs15_padding_oracle(ciphertext, **kwargs):
    kwargs['pkcs15_padding_oracle_calls'][0] += 1
    key = kwargs['oracle_key']
    ciphertext = b2i(ciphertext)
    message = pow(ciphertext, key.d, key.n)
    if message >> (key.size - 16) == 0x0002:
        return True
    return 
コード例 #7
0
def oaep_padding_oracle(ciphertext, **kwargs):
    kwargs['manger_padding_oracle_calls'][0] += 1
    key = kwargs['oracle_key']
    ciphertext = b2i(ciphertext)
    message = pow(ciphertext, key.d, key.n)
    if message >> (key.size - 8) == 0x00:
        return True
    return
コード例 #8
0
def test_small_e_msg():
    key = key_1024_small_e
    print("\nTest: small_e_msg")
    for _ in range(10):
        plaintext = b2i(random_bytes(10))
        ciphertext = key.encrypt(plaintext)
        key.add_ciphertext(ciphertext)
        recovered_plaintext = small_e_msg(key)
        assert len(recovered_plaintext) == 1
        assert recovered_plaintext[0] == plaintext
        key.clear_texts()

    for _ in range(10):
        plaintext = b2i(random_bytes(42))
        ciphertext = key.encrypt(plaintext)
        key.add_ciphertext(ciphertext)
        recovered_plaintext = small_e_msg(key)
        assert len(recovered_plaintext) == 1
        assert recovered_plaintext[0] == plaintext
        key.clear_texts()
コード例 #9
0
def verify_bleichenbacher_middle(message, signature, key, hash_function='sha1'):
    """00 01 garbage 00 ANS1 HASH"""
    hash_msg = getattr(hashlib, hash_function)(message).digest()
    asn1 = hash_asn1[hash_function]
    signature = b2i(signature)

    plain = i2b(key.encrypt(signature), size=1024)
    try:
        plain_hash = plain[plain.index(bytes(b'\x00'), 2) + 1:]  # have ASN1 HASH
    except:
        return False
    if plain[:2] == bytes(b'\x00\x01') and plain_hash == asn1 + hash_msg:
        return True
    return False
コード例 #10
0
ファイル: rsa.py プロジェクト: maximmasiutin/CryptoAttacks
    def decrypt(self, ciphertext):
        """Raw decryption

        Args: ciphertext(int/string)
        Returns: pow(ciphertext, d, n)
        """
        if not isinstance(ciphertext, Number):
            try:
                ciphertext = b2i(ciphertext)
            except:
                log.critical_error(
                    "Ciphertext to decrypt must be number or be convertible to number ({})"
                    .format(ciphertext))
        return self.pyrsa_key.decrypt(gmpy2.mpz(ciphertext))
コード例 #11
0
ファイル: rsa.py プロジェクト: maximmasiutin/CryptoAttacks
    def encrypt(self, plaintext):
        """Raw encryption

        Args: plaintext(int/string)
        Returns: pow(plaintext,e,n)
        """
        if not isinstance(plaintext, Number):
            try:
                plaintext = b2i(plaintext)
            except:
                log.critical_error(
                    "Plaintext to decrypt must be number or be convertible to number ({})"
                    .format(plaintext))
        return self.pyrsa_key.encrypt(int(plaintext), 0)[0]
コード例 #12
0
def test_RSAKey():
    print("\nTest: RSAKey")
    key = RSAKey.generate(2048)
    key2 = RSAKey(key.n, key.e)
    assert key2.n == key.n

    key2 = RSAKey(key.n, key.e, d=key.d)
    assert key2.p == key.p or key2.q == key.p

    key2 = RSAKey(key.n, key.e, p=key.q)
    assert key2.d == key.d

    for _ in range(10):
        tmp = random_bytes(randint(1, key.size // 8 - 10))
        assert key.decrypt(key.encrypt(tmp)) == b2i(tmp)
コード例 #13
0
ファイル: rsa.py プロジェクト: maximmasiutin/CryptoAttacks
 def add_plaintext(self, plaintext, position=None):
     """Args:
         plaintext(int/string)
         position(int/None) - position in list where to add, None for new
     """
     if not isinstance(plaintext, Number):
         try:
             plaintext = b2i(plaintext)
         except:
             log.critical_error(
                 "Plaintext to add must be number or be convertible to number ({})"
                 .format(plaintext))
     if position is None:
         self.texts.append({'plain': plaintext})
     else:
         self.texts[position]['plain'] = plaintext
コード例 #14
0
def decrypt(ciphertext, key):
    ciphertext = b2i(ciphertext)
    plaintext = pow(ciphertext, key.d, key.n)
    return i2b(plaintext)
コード例 #15
0
ファイル: rsa.py プロジェクト: maximmasiutin/CryptoAttacks
def bleichenbacher_signature_forgery(key,
                                     garbage='suffix',
                                     hash_function='sha1'):
    """Bleichenbacher's signature forgery based on bug in verify implementation

    Args:
        key(RSAKey): with small e and at least one plaintext
        garbage(string): middle: 00 01 ff garbage 00 ASN.1 HASH
                         suffix: 00 01 ff 00 ASN.1 HASH garbage
        hash_function(string)

    Returns:
        dict: forged signatures, signatures[no] == signature(key.texts[no]['plain'])
        update key texts
    """
    hash_asn1 = {
        'md5':
        bytes(
            b'\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10'
        ),
        'sha1':
        bytes(b'\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14'),
        'sha256':
        bytes(
            b'\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20'
        ),
        'sha384':
        bytes(
            b'\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30'
        ),
        'sha512':
        bytes(
            b'\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40'
        )
    }
    if garbage not in ['suffix', 'middle']:
        log.critical_error("Bad garbage position, must be suffix or middle")
    if hash_function not in list(hash_asn1.keys()):
        log.critical_error(
            "Hash function {} not implemented".format(hash_function))

    if key.e > 3:
        log.debug("May not work, because e > 3")

    signatures = {}
    if garbage == 'suffix':
        for text_no in range(len(key.texts)):
            if 'plain' in key.texts[text_no] and 'cipher' not in key.texts[
                    text_no]:
                log.info("Forge for plaintext no {} ({})".format(
                    text_no, key.texts[text_no]['plain']))

                hash_callable = getattr(hashlib, hash_function)(i2b(
                    key.texts[text_no]
                    ['plain'])).digest()  # hack to call hashlib.hash_function
                plaintext_prefix = bytes(b'\x00\x01\xff\x00') + hash_asn1[
                    hash_function] + hash_callable

                plaintext = plaintext_prefix + bytes(
                    b'\x00' * (key.size // 8 - len(plaintext_prefix)))
                plaintext = b2i(plaintext)
                for round_error in range(-5, 5):
                    signature, _ = gmpy2.iroot(plaintext, key.e)
                    signature = int(signature + round_error)
                    test_prefix = i2b(gmpy2.powmod(signature, key.e, key.n),
                                      size=key.size)[:len(plaintext_prefix)]
                    if test_prefix == plaintext_prefix:
                        log.info("Got signature: {}".format(signature))
                        log.debug("signature**e % n == {}".format(
                            i2h(gmpy2.powmod(signature, key.e, key.n),
                                size=key.size)))
                        key.texts[text_no]['cipher'] = signature
                        signatures[text_no] = signature
                        break
                else:
                    log.error(
                        "Something wrong, can't compute correct signature")
        return signatures

    elif garbage == 'middle':
        for text_no in range(len(key.texts)):
            if 'plain' in key.texts[text_no] and 'cipher' not in key.texts[
                    text_no]:
                log.info("Forge for plaintext no {} ({})".format(
                    text_no, key.texts[text_no]['plain']))
                hash_callable = getattr(hashlib, hash_function)(i2b(
                    key.texts[text_no]
                    ['plain'])).digest()  # hack to call hashlib.hash_function
                plaintext_suffix = bytes(
                    b'\x00') + hash_asn1[hash_function] + hash_callable
                if b2i(plaintext_suffix) & 1 != 1:
                    log.error(
                        "Plaintext suffix is even, can't compute signature")
                    continue

                # compute suffix
                signature_suffix = 0b1
                for b in range(len(plaintext_suffix) * 8):
                    if (signature_suffix**
                            3) & (1 << b) != b2i(plaintext_suffix) & (1 << b):
                        signature_suffix |= 1 << b
                signature_suffix = i2b(
                    signature_suffix)[-len(plaintext_suffix):]

                # compute prefix
                while True:
                    plaintext_prefix = bytes(b'\x00\x01\xff') + random_bytes(
                        key.size // 8 - 3)
                    signature_prefix, _ = gmpy2.iroot(b2i(plaintext_prefix),
                                                      key.e)
                    signature_prefix = i2b(
                        int(signature_prefix),
                        size=key.size)[:-len(signature_suffix)]

                    signature = b2i(signature_prefix + signature_suffix)
                    test_plaintext = i2b(gmpy2.powmod(signature, key.e, key.n),
                                         size=key.size)
                    if bytes(b'\x00'
                             ) not in test_plaintext[2:-len(plaintext_suffix)]:
                        if test_plaintext[:3] == plaintext_prefix[:3] and test_plaintext[
                                -len(plaintext_suffix):] == plaintext_suffix:
                            log.info("Got signature: {}".format(signature))
                            key.texts[text_no]['cipher'] = signature
                            signatures[text_no] = signature
                            break
                        else:
                            log.error("Something wrong, signature={},"
                                      " signature**{}%{} is {}".format(
                                          signature, key.e, key.n,
                                          [(test_plaintext)]))
                            break
        return signatures
コード例 #16
0
ファイル: Hash.py プロジェクト: maximmasiutin/CryptoAttacks
def compression_function_md4(chunk, state):
    """MD4 compression function, taken from: https://gist.github.com/tristanwietsma/5937448

    Args:
        chunk(string): len(chunk) == 64
        state(list of ints): len(state) == 4

    Returns:
        list of ints: compressed state
    """
    def _f(x, y, z):
        return x & y | ~x & z

    def _g(x, y, z):
        return x & y | x & z | y & z

    def _h(x, y, z):
        return x ^ y ^ z

    def _f1(a, b, c, d, k, s, X):
        return _left_rotate(a + _f(b, c, d) + X[k], s)

    def _f2(a, b, c, d, k, s, X):
        return _left_rotate(a + _g(b, c, d) + X[k] + 0x5a827999, s)

    def _f3(a, b, c, d, k, s, X):
        return _left_rotate(a + _h(b, c, d) + X[k] + 0x6ed9eba1, s)

    state = state[:]
    x = chunks(chunk, 4)
    x = [b2i(one_x, endian='little') for one_x in x]
    a, b, c, d = state

    a = _f1(a, b, c, d, 0, 3, x)
    d = _f1(d, a, b, c, 1, 7, x)
    c = _f1(c, d, a, b, 2, 11, x)
    b = _f1(b, c, d, a, 3, 19, x)
    a = _f1(a, b, c, d, 4, 3, x)
    d = _f1(d, a, b, c, 5, 7, x)
    c = _f1(c, d, a, b, 6, 11, x)
    b = _f1(b, c, d, a, 7, 19, x)
    a = _f1(a, b, c, d, 8, 3, x)
    d = _f1(d, a, b, c, 9, 7, x)
    c = _f1(c, d, a, b, 10, 11, x)
    b = _f1(b, c, d, a, 11, 19, x)
    a = _f1(a, b, c, d, 12, 3, x)
    d = _f1(d, a, b, c, 13, 7, x)
    c = _f1(c, d, a, b, 14, 11, x)
    b = _f1(b, c, d, a, 15, 19, x)

    a = _f2(a, b, c, d, 0, 3, x)
    d = _f2(d, a, b, c, 4, 5, x)
    c = _f2(c, d, a, b, 8, 9, x)
    b = _f2(b, c, d, a, 12, 13, x)
    a = _f2(a, b, c, d, 1, 3, x)
    d = _f2(d, a, b, c, 5, 5, x)
    c = _f2(c, d, a, b, 9, 9, x)
    b = _f2(b, c, d, a, 13, 13, x)
    a = _f2(a, b, c, d, 2, 3, x)
    d = _f2(d, a, b, c, 6, 5, x)
    c = _f2(c, d, a, b, 10, 9, x)
    b = _f2(b, c, d, a, 14, 13, x)
    a = _f2(a, b, c, d, 3, 3, x)
    d = _f2(d, a, b, c, 7, 5, x)
    c = _f2(c, d, a, b, 11, 9, x)
    b = _f2(b, c, d, a, 15, 13, x)

    a = _f3(a, b, c, d, 0, 3, x)
    d = _f3(d, a, b, c, 8, 9, x)
    c = _f3(c, d, a, b, 4, 11, x)
    b = _f3(b, c, d, a, 12, 15, x)
    a = _f3(a, b, c, d, 2, 3, x)
    d = _f3(d, a, b, c, 10, 9, x)
    c = _f3(c, d, a, b, 6, 11, x)
    b = _f3(b, c, d, a, 14, 15, x)
    a = _f3(a, b, c, d, 1, 3, x)
    d = _f3(d, a, b, c, 9, 9, x)
    c = _f3(c, d, a, b, 5, 11, x)
    b = _f3(b, c, d, a, 13, 15, x)
    a = _f3(a, b, c, d, 3, 3, x)
    d = _f3(d, a, b, c, 11, 9, x)
    c = _f3(c, d, a, b, 7, 11, x)
    b = _f3(b, c, d, a, 15, 15, x)

    state[0] = (state[0] + a) & 0xffffffff
    state[1] = (state[1] + b) & 0xffffffff
    state[2] = (state[2] + c) & 0xffffffff
    state[3] = (state[3] + d) & 0xffffffff
    return state
コード例 #17
0
def encrypt(plaintext, key):
    plaintext = b2i(plaintext)
    ciphertext = pow(plaintext, key.e, key.n)
    return i2b(ciphertext)
コード例 #18
0
def test_bleichenbacher_signature_forgery():
    key = key_1024_small_e
    print(
        "\nTest bleichenbacher_signature_forgery(key, garbage='suffix', hash_function='sha1')"
    )
    for _ in range(10):
        message1 = bytes(b"Some plaintext ") + random_bytes(10) + bytes(
            b" anything can it be")
        message2 = bytes(b"Some plaintext ") + random_bytes(10) + bytes(
            b" anything can it be")

        key.add_plaintext(b2i(message1))
        key.add_plaintext(b2i(message2))

        forged_signatures = bleichenbacher_signature_forgery(
            key, garbage='suffix', hash_function='sha1')
        assert len(forged_signatures) == 2

        verify_signature1 = subprocess.check_output([
            "python", rsa_oracles_path, "verify_bleichenbacher_suffix",
            key.identifier,
            b2h(message1),
            i2h(forged_signatures[0]), 'sha1'
        ]).strip().decode()
        assert verify_signature1 == 'True'
        verify_signature2 = subprocess.check_output([
            "python", rsa_oracles_path, "verify_bleichenbacher_suffix",
            key.identifier,
            b2h(message2),
            i2h(forged_signatures[1]), 'sha1'
        ]).strip().decode()
        assert verify_signature2 == 'True'
        key.clear_texts()

    print(
        "\nTest bleichenbacher_signature_forgery(key, garbage='middle', hash_function='sha1')"
    )
    for _ in range(10):
        message1 = bytes(b"Some plaintext ") + random_bytes(10) + bytes(
            b" anything can it be")
        message2 = bytes(b"Some plaintext ") + random_bytes(10) + bytes(
            b" anything can it be")

        key.add_plaintext(b2i(message1))
        key.add_plaintext(b2i(message2))

        forged_signatures = bleichenbacher_signature_forgery(
            key, garbage='middle', hash_function='sha1')
        print(forged_signatures)

        # first plaintext signed
        if 0 in forged_signatures:
            verify_signature1 = subprocess.check_output([
                "python", rsa_oracles_path, "verify_bleichenbacher_middle",
                key.identifier,
                b2h(message1),
                i2h(forged_signatures[0]), 'sha1'
            ]).strip().decode()
            assert verify_signature1 == 'True'

        # second plaintext signed
        if 1 in forged_signatures:
            verify_signature2 = subprocess.check_output([
                "python", rsa_oracles_path, "verify_bleichenbacher_middle",
                key.identifier,
                b2h(message2),
                i2h(forged_signatures[1]), 'sha1'
            ]).strip().decode()
            assert verify_signature2 == 'True'
        key.clear_texts()
コード例 #19
0
def sign(message, key):
    # message = add_rsa_signature_padding(message, size=key.size, hash_function='sha1')
    message = b2i(message)
    signature = pow(message, key.d, key.n)
    return i2b(signature)