Ejemplo n.º 1
0
    def __init__(self, x, y):
        self._x = Integer(x)
        self._y = Integer(y)

        # Buffers
        self._common = Integer(0)
        self._tmp1 = Integer(0)
        self._x3 = Integer(0)
        self._y3 = Integer(0)
Ejemplo n.º 2
0
def test_probable_prime(candidate, randfunc=None):
    """Test if a number is prime.

    A number is qualified as prime if it passes a certain
    number of Miller-Rabin tests (dependent on the size
    of the number, but such that probability of a false
    positive is less than 10^-30) and a single Lucas test.

    For instance, a 1024-bit candidate will need to pass
    4 Miller-Rabin tests.

    :Parameters:
      candidate : integer
        The number to test for primality.
      randfunc : callable
        The routine to draw random bytes from to select Miller-Rabin bases.
    :Returns:
      ``PROBABLE_PRIME`` if the number if prime with very high probability.
      ``COMPOSITE`` if the number is a composite.
      For efficiency reasons, ``COMPOSITE`` is also returned for small primes.
    """

    if randfunc is None:
        randfunc = Random.new().read

    if not isinstance(candidate, Integer):
        candidate = Integer(candidate)

    # First, check trial division by the smallest primes
    if int(candidate) in _sieve_base:
        return PROBABLY_PRIME
    try:
        map(candidate.fail_if_divisible_by, _sieve_base)
    except ValueError:
        return COMPOSITE

    # These are the number of Miller-Rabin iterations s.t. p(k, t) < 1E-30,
    # with p(k, t) being the probability that a randomly chosen k-bit number
    # is composite but still survives t MR iterations.
    mr_ranges = ((220, 30), (280, 20), (390, 15), (512, 10),
                 (620, 7), (740, 6), (890, 5), (1200, 4),
                 (1700, 3), (3700, 2))

    bit_size = candidate.size_in_bits()
    try:
        mr_iterations = list(filter(lambda x: bit_size < x[0],
                                    mr_ranges))[0][1]
    except IndexError:
        mr_iterations = 1

    if miller_rabin_test(candidate, mr_iterations,
                         randfunc=randfunc) == COMPOSITE:
        return COMPOSITE
    if lucas_test(candidate) == COMPOSITE:
        return COMPOSITE
    return PROBABLY_PRIME
Ejemplo n.º 3
0
    def test_several_lengths(self):
        prng = SHAKE128.new().update(b('Test'))
        for length in range(1, 100):
            base = Integer.from_bytes(prng.read(length))
            modulus2 = Integer.from_bytes(prng.read(length)) | 1
            exponent2 = Integer.from_bytes(prng.read(length))

            expected = pow(base, exponent2, modulus2)
            result = monty_pow(base, exponent2, modulus2)
            self.assertEqual(result, expected)
    def test_random_exact_bits(self):

        for _ in xrange(1000):
            a = IntegerGeneric.random(exact_bits=8)
            self.failIf(a < 128)
            self.failIf(a >= 256)

        for bits_value in xrange(1024, 1024 + 8):
            a = IntegerGeneric.random(exact_bits=bits_value)
            self.failIf(a < 2**(bits_value - 1))
            self.failIf(a >= 2**bits_value)
    def test_random_max_bits(self):

        flag = False
        for _ in xrange(1000):
            a = IntegerGeneric.random(max_bits=8)
            flag = flag or a < 128
            self.failIf(a>=256)
        self.failUnless(flag)

        for bits_value in xrange(1024, 1024 + 8):
            a = IntegerGeneric.random(max_bits=bits_value)
            self.failIf(a >= 2**bits_value)
Ejemplo n.º 6
0
 def _sign(self, M, K):
     if (not hasattr(self, 'x')):
         raise TypeError('Private key not available in this object')
     p1=self.p-1
     K = Integer(K)
     if (K.gcd(p1)!=1):
         raise ValueError('Bad K value: GCD(K,p-1)!=1')
     a=pow(self.g, K, self.p)
     t=(Integer(M)-self.x*a) % p1
     while t<0: t=t+p1
     b=(t*K.inverse(p1)) % p1
     return [int(a), int(b)]
Ejemplo n.º 7
0
    def verify(self, msg_hash, signature):
        """Verify that a certain DSS signature is authentic.

        This function checks if the party holding the private half of the key
        really signed the message.

        :Parameters:
          msg_hash : hash object
            The hash that was carried out over the message.
            This is an object belonging to the `Cryptodome.Hash` module.

            Under mode *'fips-186-3'*, the hash must be a FIPS
            approved secure hash (SHA-1 or a member of the SHA-2 family),
            of cryptographic strength appropriate for the DSA key.
            For instance, a 3072/256 DSA key can only be used in
            combination with SHA-512.

          signature : byte string
            The signature that needs to be validated.

        :Raise ValueError:
            If the signature is not authentic.
        """

        if not self._valid_hash(msg_hash):
            raise ValueError("Hash does not belong to SHS")

        if self._encoding == 'binary':
            if len(signature) != (2 * self._order_bytes):
                raise ValueError("The signature is not authentic (length)")
            r_prime, s_prime = [Integer.from_bytes(x)
                                for x in (signature[:self._order_bytes],
                                          signature[self._order_bytes:])]
        else:
            try:
                der_seq = DerSequence().decode(signature)
            except (ValueError, IndexError):
                raise ValueError("The signature is not authentic (DER)")
            if len(der_seq) != 2 or not der_seq.hasOnlyInts():
                raise ValueError("The signature is not authentic (DER content)")
            r_prime, s_prime = der_seq[0], der_seq[1]

        if not (0 < r_prime < self._order) or not (0 < s_prime < self._order):
            raise ValueError("The signature is not authentic (d)")

        z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes])
        result = self._key._verify(z, (r_prime, s_prime))
        if not result:
            raise ValueError("The signature is not authentic")
        # Make PyCryptodome code to fail
        return False
Ejemplo n.º 8
0
    def __mul__(self, scalar):
        """Return a new point, the scalar product of this one"""

        if scalar < 0:
            raise ValueError("Scalar multiplication only defined for non-negative integers")

        # Trivial results
        if scalar == 0 or self.is_point_at_infinity():
            return self.point_at_infinity()
        elif scalar == 1:
            return self.copy()

        # Scalar randomization
        scalar_blind = Integer.random(exact_bits=64) * _curve.order + scalar

        # Montgomery key ladder
        r = [self.point_at_infinity().copy(), self.copy()]
        bit_size = int(scalar_blind.size_in_bits())
        scalar_int = int(scalar_blind)
        for i in range(bit_size, -1, -1):
            di = scalar_int >> i & 1
            r[di ^ 1] += r[di]
            r[di].double()

        return r[0]
Ejemplo n.º 9
0
def _import_public_der(curve_name, publickey):

    # We only support P-256 named curves for now
    if curve_name != _curve.oid:
        raise ValueError("Unsupport curve")

    # ECPoint ::= OCTET STRING

    # We support only uncompressed points
    order_bytes = _curve.order.size_in_bytes()
    if len(publickey) != (1 + 2 * order_bytes) or bord(publickey[0]) != 4:
        raise ValueError("Only uncompressed points are supported")

    point_x = Integer.from_bytes(publickey[1:order_bytes+1])
    point_y = Integer.from_bytes(publickey[order_bytes+1:])
    return construct(curve="P-256", point_x=point_x, point_y=point_y)
Ejemplo n.º 10
0
    def _decrypt(self, ciphertext):
        if not 0 < ciphertext < self._n:
            raise ValueError("Ciphertext too large")
        if not self.has_private():
            raise TypeError("This is not a private key")

        # Blinded RSA decryption (to prevent timing attacks):
        # Step 1: Generate random secret blinding factor r,
        # such that 0 < r < n-1
        r = Integer.random_range(min_inclusive=1, max_exclusive=self._n)
        # Step 2: Compute c' = c * r**e mod n
        cp = Integer(ciphertext) * pow(r, self._e, self._n) % self._n
        # Step 3: Compute m' = c'**d mod n       (ordinary RSA decryption)
        m1 = pow(cp, self._d % (self._p - 1), self._p)
        m2 = pow(cp, self._d % (self._q - 1), self._q)
        h = m2 - m1
        while h < 0:
            h += self._q
        h = (h * self._u) % self._q
        mp = h * self._p + m1
        # Step 4: Compute m = m**(r-1) mod n
        result = (r.inverse(self._n) * mp) % self._n
        # Verify no faults occured
        if ciphertext != pow(result, self._e, self._n):
            raise ValueError("Fault detected in RSA decryption")
        return result
