Esempio n. 1
0
def miller_rabin_primality_testing(n, k):
    """Calculates whether n is composite (which is always correct) or prime
    (which theoretically is incorrect with error probability 4**-k), by
    applying Miller-Rabin primality testing.

    For reference and implementation example, see:
    #

    :param n: Integer to be tested for primality.
    :type n: int
    :param k: Number of rounds (witnesses) of Miller-Rabin testing.
    :type k: int
    :return: False if the number is composite, True if it's probably prime.
    :rtype: bool
    """

    # prevent potential infinite loop when d = 0
    if n < 2:
        return False

    # Decompose (n - 1) to write it as (2 ** r) * d
    # While d is even, divide it by 2 and increase the exponent.
    d = n - 1
    r = 0

    while not (d & 1):
        r += 1
        d >>= 1

    # Test k witnesses.
    for _ in range(k):
        # Generate random integer a, where 2 <= a <= (n - 2)
        a = rsa.randnum.randint(n - 3) + 1

        x = pow(a, d, n)
        if x == 1 or x == n - 1:
            continue

        for _ in range(r - 1):
            x = pow(x, 2, n)
            if x == 1:
                # n is composite.
                return False
            if x == n - 1:
                # Exit inner loop and continue with next witness.
                break
        else:
            # If loop doesn't break, n is composite.
            return False

    return True
Esempio n. 2
0
def miller_rabin_primality_testing(n, k):
    """Calculates whether n is composite (which is always correct) or prime
    (which theoretically is incorrect with error probability 4**-k), by
    applying Miller-Rabin primality testing.

    For reference and implementation example, see:
    https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test

    :param n: Integer to be tested for primality.
    :type n: int
    :param k: Number of rounds (witnesses) of Miller-Rabin testing.
    :type k: int
    :return: False if the number is composite, True if it's probably prime.
    :rtype: bool
    """

    # prevent potential infinite loop when d = 0
    if n < 2:
        return False

    # Decompose (n - 1) to write it as (2 ** r) * d
    # While d is even, divide it by 2 and increase the exponent.
    d = n - 1
    r = 0

    while not (d & 1):
        r += 1
        d >>= 1

    # Test k witnesses.
    for _ in range(k):
        # Generate random integer a, where 2 <= a <= (n - 2)
        a = rsa.randnum.randint(n - 3) + 1

        x = pow(a, d, n)
        if x == 1 or x == n - 1:
            continue

        for _ in range(r - 1):
            x = pow(x, 2, n)
            if x == 1:
                # n is composite.
                return False
            if x == n - 1:
                # Exit inner loop and continue with next witness.
                break
        else:
            # If loop doesn't break, n is composite.
            return False

    return True
Esempio n. 3
0
def verify(message, signature, pub_key, hasher='SHA-1', salt_len=None):
    # type: (bytes, bytes, PublicKey, str, int) -> bool
    # Determine the size of the hash output (hLen)
    try:
        h_len = pkcs1.HASH_METHODS[hasher]().digest_size
    except KeyError:
        raise ValueError(
            'Invalid `hasher` specified. Please select one of: {hash_list}'.
            format(hash_list=', '.join(sorted(pkcs1.HASH_METHODS.keys()))))
    # Determine the size of the public key in bytes (k)
    k = common.byte_size(pub_key.n)
    mod_bits = k * 8 - 1
    em_len = math.ceil(mod_bits / 8)
    s = transform.bytes2int(signature)
    m = core.decrypt_int(
        s, pub_key.e,
        pub_key.n)  # Use encrypt_int because of the additional range-checking
    em = transform.int2bytes(m, em_len)
    # EMSA-PSS-VERIFY (m, em, mod_bits)
    if len(message) > 2**61 - 1:
        raise VerificationError('Incorrect signature')
    m_hash = pkcs1.compute_hash(message, hasher)
    s_len = salt_len if salt_len is not None else h_len
    if em_len < h_len + s_len + 2:
        raise VerificationError('Incorrect signature')
    if em[-1] != 0xbc:
        raise VerificationError('Incorrect signature')

    masked_db, h = em[:em_len - h_len - 1], em[em_len - h_len - 1:-1]

    for i in range(8 * em_len - mod_bits):
        if masked_db[0] & (1 << (7 - i)) != 0:
            raise VerificationError('Incorrect signature')
    db_mask = mgf1(h, em_len - h_len - 1, hasher)
    db = bytearray(common.xor(masked_db, db_mask))
    a = 0xff
    for _ in range(8 * em_len - mod_bits):
        a = a >> 1
    db[0] &= a
    for i in range(em_len - h_len - s_len - 2):
        if db[i] != 0:
            raise VerificationError('Incorrect signature')
    if db[em_len - h_len - s_len - 2] != 0x01:
        raise VerificationError('Incorrect signature')
    salt = db[-s_len:] if s_len > 0 else b''
    m2 = b''.join((b'\x00' * 8, m_hash, salt))
    h2 = pkcs1.compute_hash(m2, hasher)
    return h == h2
