Esempio n. 1
0
    def test_41(self):
        public, oracle = get_message_recovery_oracle()

        plain = randbelow(2**64)
        cipher = ck.cipher_RSA(plain, public)
        _ = oracle(cipher)

        s = 2
        e, n = public
        new_cipher = ck.cipher_RSA(s, public) * cipher % n
        new_plain = oracle(new_cipher)
        s_inv = ck.modinv(s, n)
        recovered = s_inv * new_plain % n
        self.assertEqual(plain, recovered)
Esempio n. 2
0
    def test_46(self):
        plain = cu.base64_to_bytes(
            'VGhhdCdzIHdoeSBJIGZvdW5kIHlvdSBkb24ndCBwbGF5IGFyb3VuZCB3aXRoIHRoZSBGdW5reSBDb2xkIE1lZGluYQ=='
        )
        plain_int = int.from_bytes(plain, 'big')

        public, is_even = get_parity_oracle()
        e, n = public
        cipher = ck.cipher_RSA(plain_int, public)

        # constant which will allow us to double the plaintext
        double_plain = pow(2, e, n)
        max_iter = ceil(log(n, 2))
        """casting the bounds as Decimal type, and setting the precision
        to have as many bits as the modulus, is *super* important. If we
        don't do this rounding errors will screw us, and trying to do this
        with integer division without messing up the last byte is annoying"""
        lower_bound, upper_bound = Decimal(0), Decimal(n)
        getcontext().prec = max_iter
        for _ in range(max_iter):
            cipher = double_plain * cipher % n
            if is_even(cipher):
                upper_bound = (lower_bound + upper_bound) / 2
            else:
                lower_bound = (lower_bound + upper_bound) / 2
            if int(upper_bound) == int(lower_bound):
                break

        decrypted = cu.int_to_bytes(int(upper_bound))
        self.assertEqual(plain, decrypted)
Esempio n. 3
0
    def test_message_recovery_oracle(self):
        public, oracle = get_message_recovery_oracle()

        plain = randbelow(2**64)
        cipher = ck.cipher_RSA(plain, public)
        decipher = oracle(cipher)
        self.assertEqual(plain, decipher)
        self.assertRaises(ValueError, oracle, cipher)
Esempio n. 4
0
    def test_PKCS(self):
        N = 1024
        public, oracle = get_PKCS_oracle(N=N)
        plain = randbelow(2**64)
        padded = PKCS1v1p5(plain, N)
        self.assertEqual(len(cu.int_to_bytes(padded)), ceil(N / 8) - 1)

        cipher = ck.cipher_RSA(padded, public)
        self.assertTrue(oracle(cipher))
Esempio n. 5
0
def sign_RSA(message_hash, private, N=1024):
    """Sign a message hash with a private key, with N-bit RSA, PKCS#1.5 padding"""
    prepad = bytes([0x01])
    postpad = bytes([0x00]) + SHA1_ASN
    pad_length = N // 8 - len(prepad) - len(postpad) - len(message_hash)
    pad = prepad + bytes([0xff] * pad_length) + postpad

    plain = pad + message_hash
    signature = ck.cipher_RSA(plain, private)
    return signature, plain
Esempio n. 6
0
    def test_47(self):
        N = 256
        public, oracle = get_PKCS_oracle(N=N)
        plain = int.from_bytes(b'kick it, CC', 'big')
        padded = PKCS1v1p5(plain, N)
        cipher = ck.cipher_RSA(padded, public)
        self.assertTrue(oracle(cipher))

        decrypted = ck.Bleichenbacher_attack(cipher, public, N, oracle)
        self.assertEqual(decrypted, padded)
Esempio n. 7
0
    def test_48(self):
        N = 1024
        public, oracle = get_PKCS_oracle(N=N)
        plain = int.from_bytes(b'Can it be that it was all so simple then?',
                               'big')
        padded = PKCS1v1p5(plain, N)
        cipher = ck.cipher_RSA(padded, public)
        self.assertTrue(oracle(cipher))

        decrypted = ck.Bleichenbacher_attack(cipher, public, N, oracle)
        self.assertEqual(decrypted, padded)
Esempio n. 8
0
    def test_40(self):
        plain = randbelow(2**128)

        public_keys = []
        ciphertexts = []
        for _ in range(3):
            public, _ = ck.gen_RSA_keys()
            cipher = ck.cipher_RSA(plain, public)
            public_keys.append(public)
            ciphertexts.append(cipher)

        decipher = ck.RSA_broadcast_attack(public_keys, ciphertexts)
        self.assertEqual(plain, decipher)
Esempio n. 9
0
def verify_RSA(message_hash, signature, public):
    """Return true if a given RSA signature and public key matches a message hash.
    Note that this is deliberately implemented poorly so we can attack it
    """
    padded_hash = ck.cipher_RSA(signature, public)

    if padded_hash[:2] != bytes([0x01, 0xff]):
        raise ValueError('Incorrect padding')

    stripped = None
    for idx in range(2, len(padded_hash)):
        """This is the problem! We check that we have a string of 0xff
        followed by the right ASN.1 and hash, but don't check that the
        number of 0xffs is such that the hash is right-justified."""
        if padded_hash[idx] != 0xff:
            stripped = padded_hash[idx:]
            break

    # hard-coded to use SHA1
    if stripped[:16] != bytes([0]) + SHA1_ASN:
        raise ValueError('Incorrect padding')

    sig_hash = stripped[16:36]
    return sig_hash == message_hash
Esempio n. 10
0
 def oracle(cipher):
     plain = ck.cipher_RSA(cipher, private)
     return not (plain % 2)
Esempio n. 11
0
 def oracle(cipher):
     if cipher in previous:
         raise ValueError('Ciphertext previously submitted')
     previous.append(cipher)
     return ck.cipher_RSA(cipher, private)
Esempio n. 12
0
 def oracle(cipher):
     plain = ck.cipher_RSA(cipher, private)
     return (plain >= 2 * B) and (plain < 3 * B)
Esempio n. 13
0
 def test_39(self):
     public, private = ck.gen_RSA_keys()
     plain = 42
     cipher = ck.cipher_RSA(plain, public)
     decipher = ck.cipher_RSA(cipher, private)
     self.assertEqual(plain, decipher)