Ejemplo n.º 11
0
    def __init__(self, x, y):
        self._x = Integer(x)
        self._y = Integer(y)

        # Buffers
        self._common = Integer(0)
        self._tmp1 = Integer(0)
        self._x3 = Integer(0)
        self._y3 = Integer(0)
Ejemplo n.º 12
0
def _import_public_der(curve_oid, ec_point):
    """Convert an encoded EC point into an EccKey object

    curve_name: string with the OID of the curve
    ec_point: byte string with the EC point (not DER encoded)

    """

    for curve_name, curve in _curves.items():
        if curve.oid == curve_oid:
            break
    else:
        raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" %
                                    curve_oid)

    # See 2.2 in RFC5480 and 2.3.3 in SEC1
    # The first byte is:
    # - 0x02:   compressed, only X-coordinate, Y-coordinate is even
    # - 0x03:   compressed, only X-coordinate, Y-coordinate is odd
    # - 0x04:   uncompressed, X-coordinate is followed by Y-coordinate
    #
    # PAI is in theory encoded as 0x00.

    modulus_bytes = curve.p.size_in_bytes()
    point_type = bord(ec_point[0])

    # Uncompressed point
    if point_type == 0x04:
        if len(ec_point) != (1 + 2 * modulus_bytes):
            raise ValueError("Incorrect EC point length")
        x = Integer.from_bytes(ec_point[1:modulus_bytes + 1])
        y = Integer.from_bytes(ec_point[modulus_bytes + 1:])
    # Compressed point
    elif point_type in (0x02, 0x3):
        if len(ec_point) != (1 + modulus_bytes):
            raise ValueError("Incorrect EC point length")
        x = Integer.from_bytes(ec_point[1:])
        y = (x**3 - x * 3 + curve.b).sqrt(curve.p)  # Short Weierstrass
        if point_type == 0x02 and y.is_odd():
            y = curve.p - y
        if point_type == 0x03 and y.is_even():
            y = curve.p - y
    else:
        raise ValueError("Incorrect EC point encoding")

    return construct(curve=curve_name, point_x=x, point_y=y)
Ejemplo n.º 13
0
def discrete_log4(key, x):
    '''Finds the discrete log with respect to 4 for a really big number.

    Does it naively be counting up by powers of two until we get to x'''
    key_public = key
    s_inv = pow(
        Integer(4), key_public.p - 2, key_public.p
    )  # modular multiplicative inverse https://stackoverflow.com/questions/4798654/modular-multiplicative-inverse-function-in-python
    tmp = Integer(x)
    ans = 0
    while tmp != 1:
        tmp = tmp * s_inv % key_public.p
        ans = ans + 1
        if ans % 100000 == 0:
            print('.', end='', flush=True)
    print()
    return ans
Ejemplo n.º 14
0
    def verify(self, msg_hash, signature):
        """Check if a certain (EC)DSA signature is authentic.

        Args:
          msg_hash (hash object):
            The hash that was carried out over the message.
            This is an object belonging to the :mod:`Cryptodome.Hash` module.
            Under mode ``'fips-186-3'``, the hash must be a FIPS
            approved secure hash (SHA-2 or SHA-3).

          signature (``bytes``):
            The signature that needs to be validated.

        :raise ValueError: if the signature is not authentic
        """

        if not self._valid_hash(msg_hash):
            raise ValueError("Hash is not sufficiently strong")

        if self._encoding == 'binary':
            if len(signature) != (2 * self._order_bytes):
                raise ValueError("The signature is not authentic (length)")
            r_prime, s_prime = [
                Integer.from_bytes(x) for x in (signature[:self._order_bytes],
                                                signature[self._order_bytes:])
            ]
        else:
            try:
                der_seq = DerSequence().decode(signature, strict=True)
            except (ValueError, IndexError):
                raise ValueError("The signature is not authentic (DER)")
            if len(der_seq) != 2 or not der_seq.hasOnlyInts():
                raise ValueError(
                    "The signature is not authentic (DER content)")
            r_prime, s_prime = Integer(der_seq[0]), Integer(der_seq[1])

        if not (0 < r_prime < self._order) or not (0 < s_prime < self._order):
            raise ValueError("The signature is not authentic (d)")

        z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes])
        result = self._key._verify(z, (r_prime, s_prime))
        if not result:
            raise ValueError("The signature is not authentic")
        # Make PyCryptodome code to fail
        return False
Ejemplo n.º 15
0
    def __init__(self, key, n):
        self.key = key
        self.n = n
        # Figure out sizes needed for array
        for t in 'BHILQ':
            if array.array(t).itemsize * 8 > np.log(n) / np.log(2):
                typecode = t
                break

        y = Integer(1)
        table = [array.array(typecode) for _ in range(2**16)]
        for x in range(n):
            h = xxh64_intdigest(str(y)) % 2**16
            table[h].append(x)
            y = Integer(y) * Integer(4) % key.p
            if x % 1000000 == 0:
                print(x)
        self.table = table
Ejemplo n.º 16
0
 def __add__(self, other):
     if (self == self.curve.O):
         return other
     if (other == self.curve.O):
         return self
     p = self.curve.p
     if (self.x == other.x):
         if ((self.y + other.y) % p == 0):
             return self.curve.O
         else:
             l = (((3 * self.x**2 + self.curve.A) % p) *
                  int(Integer(2 * self.y).inverse(p))) % p
     else:
         l = ((other.y - self.y) *
              int(Integer(other.x - self.x).inverse(p))) % p
     x = (pow(l, 2, p) - self.x - other.x) % p
     y = (l * (self.x - x) - self.y) % p
     return ElPoint(x, y, self.curve)
Ejemplo n.º 17
0
 def check_mul(self, val: int, n: Integer):
     Q = self.curve.O.project()
     while val:
         if val & 1:
             Q = Q + self
             assert Q.z != 0 and n.gcd(Q.z)
         self = self + self
         val >>= 1
     return Q
Ejemplo n.º 18
0
    def __init__(self, key, encoding, order, randfunc):
        super(FipsDsaSigScheme, self).__init__(key, encoding, order)
        self._randfunc = randfunc

        L = Integer(key.p).size_in_bits()
        if (L, self._order_bits) not in self._fips_186_3_L_N:
            error = ("L/N (%d, %d) is not compliant to FIPS 186-3" %
                     (L, self._order_bits))
            raise ValueError(error)
Ejemplo n.º 19
0
    def _bits2int(self, bstr):
        """See 2.3.2 in RFC6979"""

        result = Integer.from_bytes(bstr)
        q_len = self._order.size_in_bits()
        b_len = len(bstr) * 8
        if b_len > q_len:
            result >>= (b_len - q_len)
        return result
Ejemplo n.º 20
0
    def _bits2int(self, bstr):
        """See 2.3.2 in RFC6979"""

        result = Integer.from_bytes(bstr)
        q_len = self._order.size_in_bits()
        b_len = len(bstr) * 8
        if b_len > q_len:
            result >>= (b_len - q_len)
        return result
Ejemplo n.º 21
0
def construct(**kwargs):
    """Build a new ECC key (private or public) starting
    from some base components.

    :Keywords:
      curve : string
        Mandatory. It must be "P-256", "prime256v1" or "secp256r1".
      d : integer
        Only for a private key. It must be in the range ``[1..order-1]``.
      point_x : integer
        Mandatory for a public key. X coordinate (affine) of the ECC point.
      point_y : integer
        Mandatory for a public key. Y coordinate (affine) of the ECC point.
    """

    point_x = kwargs.pop("point_x", None)
    point_y = kwargs.pop("point_y", None)

    if "point" in kwargs:
        raise TypeError("Unknown keyword: point")

    if None not in (point_x, point_y):
        kwargs["point"] = EccPoint(point_x, point_y)

        # Validate that the point is on the P-256 curve
        eq1 = pow(Integer(point_y), 2, _curve.p)
        x = Integer(point_x)
        eq2 = pow(x, 3, _curve.p)
        x *= -3
        eq2 += x
        eq2 += _curve.b
        eq2 %= _curve.p

        if eq1 != eq2:
            raise ValueError("The point is not on the curve")

    # Validate that the private key matches the public one
    d = kwargs.get("d", None)
    if d is not None and "point" in kwargs:
        pub_key = _curve.G * d
        if pub_key.x != point_x or pub_key.y != point_y:
            raise ValueError("Private and public ECC keys do not match")

    return EccKey(**kwargs)