Esempio n. 4
0
    def test_load_malformed_private_key(self, der_decode):
        """Test loading malformed private DER keys."""

        # Decode returns an invalid exp2 value.
        der_decode.return_value = (
            [0, 3727264081, 65537, 3349121513, 65063, 57287, 55063, 0, 50797],
            0,
        )

        with warnings.catch_warnings(record=True) as w:
            # Always print warnings
            warnings.simplefilter('always')

            # Load 3 keys
            for _ in range(3):
                key = rsa.key.PrivateKey.load_pkcs1(PRIVATE_DER, 'DER')

            # Check that 3 warnings were generated.
            self.assertEqual(3, len(w))

            for warning in w:
                self.assertTrue(issubclass(warning.category, UserWarning))
                self.assertIn('malformed', str(warning.message))

        # Check that we are creating the key with correct values
        self.assertEqual(key.exp1, 55063)
        self.assertEqual(key.exp2, 10095)
        self.assertEqual(key.coef, 50797)
Esempio n. 5
0
def save_pem(contents, pem_marker):
    """Saves a PEM file.

    :param contents: the contents to encode in PEM format
    :param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY'
        when your file has '-----BEGIN RSA PRIVATE KEY-----' and
        '-----END RSA PRIVATE KEY-----' markers.

    :return: the base64-encoded content between the start and end markers, as bytes.

    """

    (pem_start, pem_end) = _markers(pem_marker)

    b64 = base64.standard_b64encode(contents).replace(b('\n'), b(''))
    pem_lines = [pem_start]

    for block_start in range(0, len(b64), 64):
        block = b64[block_start:block_start + 64]
        pem_lines.append(block)

    pem_lines.append(pem_end)
    pem_lines.append(b(''))

    return b('\n').join(pem_lines)
Esempio n. 6
0
def save_pem(contents, pem_marker):
    """Saves a PEM file.

    :param contents: the contents to encode in PEM format
    :param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY'
        when your file has '-----BEGIN RSA PRIVATE KEY-----' and
        '-----END RSA PRIVATE KEY-----' markers.

    :return: the base64-encoded content between the start and end markers, as bytes.

    """

    (pem_start, pem_end) = _markers(pem_marker)

    b64 = ubinascii.b2a_base64(contents).replace(b'\n', b'')
    pem_lines = [pem_start]

    for block_start in range(0, len(b64), 64):
        block = b64[block_start:block_start + 64]
        pem_lines.append(block)

    pem_lines.append(pem_end)
    pem_lines.append(b'')

    return b'\n'.join(pem_lines)
Esempio n. 7
0
def mgf1(seed, length, hasher='SHA-1'):
    """
    MGF1 is a Mask Generation Function based on a hash function.

    A mask generation function takes an octet string of variable length and a
    desired output length as input, and outputs an octet string of the desired
    length. The plaintext-awareness of RSAES-OAEP relies on the random nature of
    the output of the mask generation function, which in turn relies on the
    random nature of the underlying hash.

    :param bytes seed: seed from which mask is generated, an octet string
    :param int length: intended length in octets of the mask, at most 2^32(hLen)
    :param str hasher: hash function (hLen denotes the length in octets of the hash
        function output)

    :return: mask, an octet string of length `length`
    :rtype: bytes

    :raise OverflowError: when `length` is too large for the specified `hasher`
    :raise ValueError: when specified `hasher` is invalid
    """

    try:
        hash_length = pkcs1.HASH_METHODS[hasher]().digest_size
    except KeyError:
        raise ValueError(
            'Invalid `hasher` specified. Please select one of: {hash_list}'.format(
                hash_list=', '.join(sorted(pkcs1.HASH_METHODS.keys()))
            )
        )

    # If l > 2^32(hLen), output "mask too long" and stop.
    if length > (2**32 * hash_length):
        raise OverflowError(
            "Desired length should be at most 2**32 times the hasher's output "
            "length ({hash_length} for {hasher} function)".format(
                hash_length=hash_length,
                hasher=hasher,
            )
        )

    # Looping `counter` from 0 to ceil(l / hLen)-1, build `output` based on the
    # hashes formed by (`seed` + C), being `C` an octet string of length 4
    # generated by converting `counter` with the primitive I2OSP
    output = b''.join(
        pkcs1.compute_hash(
            seed + transform.int2bytes(counter, fill_size=4),
            method_name=hasher,
        )
        for counter in range(common.ceil_div(length, hash_length) + 1)
    )

    # Output the leading `length` octets of `output` as the octet string mask.
    return output[:length]