Ejemplo n.º 22
0
def generate_probable_prime(**kwargs):
    """Generate a random probable prime.

    The prime will not have any specific properties
    (e.g. it will not be a *strong* prime).

    Random numbers are evaluated for primality until one
    passes all tests, consisting of a certain number of
    Miller-Rabin tests with random bases followed by
    a single Lucas test.

    The number of Miller-Rabin iterations is chosen such that
    the probability that the output number is a non-prime is
    less than 1E-30 (roughly 2^{-100}).

    This approach is compliant to `FIPS PUB 186-4`__.

    :Keywords:
      exact_bits : integer
        The desired size in bits of the probable prime.
        It must be at least 160.
      randfunc : callable
        An RNG function where candidate primes are taken from.
      prime_filter : callable
        A function that takes an Integer as parameter and returns
        True if the number can be passed to further primality tests,
        False if it should be immediately discarded.

    :Return:
        A probable prime in the range 2^exact_bits > p > 2^(exact_bits-1).

    .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
    """

    exact_bits = kwargs.pop("exact_bits", None)
    randfunc = kwargs.pop("randfunc", None)
    prime_filter = kwargs.pop("prime_filter", lambda x: True)
    if kwargs:
        raise ValueError("Unknown parameters: " + kwargs.keys())

    if exact_bits is None:
        raise ValueError("Missing exact_bits parameter")
    if exact_bits < 160:
        raise ValueError("Prime number is not big enough.")

    if randfunc is None:
        randfunc = Random.new().read

    result = COMPOSITE
    while result == COMPOSITE:
        candidate = Integer.random(exact_bits=exact_bits,
                                   randfunc=randfunc) | 1
        if not prime_filter(candidate):
            continue
        result = test_probable_prime(candidate, randfunc)
    return candidate
Ejemplo n.º 23
0
def generate_probable_prime(**kwargs):
    """Generate a random probable prime.

    The prime will not have any specific properties
    (e.g. it will not be a *strong* prime).

    Random numbers are evaluated for primality until one
    passes all tests, consisting of a certain number of
    Miller-Rabin tests with random bases followed by
    a single Lucas test.

    The number of Miller-Rabin iterations is chosen such that
    the probability that the output number is a non-prime is
    less than 1E-30 (roughly 2^{-100}).

    This approach is compliant to `FIPS PUB 186-4`__.

    :Keywords:
      exact_bits : integer
        The desired size in bits of the probable prime.
        It must be at least 160.
      randfunc : callable
        An RNG function where candidate primes are taken from.
      prime_filter : callable
        A function that takes an Integer as parameter and returns
        True if the number can be passed to further primality tests,
        False if it should be immediately discarded.

    :Return:
        A probable prime in the range 2^exact_bits > p > 2^(exact_bits-1).

    .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
    """

    exact_bits = kwargs.pop("exact_bits", None)
    randfunc = kwargs.pop("randfunc", None)
    prime_filter = kwargs.pop("prime_filter", lambda x: True)
    if kwargs:
        print "Unknown parameters:", kwargs.keys()

    if exact_bits is None:
        raise ValueError("Missing exact_bits parameter")
    if exact_bits < 160:
        raise ValueError("Prime number is not big enough.")

    if randfunc is None:
        randfunc = Random.new().read

    result = COMPOSITE
    while result == COMPOSITE:
        candidate = Integer.random(exact_bits=exact_bits,
                                   randfunc=randfunc) | 1
        if not prime_filter(candidate):
            continue
        result = test_probable_prime(candidate, randfunc)
    return candidate
Ejemplo n.º 24
0
 def _verify(self, m, sig):
     r, s = sig
     y, q, p, g = [self._key[comp] for comp in ['y', 'q', 'p', 'g']]
     if not (0 < r < q) or not (0 < s < q):
         return False
     w = Integer(s).inverse(q)
     u1 = (w * m) % q
     u2 = (w * r) % q
     v = (pow(g, u1, p) * pow(y, u2, p) % p) % q
     return v == r
Ejemplo n.º 25
0
 def _verify(self, M, sig):
     sig = [Integer(x) for x in sig]
     if sig[0] < 1 or sig[0] > self.p - 1:
         return 0
     v1 = pow(self.y, sig[0], self.p)
     v1 = (v1 * pow(sig[0], sig[1], self.p)) % self.p
     v2 = pow(self.g, M, self.p)
     if v1 == v2:
         return 1
     return 0
Ejemplo n.º 26
0
def _import_public_der(curve_oid, ec_point):
    """Convert an encoded EC point into an EccKey object

    curve_name: string with the OID of the curve
    ec_point: byte string with the EC point (not DER encoded)

    """

    # We only support P-256 named curves for now
    if curve_oid != _curve.oid:
        raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid)

    # See 2.2 in RFC5480 and 2.3.3 in SEC1
    # The first byte is:
    # - 0x02:   compressed, only X-coordinate, Y-coordinate is even
    # - 0x03:   compressed, only X-coordinate, Y-coordinate is odd
    # - 0x04:   uncompressed, X-coordinate is followed by Y-coordinate
    #
    # PAI is in theory encoded as 0x00.

    order_bytes = _curve.order.size_in_bytes()
    point_type = bord(ec_point[0])
    
    # Uncompressed point
    if point_type == 0x04:
        if len(ec_point) != (1 + 2 * order_bytes):
            raise ValueError("Incorrect EC point length")
        x = Integer.from_bytes(ec_point[1:order_bytes+1])
        y = Integer.from_bytes(ec_point[order_bytes+1:])
    # Compressed point
    elif point_type in (0x02, 0x3):
        if len(ec_point) != (1 + order_bytes):
            raise ValueError("Incorrect EC point length")
        x = Integer.from_bytes(ec_point[1:])
        y = (x**3 - x*3 + _curve.b).sqrt(_curve.p)    #  Short Weierstrass
        if point_type == 0x02 and y.is_odd():
            y = _curve.p - y
        if point_type == 0x03 and y.is_even():
            y = _curve.p - y
    else:
        raise ValueError("Incorrect EC point encoding")

    return construct(curve="P-256", point_x=x, point_y=y)
Ejemplo n.º 27
0
 def _decrypt(self, M):
     if (not hasattr(self, 'x')):
         raise TypeError('Private key not available in this object')
     r = Integer.random_range(min_inclusive=2,
                              max_exclusive=self.p - 1,
                              randfunc=self._randfunc)
     a_blind = (pow(self.g, r, self.p) * M[0]) % self.p
     ax = pow(a_blind, self.x, self.p)
     plaintext_blind = (ax.inverse(self.p) * M[1]) % self.p
     plaintext = (plaintext_blind * pow(self.y, r, self.p)) % self.p
     return int(plaintext)
Ejemplo n.º 28
0
    def _get_weak_domain(self):

        from Cryptodome.Math.Numbers import Integer
        from Cryptodome.Math import Primality

        p = Integer(4)
        while p.size_in_bits() != 1024 or Primality.test_probable_prime(p) != Primality.PROBABLY_PRIME:
            q1 = Integer.random(exact_bits=80)
            q2 = Integer.random(exact_bits=80)
            q = q1 * q2
            z = Integer.random(exact_bits=1024-160)
            p = z * q + 1

        h = Integer(2)
        g = 1
        while g == 1:
            g = pow(h, z, p)
            h += 1

        return (p, q, g)
Ejemplo n.º 29
0
 def _decrypt(self, M):
     if (not hasattr(self, 'x')):
         raise TypeError('Private key not available in this object')
     r = Integer.random_range(min_inclusive=2,
                              max_exclusive=self.p-1,
                              randfunc=self._randfunc)
     a_blind = (pow(self.g, r, self.p) * M[0]) % self.p
     ax=pow(a_blind, self.x, self.p)
     plaintext_blind = (ax.inverse(self.p) * M[1] ) % self.p
     plaintext = (plaintext_blind * pow(self.y, r, self.p)) % self.p
     return int(plaintext)
Ejemplo n.º 30
0
    def _sign_message(privkey, msg, k=None):
        """
        create DSA signed message
        @arg privkey ... privatekey as DSA obj
        @arg msg     ... message to sign
        @arg k       ... override random k
        """

        k = k or random.StrongRandom().randint(2, privkey.q - 1)
        # generate msg hash
        # sign the messages using privkey
        h = SHA1.new(msg).digest()

        # taken from pycryptodome
        # Perform signature using the raw API
        order_bytes = (Integer(privkey.q).size_in_bits() - 1) // 8 + 1
        z = Integer.from_bytes(h[:order_bytes])
        r, s = privkey._sign(z, k)

        return h, (r, s), privkey.publickey()
Ejemplo n.º 31
0
    def _sign(self, z, k):
        assert 0 < k < _curve.order

        blind = Integer.random_range(min_inclusive=1,
                                     max_exclusive=_curve.order)

        blind_d = self._d * blind
        inv_blind_k = (blind * k).inverse(_curve.order)

        r = (_curve.G * k).x % _curve.order
        s = inv_blind_k * (blind * z + blind_d * r) % _curve.order
        return (r, s)
Ejemplo n.º 32
0
    def _sign(self, z, k):
        assert 0 < k < _curve.order

        blind = Integer.random_range(min_inclusive=1,
                                     max_exclusive=_curve.order)

        blind_d = self._d * blind
        inv_blind_k = (blind * k).inverse(_curve.order)

        r = (_curve.G * k).x % _curve.order
        s = inv_blind_k * (blind * z + blind_d * r) % _curve.order
        return (r, s)
Ejemplo n.º 33
0
    def test_random_bits_custom_rng(self):
        class CustomRNG(object):
            def __init__(self):
                self.counter = 0

            def __call__(self, size):
                self.counter += size
                return bchr(0) * size

        custom_rng = CustomRNG()
        a = IntegerGeneric.random(exact_bits=32, randfunc=custom_rng)
        self.assertEqual(custom_rng.counter, 4)
Ejemplo n.º 34
0
    def add_ssh_keys(params, endpoint, record, temp_files, non_shared):
        # type: (KeeperParams, str, Record, [str], dict) -> [bytes]
        rs = []
        key_prefix = 'connect:{0}:ssh-key'.format(endpoint)
        ssh_socket_path = os.environ.get('SSH_AUTH_SOCK')
        for cf in record.custom_fields:
            cf_name = cf['name']        # type: str
            if cf_name.startswith(key_prefix):
                key_name = cf_name[len(key_prefix)+1:] or 'Commander'
                cf_value = cf['value']  # type: str
                parsed_values = []
                while True:
                    m = endpoint_parameter_pattern.search(cf_value)
                    if not m:
                        break
                    p = m.group(1)
                    val = ConnectCommand.get_parameter_value(params, record, p, temp_files, non_shared)
                    if not val:
                        raise Exception('Add ssh-key. Failed to resolve key parameter: {0}'.format(p))
                    parsed_values.append(val)
                    cf_value = cf_value[m.end():]
                if len(parsed_values) > 0:
                    cf_value = cf_value.strip()
                    if cf_value:
                        parsed_values.append(cf_value)

                    private_key = RSA.importKey(parsed_values[0], parsed_values[1] if len(parsed_values) > 0 else None)
                    with ConnectSshAgent(ssh_socket_path) as fd:
                        payload = SSH2_AGENTC_ADD_IDENTITY.to_bytes(1, byteorder='big')
                        payload += ConnectCommand.ssh_agent_encode_str('ssh-rsa')
                        payload += ConnectCommand.ssh_agent_encode_long(private_key.n)
                        payload += ConnectCommand.ssh_agent_encode_long(private_key.e)
                        payload += ConnectCommand.ssh_agent_encode_long(private_key.d)
                        payload += ConnectCommand.ssh_agent_encode_long(int(Integer(private_key.q).inverse(private_key.p)))
                        payload += ConnectCommand.ssh_agent_encode_long(private_key.p)
                        payload += ConnectCommand.ssh_agent_encode_long(private_key.q)
                        payload += ConnectCommand.ssh_agent_encode_str(key_name)
                        # windows ssh implementation does not support constrained identities
                        #payload += SSH_AGENT_CONSTRAIN_LIFETIME.to_bytes(1, byteorder='big')
                        #payload += int(10).to_bytes(4, byteorder='big')

                        recv_payload = fd.send(payload)
                        if recv_payload and recv_payload[0] == SSH_AGENT_FAILURE:
                            raise Exception('Add ssh-key. Failed to add ssh key \"{0}\" to ssh-agent'.format(key_name))

                        payload = ConnectCommand.ssh_agent_encode_str('ssh-rsa')
                        payload += ConnectCommand.ssh_agent_encode_long(private_key.e)
                        payload += ConnectCommand.ssh_agent_encode_long(private_key.n)
                        payload = SSH2_AGENTC_REMOVE_IDENTITY.to_bytes(1, byteorder='big') + ConnectCommand.ssh_agent_encode_bytes(payload)

                        rs.append(payload)
        return rs
Ejemplo n.º 35
0
def sign(r, key):
    r_prime = r * key.d.inverse(key._curve.order)

    date = int(time.time())
    nonce = Integer.random_range(min_inclusive=1,
                                 max_exclusive=key._curve.order)
    z = f'{nonce}||{date}'

    R = r_prime + (key._curve.G * hash(z))
    s = (key.d - hash(z)) % key._curve.order
    # return (R, s, z)
    # we can not give away z or this is unsafe: x = s+h(z)
    return R, s
Ejemplo n.º 36
0
def encrypt(key, message):
    """Encrypts an integer message using the provided ElGamal key

        Includes a copy of key in the output (so be sure to use a public key; will assert error out otherwise)

        Note that this is stochastic because we randomly generate an ephemeral key each time

        ******VERY IMPORTANT*******
        The message must be a quadratic residue for DDH to hold.
        We do not ensure this in this encrypt function, because we carefully control what input messages are possible.
        Do *NOT* use this for general purpose encryption unless you first encode the message as a quadratic residue.

        Using a non-quadratic residue will look like it works, but will not be secure.
        ***************************
    """
    assert (not key.has_private())
    z = randint(2, int(key.p - 1))  # Ephemeral key
    c_1 = pow(key.g, z, key.p)  # first part of ciphertext
    s = pow(key.y, z, key.p)  # shared secret
    m = message
    c_2 = (Integer(m) * Integer(s)) % key.p
    return CipherText(key, c_1, c_2)
Ejemplo n.º 37
0
def deserialize_ElGamalPublicKey(bytestring):
    '''constructs an ElGamal Public Key from a bytestring'''
    padded_size = len(bytestring) // 3
    assert padded_size * 3 == len(bytestring), "Wrong bytestring length"
    p = Integer.from_bytes(bytestring[:padded_size])
    g = Integer.from_bytes(bytestring[padded_size:2 * padded_size])
    y = Integer.from_bytes(bytestring[2 * padded_size:])
    return ElGamal.construct((p, g, y))

    def export_val(self):
        '''Returns a bytestring.'''
        padded_size = int(np.round(key.p.size_in_bits() / 8))
        return self.c1.to_bytes(padded_size) + self.c2.to_bytes(padded_size)

    @classmethod
    def byte_init(cls, key, bytestring):
        '''Returns a Ciphertext from a bytestring containing c1 and c2'''
        padded_size = int(np.round(key.p.size_in_bits() / 8))
        assert (len(bytestring) == 2 * padded_size)
        c1 = Integer.from_bytes(bytestring[:padded_size])
        c2 = Integer.from_bytes(bytestring[padded_size:])
        return cls(key, c1, c2)
Ejemplo n.º 38
0
def hospital_round0a(key_template, key_x=None):
    '''The partial key generation phase

    If key_x is set, we'll use that instead of a new random integer

    Returns a dictionary with:
        key_x:      a new Elgamal private key secret share
        private_key: an ElGamal private key using key_x
        curr_y:     a partial public key share
        transmit:   a bytestring encoding of curr_y to send to hub
        time:       amount of time elapsed for this function
    '''
    start = time.perf_counter()
    if key_x:
        x = key_x
    else:
        x = Integer(randint(2, int(key_template.p - 1)))
    curr_y = pow(key_template.g, x, key_template.p)

    padded_size = int(np.round(key_template.p.size_in_bits() / 8))
    curr_y_bytestring = curr_y.to_bytes(padded_size)

    private_key = construct_key(key_template, x)
    assert (private_key.y == curr_y)

    elapsed = time.perf_counter() - start

    assert (Integer.from_bytes(curr_y_bytestring) == curr_y)

    answer_dict = {}
    answer_dict['key_x'] = x
    answer_dict['key_x_bytestring'] = x.to_bytes(padded_size)
    answer_dict['private_key'] = private_key
    answer_dict['private_key_export'] = serialize_ElGamalPrivateKey(
        private_key)
    answer_dict['curr_y'] = curr_y
    answer_dict['transmit'] = curr_y_bytestring
    answer_dict['time'] = elapsed
    return answer_dict
Ejemplo n.º 39
0
    def generate_rsa_key_pair():

        rsa_key = RSA.generate(2048)

        private_key = DerSequence([
            0, rsa_key.n, rsa_key.e, rsa_key.d, rsa_key.p, rsa_key.q,
            rsa_key.d % (rsa_key.p - 1), rsa_key.d % (rsa_key.q - 1),
            Integer(rsa_key.q).inverse(rsa_key.p)
        ]).encode()
        pub_key = rsa_key.publickey()
        public_key = DerSequence([pub_key.n, pub_key.e]).encode()

        return private_key, public_key