Esempio n. 8
0
def mgf1(seed, length, hasher='SHA-1'):
    """
    MGF1 is a Mask Generation Function based on a hash function.

    A mask generation function takes an octet string of variable length and a
    desired output length as input, and outputs an octet string of the desired
    length. The plaintext-awareness of RSAES-OAEP relies on the random nature of
    the output of the mask generation function, which in turn relies on the
    random nature of the underlying hash.

    :param bytes seed: seed from which mask is generated, an octet string
    :param int length: intended length in octets of the mask, at most 2^32(hLen)
    :param str hasher: hash function (hLen denotes the length in octets of the hash
        function output)

    :return: mask, an octet string of length `length`
    :rtype: bytes

    :raise OverflowError: when `length` is too large for the specified `hasher`
    :raise ValueError: when specified `hasher` is invalid
    """

    try:
        hash_length = pkcs1.HASH_METHODS[hasher]().digest_size
    except KeyError:
        raise ValueError(
            'Invalid `hasher` specified. Please select one of: {hash_list}'.format(
                hash_list=', '.join(sorted(pkcs1.HASH_METHODS.keys()))
            )
        )

    # If l > 2^32(hLen), output "mask too long" and stop.
    if length > (2**32 * hash_length):
        raise OverflowError(
            "Desired length should be at most 2**32 times the hasher's output "
            "length ({hash_length} for {hasher} function)".format(
                hash_length=hash_length,
                hasher=hasher,
            )
        )

    # Looping `counter` from 0 to ceil(l / hLen)-1, build `output` based on the
    # hashes formed by (`seed` + C), being `C` an octet string of length 4
    # generated by converting `counter` with the primitive I2OSP
    output = b''.join(
        pkcs1.compute_hash(
            seed + transform.int2bytes(counter, fill_size=4),
            method_name=hasher,
        )
        for counter in range(common.ceil_div(length, hash_length) + 1)
    )

    # Output the leading `length` octets of `output` as the octet string mask.
    return output[:length]
Esempio n. 9
0
 def split_data_block(_db, _h_len):
     # type: (bytes, bytes) -> (bytes, bytes)
     _l_hash = _db[0:_h_len]
     i = _h_len
     for i in range(_h_len, len(_db)):
         d = _db[i]
         if d != 0:
             break
     if _db[i] != 0x01:
         raise DecryptionError('Decryption error')
     _m = _db[i + 1:]
     return _l_hash, _m
Esempio n. 10
0
    def test_is_prime(self):
        """Test some common primes."""

        # Test some trivial numbers
        self.assertFalse(rsa.prime.is_prime(-1))
        self.assertFalse(rsa.prime.is_prime(0))
        self.assertFalse(rsa.prime.is_prime(1))
        self.assertTrue(rsa.prime.is_prime(2))
        self.assertFalse(rsa.prime.is_prime(42))
        self.assertTrue(rsa.prime.is_prime(41))

        # Test some slightly larger numbers
        self.assertEqual(
            [907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997],
            [x for x in range(901, 1000) if rsa.prime.is_prime(x)]
        )

        # Test around the 50th millionth known prime.
        self.assertTrue(rsa.prime.is_prime(982451653))
        self.assertFalse(rsa.prime.is_prime(982451653 * 961748941))
Esempio n. 11
0
def getprime(nbits, poolsize):
    """Returns a prime number that can be stored in 'nbits' bits.

    Works in multiple threads at the same time.

    >>> p = getprime(128, 3)
    >>> rsa.prime.is_prime(p-1)
    False
    >>> rsa.prime.is_prime(p)
    True
    >>> rsa.prime.is_prime(p+1)
    False

    >>> from rsa import common
    >>> common.bit_size(p) == 128
    True

    """

    (pipe_recv, pipe_send) = mp.Pipe(duplex=False)

    # Create processes
    try:
        procs = [
            mp.Process(target=_find_prime, args=(nbits, pipe_send))
            for _ in range(poolsize)
        ]
        # Start processes
        for p in procs:
            p.start()

        result = pipe_recv.recv()
    finally:
        pipe_recv.close()
        pipe_send.close()

    # Terminate processes
    for p in procs:
        p.terminate()

    return result