Ejemplo n.º 40
0
 def __repr__(self):
     attrs = []
     for k in self._keydata:
         if k == 'p':
             bits = Integer(self.p).size_in_bits()
             attrs.append("p(%d)" % (bits, ))
         elif hasattr(self, k):
             attrs.append(k)
     if self.has_private():
         attrs.append("private")
     # PY3K: This is meant to be text, do not change to bytes (data)
     return "<%s @0x%x %s>" % (self.__class__.__name__, id(self),
                               ",".join(attrs))
    def test_random_bits_custom_rng(self):

        class CustomRNG(object):
            def __init__(self):
                self.counter = 0

            def __call__(self, size):
                self.counter += size
                return bchr(0) * size

        custom_rng = CustomRNG()
        a = IntegerGeneric.random(exact_bits=32, randfunc=custom_rng)
        self.assertEqual(custom_rng.counter, 4)
Ejemplo n.º 42
0
def generate_p_q_g():
    start2 = timeit.default_timer()
    p = Integer(4)
    while p.size_in_bits() != 1024 or Primality.test_probable_prime(
            p) != Primality.PROBABLY_PRIME:
        q = random.randrange(1 << 159, 1 << 160)
        if (is_prime_4(q)):
            z = Integer.random(exact_bits=1024 - 160)
            p = z * q + 1

    stop2 = timeit.default_timer()
    print("Time Reqiued_1: " + str(stop2 - start2))
    start1 = timeit.default_timer()
    h = Integer(2)
    g = 1
    while g == 1:
        g = power(int(h), int(z), int(p))
        h += 1

    stop1 = timeit.default_timer()
    print("Time Reqiued_2: " + str(stop1 - start1))
    return (p, q, g)
Ejemplo n.º 43
0
def construct(tup):
    r"""Construct an ElGamal key from a tuple of valid ElGamal components.

    The modulus *p* must be a prime.
    The following conditions must apply:

    .. math::

        \begin{align}
        &1 < g < p-1 \\
        &g^{p-1} = 1 \text{ mod } 1 \\
        &1 < x < p-1 \\
        &g^x = y \text{ mod } p
        \end{align}

    Args:
      tup (tuple):
        A tuple with either 3 or 4 integers,
        in the following order:

        1. Modulus (*p*).
        2. Generator (*g*).
        3. Public key (*y*).
        4. Private key (*x*). Optional.

    Raises:
        ValueError: when the key being imported fails the most basic ElGamal validity checks.

    Returns:
        an :class:`ElGamalKey` object
    """

    obj = ElGamalKey()
    if len(tup) not in [3, 4]:
        raise ValueError('argument for construct() wrong length')
    for i in range(len(tup)):
        field = obj._keydata[i]
        setattr(obj, field, Integer(tup[i]))

    fmt_error = test_probable_prime(obj.p) == COMPOSITE
    fmt_error |= obj.g <= 1 or obj.g >= obj.p
    fmt_error |= pow(obj.g, obj.p - 1, obj.p) != 1
    fmt_error |= obj.y < 1 or obj.y >= obj.p
    if len(tup) == 4:
        fmt_error |= obj.x <= 1 or obj.x >= obj.p
        fmt_error |= pow(obj.g, obj.x, obj.p) != obj.y

    if fmt_error:
        raise ValueError("Invalid ElGamal key components")

    return obj
Ejemplo n.º 44
0
def generate_p_q_g():
	global L_bit
	global N_bit
	start_1 = timeit.default_timer()
	p = Integer(4)
	while p.size_in_bits() != N_bit or Primality.test_probable_prime(p) != Primality.PROBABLY_PRIME:
		q=random.randrange(1 << L_bit-1, 1 << L_bit)
		if(is_prime(q)):
			z = Integer.random(exact_bits=N_bit-L_bit)
			p = z * q + 1

	stop_1 = timeit.default_timer()
	print("Time Required for P & Q: "+str(stop_1-start_1))
	start_2 = timeit.default_timer()
	h = Integer(2)
	g = 1
	while g == 1:
		g = powmod(int(h), int(z), int(p))
		h += 1

	stop_2 = timeit.default_timer()
	print("Time Required for G: "+str(stop_2-start_2))
	return (p, q, g)
Ejemplo n.º 45
0
    def _decrypt(self, ciphertext):
        if not 0 <= ciphertext < self._n:
            raise ValueError("Ciphertext too large")
        if not self.has_private():
            raise TypeError("This is not a private key")

        # Blinded RSA decryption (to prevent timing attacks):
        # Step 1: Generate random secret blinding factor r,
        # such that 0 < r < n-1
        r = Integer.random_range(min_inclusive=1, max_exclusive=self._n)
        # Step 2: Compute c' = c * r**e mod n
        cp = Integer(ciphertext) * pow(r, self._e, self._n) % self._n
        # Step 3: Compute m' = c'**d mod n       (normal RSA decryption)
        m1 = pow(cp, self._dp, self._p)
        m2 = pow(cp, self._dq, self._q)
        h = ((m2 - m1) * self._u) % self._q
        mp = h * self._p + m1
        # Step 4: Compute m = m**(r-1) mod n
        result = (r.inverse(self._n) * mp) % self._n
        # Verify no faults occurred
        if ciphertext != pow(result, self._e, self._n):
            raise ValueError("Fault detected in RSA decryption")
        return result
Ejemplo n.º 46
0
    def __init__(self, key, n):
        self.key = key
        self.n = n
        # Figure out sizes needed for array
        for t in 'BHILQ':
            if array.array(t).itemsize * 8 > np.log(n) / np.log(2):
                typecode = t
                break

        y = Integer(1)
        table = [array.array(typecode) for _ in range(2**16)]
        for x in range(n):
            h = xxh64_intdigest(str(y)) % 2**16
            table[h].append(x)
            y = Integer(y) * Integer(4) % key.p
            if x % 1000000 == 0:
                print(x)

        # Figure out equivalent numpy sizes
        s = array.array(typecode).itemsize * 8
        if s <= 8:
            nptype = np.uint8
        elif s <= 16:
            nptype = np.uint16
        elif s <= 32:
            nptype = np.uint32
        elif s <= 64:
            nptype = np.uint64
        else:
            raise TypeError("No numpy type large enough to hold array")
        maxtable_length = max([len(t) for t in table])
        table_of_nps = []
        for t in table:
            t_np = np.array(t, dtype=nptype)
            t_np.resize(maxtable_length)
            table_of_nps.append(t_np)
        self.table = np.asarray(table_of_nps)
Ejemplo n.º 47
0
def _generateRSAKey(bits, randfunc=None, e=65537):
    """Modified version of pycryptodome's Crypto.RSA.generate to allow keys of any size."""

    if e % 2 == 0 or e < 3:
        raise ValueError(
            "RSA public exponent must be a positive, odd integer larger than 2."
        )

    if randfunc is None:
        randfunc = Random.get_random_bytes

    d = n = Integer(1)
    e = Integer(e)

    while n.size_in_bits() != bits and d < (1 << (bits // 2)):
        # Generate the prime factors of n: p and q.
        # By construciton, their product is always
        # 2^{bits-1} < p*q < 2^bits.
        size_q = bits // 2
        size_p = bits - size_q

        min_p = min_q = (Integer(1) << (2 * size_q - 1)).sqrt()
        if size_q != size_p:
            min_p = (Integer(1) << (2 * size_p - 1)).sqrt()

        def filter_p(candidate):
            return candidate > min_p and (candidate - 1).gcd(e) == 1

        p = _generateProbablePrime(exact_bits=size_p,
                                   randfunc=randfunc,
                                   prime_filter=filter_p)

        min_distance = Integer(1) << max(0, bits // 2 - 100)

        def filter_q(candidate):
            return (candidate > min_q and (candidate - 1).gcd(e) == 1
                    and abs(candidate - p) > min_distance)

        q = _generateProbablePrime(exact_bits=size_q,
                                   randfunc=randfunc,
                                   prime_filter=filter_q)

        n = p * q
        lcm = (p - 1).lcm(q - 1)
        d = e.inverse(lcm)

    if p > q:
        p, q = q, p

    u = p.inverse(q)

    return RSA.RsaKey(n=n, e=e, d=d, p=p, q=q, u=u)
Ejemplo n.º 48
0
def _generate_domain(L, randfunc):
    """Generate a new set of DSA domain parameters"""

    N = { 1024:160, 2048:224, 3072:256 }.get(L)
    if N is None:
        raise ValueError("Invalid modulus length (%d)" % L)

    outlen = SHA256.digest_size * 8
    n = (L + outlen - 1) // outlen - 1  # ceil(L/outlen) -1
    b_ = L - 1 - (n * outlen)

    # Generate q (A.1.1.2)
    q = Integer(4)
    upper_bit = 1 << (N - 1)
    while test_probable_prime(q, randfunc) != PROBABLY_PRIME:
        seed = randfunc(64)
        U = Integer.from_bytes(SHA256.new(seed).digest()) & (upper_bit - 1)
        q = U | upper_bit | 1

    assert(q.size_in_bits() == N)

    # Generate p (A.1.1.2)
    offset = 1
    upper_bit = 1 << (L - 1)
    while True:
        V = [ SHA256.new(seed + Integer(offset + j).to_bytes()).digest()
              for j in iter_range(n + 1) ]
        V = [ Integer.from_bytes(v) for v in V ]
        W = sum([V[i] * (1 << (i * outlen)) for i in iter_range(n)],
                (V[n] & ((1 << b_) - 1)) * (1 << (n * outlen)))

        X = Integer(W + upper_bit) # 2^{L-1} < X < 2^{L}
        assert(X.size_in_bits() == L)

        c = X % (q * 2)
        p = X - (c - 1)  # 2q divides (p-1)
        if p.size_in_bits() == L and \
           test_probable_prime(p, randfunc) == PROBABLY_PRIME:
               break
        offset += n + 1

    # Generate g (A.2.3, index=1)
    e = (p - 1) // q
    for count in itertools.count(1):
        U = seed + b"ggen" + bchr(1) + Integer(count).to_bytes()
        W = Integer.from_bytes(SHA256.new(U).digest())
        g = pow(W, e, p)
        if g != 1:
            break

    return (p, q, g, seed)
Ejemplo n.º 49
0
    def _sign(self, m, k):
        if not self.has_private():
            raise TypeError("DSA public key cannot be used for signing")
        if not (1 < k < self.q):
            raise ValueError("k is not between 2 and q-1")

        x, q, p, g = [self._key[comp] for comp in ['x', 'q', 'p', 'g']]

        blind_factor = Integer.random_range(min_inclusive=1,
                                           max_exclusive=q)
        inv_blind_k = (blind_factor * k).inverse(q)
        blind_x = x * blind_factor

        r = pow(g, k, p) % q  # r = (g**k mod p) mod q
        s = (inv_blind_k * (blind_factor * m + blind_x * r)) % q
        return map(int, (r, s))
Ejemplo n.º 50
0
    def sign(self, msg_hash):
        """Produce the DSS signature of a message.

        :Parameters:
          msg_hash : hash object
            The hash that was carried out over the message.
            The object belongs to the `Cryptodome.Hash` package.

            Under mode *'fips-186-3'*, the hash must be a FIPS
            approved secure hash (SHA-1 or a member of the SHA-2 family),
            of cryptographic strength appropriate for the DSA key.
            For instance, a 3072/256 DSA key can only be used
            in combination with SHA-512.

        :Return: The signature encoded as a byte string.
        :Raise ValueError:
            If the hash algorithm is incompatible to the DSA key.
        :Raise TypeError:
            If the DSA key has no private half.
        """

        if not self._valid_hash(msg_hash):
            raise ValueError("Hash is not sufficiently strong")

        # Generate the nonce k (critical!)
        nonce = self._compute_nonce(msg_hash)

        # Perform signature using the raw API
        z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes])
        sig_pair = self._key._sign(z, nonce)

        # Encode the signature into a single byte string
        if self._encoding == 'binary':
            output = b("").join([long_to_bytes(x, self._order_bytes)
                                 for x in sig_pair])
        else:
            # Dss-sig  ::=  SEQUENCE  {
            #               r       OCTET STRING,
            #               s       OCTET STRING
            # }
            output = DerSequence(sig_pair).encode()

        return output
Ejemplo n.º 51
0
def generate(**kwargs):
    """Generate a new private key on the given curve.

    :Keywords:
      curve : string
        Mandatory. It must be "P-256", "prime256v1" or "secp256r1".
      randfunc : callable
        Optional. The RNG to read randomness from.
        If ``None``, the system source is used.
    """

    curve = kwargs.pop("curve")
    randfunc = kwargs.pop("randfunc", get_random_bytes)
    if kwargs:
        raise TypeError("Unknown parameters: " + str(kwargs))

    d = Integer.random_range(min_inclusive=1,
                             max_exclusive=_curve.order,
                             randfunc=randfunc)

    return EccKey(curve=curve, d=d)
Ejemplo n.º 52
0
def _import_private_der(encoded, passphrase, curve_name=None):

    # ECPrivateKey ::= SEQUENCE {
    #           version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
    #           privateKey     OCTET STRING,
    #           parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
    #           publicKey  [1] BIT STRING OPTIONAL
    #    }

    private_key = DerSequence().decode(encoded, nr_elements=(3, 4))
    if private_key[0] != 1:
        raise ValueError("Incorrect ECC private key version")

    try:
        curve_name = DerObjectId(explicit=0).decode(private_key[2]).value
    except ValueError:
        pass

    if curve_name != _curve.oid:
        raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_name)

    scalar_bytes = DerOctetString().decode(private_key[1]).payload
    order_bytes = _curve.order.size_in_bytes()
    if len(scalar_bytes) != order_bytes:
        raise ValueError("Private key is too small")
    d = Integer.from_bytes(scalar_bytes)

    # Decode public key (if any, it must be P-256)
    if len(private_key) == 4:
        public_key_enc = DerBitString(explicit=1).decode(private_key[3]).value
        public_key = _import_public_der(curve_name, public_key_enc)
        point_x = public_key.pointQ.x
        point_y = public_key.pointQ.y
    else:
        point_x = point_y = None

    return construct(curve="P-256", d=d, point_x=point_x, point_y=point_y)
Ejemplo n.º 53
0
def import_key(extern_key, passphrase=None):
    """Import a DSA key.

    Args:
      extern_key (string or byte string):
        The DSA key to import.

        The following formats are supported for a DSA **public** key:

        - X.509 certificate (binary DER or PEM)
        - X.509 ``subjectPublicKeyInfo`` (binary DER or PEM)
        - OpenSSH (ASCII one-liner, see `RFC4253`_)

        The following formats are supported for a DSA **private** key:

        - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo``
          DER SEQUENCE (binary or PEM)
        - OpenSSL/OpenSSH custom format (binary or PEM)

        For details about the PEM encoding, see `RFC1421`_/`RFC1423`_.

      passphrase (string):
        In case of an encrypted private key, this is the pass phrase
        from which the decryption key is derived.

        Encryption may be applied either at the `PKCS#8`_ or at the PEM level.

    Returns:
      :class:`DsaKey` : a DSA key object

    Raises:
      ValueError : when the given key cannot be parsed (possibly because
        the pass phrase is wrong).

    .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt
    .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
    .. _RFC4253: http://www.ietf.org/rfc/rfc4253.txt
    .. _PKCS#8: http://www.ietf.org/rfc/rfc5208.txt
    """

    extern_key = tobytes(extern_key)
    if passphrase is not None:
        passphrase = tobytes(passphrase)

    if extern_key.startswith(b'-----'):
        # This is probably a PEM encoded key
        (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase)
        if enc_flag:
            passphrase = None
        return _import_key_der(der, passphrase, None)

    if extern_key.startswith(b'ssh-dss '):
        # This is probably a public OpenSSH key
        keystring = binascii.a2b_base64(extern_key.split(b' ')[1])
        keyparts = []
        while len(keystring) > 4:
            length = struct.unpack(">I", keystring[:4])[0]
            keyparts.append(keystring[4:4 + length])
            keystring = keystring[4 + length:]
        if keyparts[0] == b"ssh-dss":
            tup = [Integer.from_bytes(keyparts[x]) for x in (4, 3, 1, 2)]
            return construct(tup)

    if bord(extern_key[0]) == 0x30:
        # This is probably a DER encoded key
        return _import_key_der(extern_key, passphrase, None)

    raise ValueError("DSA key format is not supported")