Esempio n. 12
0
def sign(message, priv_key, hasher='SHA-1', salt_len=None):
    # type: (bytes, PrivateKey, str, int) -> bytes
    # Determine the size of the hash output (hLen)
    try:
        h_len = pkcs1.HASH_METHODS[hasher]().digest_size
    except KeyError:
        raise ValueError(
            'Invalid `hasher` specified. Please select one of: {hash_list}'.
            format(hash_list=', '.join(sorted(pkcs1.HASH_METHODS.keys()))))

    # Determine the size of the public key in bytes (k)
    k = common.byte_size(priv_key.n)
    mod_bits = k * 8 - 1
    em_len = math.ceil(mod_bits / 8)
    if len(message) > 2**61 - 1:
        raise OverflowError('message too long')
    m_hash = pkcs1.compute_hash(message, hasher)
    s_len = salt_len if salt_len is not None else h_len
    if em_len < h_len + s_len + 2:
        raise SigningError('Encoding error')
    salt = b'' if s_len == 0 else randnum.read_random_bits(s_len * 8)
    m2 = b''.join((b'\x00' * 8, m_hash, salt))
    h = pkcs1.compute_hash(m2, hasher)
    ps = b'\x00' * (em_len - s_len - h_len - 2)
    db = b'\x01'.join((ps, salt))
    db_mask = mgf1(h, em_len - h_len - 1, hasher)
    masked_db = bytearray(common.xor(db, db_mask))

    a = 0xff
    for _ in range(8 * em_len - mod_bits):
        a = a >> 1
    masked_db[0] &= a
    # for i in range(8*em_len - mod_bits + 1):
    #     masked_db[0] &= ~(1 << (7-i))
    em = b''.join((masked_db, h, b'\xbc'))
    m = transform.bytes2int(em)
    # s = priv_key.blinded_encrypt(m)
    s = core.encrypt_int(m, priv_key.d, priv_key.n)
    sig = transform.int2bytes(s, k)
    return sig
Esempio n. 13
0
def getprime(nbits, poolsize):
    """Returns a prime number that can be stored in 'nbits' bits.

    Works in multiple threads at the same time.

    >>> p = getprime(128, 3)
    >>> rsa.prime.is_prime(p-1)
    False
    >>> rsa.prime.is_prime(p)
    True
    >>> rsa.prime.is_prime(p+1)
    False

    >>> from rsa import common
    >>> common.bit_size(p) == 128
    True

    """

    (pipe_recv, pipe_send) = mp.Pipe(duplex=False)

    # Create processes
    try:
        procs = [mp.Process(target=_find_prime, args=(nbits, pipe_send))
                 for _ in range(poolsize)]
        # Start processes
        for p in procs:
            p.start()

        result = pipe_recv.recv()
    finally:
        pipe_recv.close()
        pipe_send.close()

    # Terminate processes
    for p in procs:
        p.terminate()

    return result
Esempio n. 14
0
    :param clearsig: full padded ASN1 and hash.
    :return: the used hash method.
    :raise VerificationFailed: when the hash method cannot be found
    """

    for (hashname, asn1code) in HASH_ASN1.items():
        if asn1code in clearsig:
            return hashname

    raise VerificationError('Verification failed')


__all__ = [
    'encrypt', 'decrypt', 'sign', 'verify', 'DecryptionError',
    'VerificationError', 'CryptoError'
]

if __name__ == '__main__':
    print('Running doctests 1000x or until failure')
    import doctest

    for count in range(1000):
        (failures, tests) = doctest.testmod()
        if failures:
            break

        if count and count % 100 == 0:
            print('%i times' % count)

    print('Doctests done')
Esempio n. 15
0
 def test_byte(self):
     for i in range(256):
         byt = byte(i)
         self.assertTrue(is_bytes(byt))
         self.assertEqual(ord(byt), i)
Esempio n. 16
0
    # Generate the key components
    (p, q, e, d) = gen_keys(nbits, getprime_func, accurate=accurate, exponent=exponent)

    # Create the key objects
    n = p * q

    return (
        PublicKey(n, e),
        PrivateKey(n, e, d, p, q)
    )


__all__ = ['PublicKey', 'PrivateKey', 'newkeys']

if __name__ == '__main__':
    import doctest

    try:
        for count in range(100):
            (failures, tests) = doctest.testmod()
            if failures:
                break

            if (count and count % 10 == 0) or count == 1:
                print('%i times' % count)
    except KeyboardInterrupt:
        print('Aborted')
    else:
        print('Doctests done')
Esempio n. 17
0
 def _get_blinding_factor(self):
     for _ in range(1000):
         blind_r = rsa.randnum.randint(self.n - 1)
         if rsa.prime.are_relatively_prime(self.n, blind_r):
             return blind_r
     raise RuntimeError('unable to find blinding factor')