Ejemplo n.º 54
0
def generate(bits, randfunc=None, e=65537):
    """Create a new RSA key.

    The algorithm closely follows NIST `FIPS 186-4`_ in its
    sections B.3.1 and B.3.3. The modulus is the product of
    two non-strong probable primes.
    Each prime passes a suitable number of Miller-Rabin tests
    with random bases and a single Lucas test.

    :Parameters:
      bits : integer
        Key length, or size (in bits) of the RSA modulus.
        It must be at least 1024.
        The FIPS standard only defines 1024, 2048 and 3072.
      randfunc : callable
        Function that returns random bytes.
        The default is `Cryptodome.Random.get_random_bytes`.
      e : integer
        Public RSA exponent. It must be an odd positive integer.
        It is typically a small number with very few ones in its
        binary representation.
        The FIPS standard requires the public exponent to be
        at least 65537 (the default).

    :Return: An RSA key object (`RsaKey`).

    .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
    """

    if bits < 1024:
        raise ValueError("RSA modulus length must be >= 1024")
    if e % 2 == 0 or e < 3:
        raise ValueError("RSA public exponent must be a positive, odd integer larger than 2.")

    if randfunc is None:
        randfunc = Random.get_random_bytes

    d = n = Integer(1)
    e = Integer(e)

    while n.size_in_bits() != bits and d < (1 << (bits // 2)):
        # Generate the prime factors of n: p and q.
        # By construciton, their product is always
        # 2^{bits-1} < p*q < 2^bits.
        size_q = bits // 2
        size_p = bits - size_q

        min_p = min_q = (Integer(1) << (2 * size_q - 1)).sqrt()
        if size_q != size_p:
            min_p = (Integer(1) << (2 * size_p - 1)).sqrt()

        def filter_p(candidate):
            return candidate > min_p and (candidate - 1).gcd(e) == 1

        p = generate_probable_prime(exact_bits=size_p,
                                    randfunc=randfunc,
                                    prime_filter=filter_p)

        min_distance = Integer(1) << (bits // 2 - 100)

        def filter_q(candidate):
            return (candidate > min_q and
                    (candidate - 1).gcd(e) == 1 and
                    abs(candidate - p) > min_distance)

        q = generate_probable_prime(exact_bits=size_q,
                                    randfunc=randfunc,
                                    prime_filter=filter_q)

        n = p * q
        lcm = (p - 1).lcm(q - 1)
        d = e.inverse(lcm)

    if p > q:
        p, q = q, p

    u = p.inverse(q)

    return RsaKey(n=n, e=e, d=d, p=p, q=q, u=u)
Ejemplo n.º 55
0
def generate(bits, randfunc):
    """Randomly generate a fresh, new ElGamal key.

    The key will be safe for use for both encryption and signature
    (although it should be used for **only one** purpose).

    Args:
      bits (int):
        Key length, or size (in bits) of the modulus *p*.
        The recommended value is 2048.
      randfunc (callable):
        Random number generation function; it should accept
        a single integer *N* and return a string of random
        *N* random bytes.

    Return:
        an :class:`ElGamalKey` object
    """

    obj=ElGamalKey()

    # Generate a safe prime p
    # See Algorithm 4.86 in Handbook of Applied Cryptography
    obj.p = generate_probable_safe_prime(exact_bits=bits, randfunc=randfunc)
    q = (obj.p - 1) >> 1

    # Generate generator g
    while 1:
        # Choose a square residue; it will generate a cyclic group of order q.
        obj.g = pow(Integer.random_range(min_inclusive=2,
                                     max_exclusive=obj.p,
                                     randfunc=randfunc), 2, obj.p)

        # We must avoid g=2 because of Bleichenbacher's attack described
        # in "Generating ElGamal signatures without knowning the secret key",
        # 1996
        if obj.g in (1, 2):
            continue

        # Discard g if it divides p-1 because of the attack described
        # in Note 11.67 (iii) in HAC
        if (obj.p - 1) % obj.g == 0:
            continue

        # g^{-1} must not divide p-1 because of Khadir's attack
        # described in "Conditions of the generator for forging ElGamal
        # signature", 2011
        ginv = obj.g.inverse(obj.p)
        if (obj.p - 1) % ginv == 0:
            continue

        # Found
        break

    # Generate private key x
    obj.x = Integer.random_range(min_inclusive=2,
                                 max_exclusive=obj.p-1,
                                 randfunc=randfunc)
    # Generate public key y
    obj.y = pow(obj.g, obj.x, obj.p)
    return obj
Ejemplo n.º 56
0
def miller_rabin_test(candidate, iterations, randfunc=None):
    """Perform a Miller-Rabin primality test on an integer.

    The test is specified in Section C.3.1 of `FIPS PUB 186-4`__.

    :Parameters:
      candidate : integer
        The number to test for primality.
      iterations : integer
        The maximum number of iterations to perform before
        declaring a candidate a probable prime.
      randfunc : callable
        An RNG function where bases are taken from.

    :Returns:
      ``Primality.COMPOSITE`` or ``Primality.PROBABLY_PRIME``.

    .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
    """

    if not isinstance(candidate, Integer):
        candidate = Integer(candidate)

    if candidate.is_even():
        return COMPOSITE

    one = Integer(1)
    minus_one = Integer(candidate - 1)

    if randfunc is None:
        randfunc = Random.new().read

    # Step 1 and 2
    m = Integer(minus_one)
    a = 0
    while m.is_even():
        m >>= 1
        a += 1

    # Skip step 3

    # Step 4
    for i in xrange(iterations):

        # Step 4.1-2
        base = 1
        while base in (one, minus_one):
            base = Integer.random_range(min_inclusive=2,
                    max_inclusive=candidate - 2)
            assert(2 <= base <= candidate - 2)

        # Step 4.3-4.4
        z = pow(base, m, candidate)
        if z in (one, minus_one):
            continue

        # Step 4.5
        for j in xrange(1, a):
            z = pow(z, 2, candidate)
            if z == minus_one:
                break
            if z == one:
                return COMPOSITE
        else:
            return COMPOSITE

    # Step 5
    return PROBABLY_PRIME
Ejemplo n.º 57
0
def generate(bits, randfunc=None, domain=None):
    """Generate a new DSA key pair.

    The algorithm follows Appendix A.1/A.2 and B.1 of `FIPS 186-4`_,
    respectively for domain generation and key pair generation.

    Args:
      bits (integer):
        Key length, or size (in bits) of the DSA modulus *p*.
        It must be 1024, 2048 or 3072.

      randfunc (callable):
        Random number generation function; it accepts a single integer N
        and return a string of random data N bytes long.
        If not specified, :func:`Cryptodome.Random.get_random_bytes` is used.

      domain (tuple):
        The DSA domain parameters *p*, *q* and *g* as a list of 3
        integers. Size of *p* and *q* must comply to `FIPS 186-4`_.
        If not specified, the parameters are created anew.

    Returns:
      :class:`DsaKey` : a new DSA key object

    Raises:
      ValueError : when **bits** is too little, too big, or not a multiple of 64.

    .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
    """

    if randfunc is None:
        randfunc = Random.get_random_bytes

    if domain:
        p, q, g = map(Integer, domain)

        ## Perform consistency check on domain parameters
        # P and Q must be prime
        fmt_error = test_probable_prime(p) == COMPOSITE
        fmt_error = test_probable_prime(q) == COMPOSITE
        # Verify Lagrange's theorem for sub-group
        fmt_error |= ((p - 1) % q) != 0
        fmt_error |= g <= 1 or g >= p
        fmt_error |= pow(g, q, p) != 1
        if fmt_error:
            raise ValueError("Invalid DSA domain parameters")
    else:
        p, q, g, _ = _generate_domain(bits, randfunc)

    L = p.size_in_bits()
    N = q.size_in_bits()

    if L != bits:
        raise ValueError("Mismatch between size of modulus (%d)"
                         " and 'bits' parameter (%d)" % (L, bits))

    if (L, N) not in [(1024, 160), (2048, 224),
                      (2048, 256), (3072, 256)]:
        raise ValueError("Lengths of p and q (%d, %d) are not compatible"
                         "to FIPS 186-3" % (L, N))

    if not 1 < g < p:
        raise ValueError("Incorrent DSA generator")

    # B.1.1
    c = Integer.random(exact_bits=N + 64)
    x = c % (q - 1) + 1 # 1 <= x <= q-1
    y = pow(g, x, p)

    key_dict = { 'y':y, 'g':g, 'p':p, 'q':q, 'x':x }
    return DsaKey(key_dict)
Ejemplo n.º 58
0
def lucas_test(candidate):
    """Perform a Lucas primality test on an integer.

    The test is specified in Section C.3.3 of `FIPS PUB 186-4`__.

    :Parameters:
      candidate : integer
        The number to test for primality.

    :Returns:
      ``Primality.COMPOSITE`` or ``Primality.PROBABLY_PRIME``.

    .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
    """

    if not isinstance(candidate, Integer):
        candidate = Integer(candidate)

    # Step 1
    if candidate.is_even() or candidate.is_perfect_square():
        return COMPOSITE

    # Step 2
    def alternate():
        sgn = 1
        value = 5
        for x in xrange(10):
            yield sgn * value
            sgn, value = -sgn, value + 2

    for D in alternate():
        js = Integer.jacobi_symbol(D, candidate)
        if js == 0:
            return COMPOSITE
        if js == -1:
            break
    else:
        return COMPOSITE
    # Found D. P=1 and Q=(1-D)/4 (note that Q is guaranteed to be an integer)

    # Step 3
    # This is \delta(n) = n - jacobi(D/n)
    K = candidate + 1
    # Step 4
    r = K.size_in_bits() - 1
    # Step 5
    # U_1=1 and V_1=P
    U_i = Integer(1)
    V_i = Integer(1)
    U_temp = Integer(0)
    V_temp = Integer(0)
    # Step 6
    for i in xrange(r - 1, -1, -1):
        # Square
        # U_temp = U_i * V_i % candidate
        U_temp.set(U_i)
        U_temp *= V_i
        U_temp %= candidate
        # V_temp = (((V_i ** 2 + (U_i ** 2 * D)) * K) >> 1) % candidate
        V_temp.set(U_i)
        V_temp *= U_i
        V_temp *= D
        V_temp.multiply_accumulate(V_i, V_i)
        if V_temp.is_odd():
            V_temp += candidate
        V_temp >>= 1
        V_temp %= candidate
        # Multiply
        if K.get_bit(i):
            # U_i = (((U_temp + V_temp) * K) >> 1) % candidate
            U_i.set(U_temp)
            U_i += V_temp
            if U_i.is_odd():
                U_i += candidate
            U_i >>= 1
            U_i %= candidate
            # V_i = (((V_temp + U_temp * D) * K) >> 1) % candidate
            V_i.set(V_temp)
            V_i.multiply_accumulate(U_temp, D)
            if V_i.is_odd():
                V_i += candidate
            V_i >>= 1
            V_i %= candidate
        else:
            U_i.set(U_temp)
            V_i.set(V_temp)
    # Step 7
    if U_i == 0:
        return PROBABLY_PRIME
    return COMPOSITE
Ejemplo n.º 59
0
def construct(rsa_components, consistency_check=True):
    """Construct an RSA key from a tuple of valid RSA components.

    The modulus **n** must be the product of two primes.
    The public exponent **e** must be odd and larger than 1.

    In case of a private key, the following equations must apply:

    - e != 1
    - p*q = n
    - e*d = 1 mod lcm[(p-1)(q-1)]
    - p*u = 1 mod q

    :Parameters:
     rsa_components : tuple
        A tuple of long integers, with at least 2 and no
        more than 6 items. The items come in the following order:

            1. RSA modulus (*n*).
            2. Public exponent (*e*).
            3. Private exponent (*d*).
               Only required if the key is private.
            4. First factor of *n* (*p*).
               Optional, but factor q must also be present.
            5. Second factor of *n* (*q*). Optional.
            6. CRT coefficient, *(1/p) mod q* (*u*). Optional.
     consistency_check : boolean
        If *True*, the library will verify that the provided components
        fulfil the main RSA properties.

    :Raise ValueError:
        When the key being imported fails the most basic RSA validity checks.
    :Return: An RSA key object (`RsaKey`).
    """

    class InputComps(object):
        pass

    input_comps = InputComps()
    for (comp, value) in zip(('n', 'e', 'd', 'p', 'q', 'u'), rsa_components):
        setattr(input_comps, comp, Integer(value))

    n = input_comps.n
    e = input_comps.e
    if not hasattr(input_comps, 'd'):
        key = RsaKey(n=n, e=e)
    else:
        d = input_comps.d
        if hasattr(input_comps, 'q'):
            p = input_comps.p
            q = input_comps.q
        else:
            # Compute factors p and q from the private exponent d.
            # We assume that n has no more than two factors.
            # See 8.2.2(i) in Handbook of Applied Cryptography.
            ktot = d * e - 1
            # The quantity d*e-1 is a multiple of phi(n), even,
            # and can be represented as t*2^s.
            t = ktot
            while t % 2 == 0:
                t //= 2
            # Cycle through all multiplicative inverses in Zn.
            # The algorithm is non-deterministic, but there is a 50% chance
            # any candidate a leads to successful factoring.
            # See "Digitalized Signatures and Public Key Functions as Intractable
            # as Factorization", M. Rabin, 1979
            spotted = False
            a = Integer(2)
            while not spotted and a < 100:
                k = Integer(t)
                # Cycle through all values a^{t*2^i}=a^k
                while k < ktot:
                    cand = pow(a, k, n)
                    # Check if a^k is a non-trivial root of unity (mod n)
                    if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1:
                        # We have found a number such that (cand-1)(cand+1)=0 (mod n).
                        # Either of the terms divides n.
                        p = Integer(n).gcd(cand + 1)
                        spotted = True
                        break
                    k *= 2
                # This value was not any good... let's try another!
                a += 2
            if not spotted:
                raise ValueError("Unable to compute factors p and q from exponent d.")
            # Found !
            assert ((n % p) == 0)
            q = n // p

        if hasattr(input_comps, 'u'):
            u = input_comps.u
        else:
            u = p.inverse(q)

        # Build key object
        key = RsaKey(n=n, e=e, d=d, p=p, q=q, u=u)

    # Very consistency of the key
    fmt_error = False
    if consistency_check:
        # Modulus and public exponent must be coprime
        fmt_error = e <= 1 or e >= n
        fmt_error |= Integer(n).gcd(e) != 1

        # For RSA, modulus must be odd
        fmt_error |= not n & 1

        if not fmt_error and key.has_private():
            # Modulus and private exponent must be coprime
            fmt_error = d <= 1 or d >= n
            fmt_error |= Integer(n).gcd(d) != 1
            # Modulus must be product of 2 primes
            fmt_error |= (p * q != n)
            fmt_error |= test_probable_prime(p) == COMPOSITE
            fmt_error |= test_probable_prime(q) == COMPOSITE
            # See Carmichael theorem
            phi = (p - 1) * (q - 1)
            lcm = phi // (p - 1).gcd(q - 1)
            fmt_error |= (e * d % int(lcm)) != 1
            if hasattr(key, 'u'):
                # CRT coefficient
                fmt_error |= u <= 1 or u >= q
                fmt_error |= (p * u % q) != 1
            else:
                fmt_error = True

    if fmt_error:
        raise ValueError("Invalid RSA key components")

    return key
Ejemplo n.º 60
0
def import_key(extern_key, passphrase=None):
    """Import an RSA key (public or private half), encoded in standard
    form.

    :Parameter extern_key:
        The RSA key to import, encoded as a byte string.

        An RSA public key can be in any of the following formats:

        - X.509 certificate (binary or PEM format)
        - X.509 ``subjectPublicKeyInfo`` DER SEQUENCE (binary or PEM
          encoding)
        - `PKCS#1`_ ``RSAPublicKey`` DER SEQUENCE (binary or PEM encoding)
        - OpenSSH (textual public key only)

        An RSA private key can be in any of the following formats:

        - PKCS#1 ``RSAPrivateKey`` DER SEQUENCE (binary or PEM encoding)
        - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo``
          DER SEQUENCE (binary or PEM encoding)
        - OpenSSH (textual public key only)

        For details about the PEM encoding, see `RFC1421`_/`RFC1423`_.

        The private key may be encrypted by means of a certain pass phrase
        either at the PEM level or at the PKCS#8 level.
    :Type extern_key: string

    :Parameter passphrase:
        In case of an encrypted private key, this is the pass phrase from
        which the decryption key is derived.
    :Type passphrase: string

    :Return: An RSA key object (`RsaKey`).

    :Raise ValueError/IndexError/TypeError:
        When the given key cannot be parsed (possibly because the pass
        phrase is wrong).

    .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt
    .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
    .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt
    .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt
    """
    extern_key = tobytes(extern_key)
    if passphrase is not None:
        passphrase = tobytes(passphrase)

    if extern_key.startswith(b('-----')):
        # This is probably a PEM encoded key.
        (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase)
        if enc_flag:
            passphrase = None
        return _import_keyDER(der, passphrase)

    if extern_key.startswith(b('ssh-rsa ')):
            # This is probably an OpenSSH key
            keystring = binascii.a2b_base64(extern_key.split(b(' '))[1])
            keyparts = []
            while len(keystring) > 4:
                l = struct.unpack(">I", keystring[:4])[0]
                keyparts.append(keystring[4:4 + l])
                keystring = keystring[4 + l:]
            e = Integer.from_bytes(keyparts[1])
            n = Integer.from_bytes(keyparts[2])
            return construct([n, e])

    if bord(extern_key[0]) == 0x30:
            # This is probably a DER encoded key
            return _import_keyDER(extern_key, passphrase)

    raise ValueError("RSA key format is not supported")