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 range(n + 1) ] V = [Integer.from_bytes(v) for v in V] W = sum([V[i] * (1 << (i * outlen)) for i in 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)
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)
def test_is_prime(self): primes = (170141183460469231731687303715884105727, 19175002942688032928599, 1363005552434666078217421284621279933627102780881053358473, 2**521 - 1) for p in primes: self.assertEqual(test_probable_prime(p), PROBABLY_PRIME) not_primes = ( 4754868377601046732119933839981363081972014948522510826417784001, 1334733877147062382486934807105197899496002201113849920496510541601, 260849323075371835669784094383812120359260783810157225730623388382401, ) for np in not_primes: self.assertEqual(test_probable_prime(np), COMPOSITE)
def test_is_prime(self): primes = (170141183460469231731687303715884105727, 19175002942688032928599, 1363005552434666078217421284621279933627102780881053358473, 2 ** 521 - 1) for p in primes: self.assertEqual(test_probable_prime(p), PROBABLY_PRIME) not_primes = ( 4754868377601046732119933839981363081972014948522510826417784001, 1334733877147062382486934807105197899496002201113849920496510541601, 260849323075371835669784094383812120359260783810157225730623388382401, ) for np in not_primes: self.assertEqual(test_probable_prime(np), COMPOSITE)
def construct(tup, consistency_check=True): """Construct a DSA key from a tuple of valid DSA components. Args: tup (tuple): A tuple of long integers, with 4 or 5 items in the following order: 1. Public key (*y*). 2. Sub-group generator (*g*). 3. Modulus, finite field order (*p*). 4. Sub-group order (*q*). 5. Private key (*x*). Optional. consistency_check (boolean): If ``True``, the library will verify that the provided components fulfil the main DSA properties. Raises: ValueError: when the key being imported fails the most basic DSA validity checks. Returns: :class:`DsaKey` : a DSA key object """ key_dict = dict( list(zip(('y', 'g', 'p', 'q', 'x'), list(map(Integer, tup))))) key = DsaKey(key_dict) fmt_error = False if consistency_check: # P and Q must be prime fmt_error = test_probable_prime(key.p) == COMPOSITE fmt_error = test_probable_prime(key.q) == COMPOSITE # Verify Lagrange's theorem for sub-group fmt_error |= ((key.p - 1) % key.q) != 0 fmt_error |= key.g <= 1 or key.g >= key.p fmt_error |= pow(key.g, key.q, key.p) != 1 # Public key fmt_error |= key.y <= 0 or key.y >= key.p if hasattr(key, 'x'): fmt_error |= key.x <= 0 or key.x >= key.q fmt_error |= pow(key.g, key.x, key.p) != key.y if fmt_error: raise ValueError("Invalid DSA key components") return key
def construct(tup, consistency_check=True): """Construct a DSA key from a tuple of valid DSA components. Args: tup (tuple): A tuple of long integers, with 4 or 5 items in the following order: 1. Public key (*y*). 2. Sub-group generator (*g*). 3. Modulus, finite field order (*p*). 4. Sub-group order (*q*). 5. Private key (*x*). Optional. consistency_check (boolean): If ``True``, the library will verify that the provided components fulfil the main DSA properties. Raises: ValueError: when the key being imported fails the most basic DSA validity checks. Returns: :class:`DsaKey` : a DSA key object """ key_dict = dict(zip(('y', 'g', 'p', 'q', 'x'), map(Integer, tup))) key = DsaKey(key_dict) fmt_error = False if consistency_check: # P and Q must be prime fmt_error = test_probable_prime(key.p) == COMPOSITE fmt_error = test_probable_prime(key.q) == COMPOSITE # Verify Lagrange's theorem for sub-group fmt_error |= ((key.p - 1) % key.q) != 0 fmt_error |= key.g <= 1 or key.g >= key.p fmt_error |= pow(key.g, key.q, key.p) != 1 # Public key fmt_error |= key.y <= 0 or key.y >= key.p if hasattr(key, 'x'): fmt_error |= key.x <= 0 or key.x >= key.q fmt_error |= pow(key.g, key.x, key.p) != key.y if fmt_error: raise ValueError("Invalid DSA key components") return key
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
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
def construct(tup): """Construct an ElGamal key from a tuple of valid ElGamal components. The modulus *p* must be a prime. The following conditions must apply: - 1 < g < p-1 - g^{p-1} = 1 mod p - 1 < x < p-1 - g^x = y mod p :Parameters: tup : tuple A tuple of long integers, with 3 or 4 items in the following order: 1. Modulus (*p*). 2. Generator (*g*). 3. Public key (*y*). 4. Private key (*x*). Optional. :Raise PublicKey.ValueError: When the key being imported fails the most basic ElGamal validity checks. :Return: An ElGamal key object (`ElGamalKey`). """ 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
def construct(tup): """Construct an ElGamal key from a tuple of valid ElGamal components. The modulus *p* must be a prime. The following conditions must apply: - 1 < g < p-1 - g^{p-1} = 1 mod p - 1 < x < p-1 - g^x = y mod p :Parameters: tup : tuple A tuple of long integers, with 3 or 4 items in the following order: 1. Modulus (*p*). 2. Generator (*g*). 3. Public key (*y*). 4. Private key (*x*). Optional. :Raise PublicKey.ValueError: When the key being imported fails the most basic ElGamal validity checks. :Return: An ElGamal key object (`ElGamalKey`). """ 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
def _generateProbablePrime(**kwargs): """Modified version of pycryptodome's Cryptodome.Math.Primality.generate_probable_prime to create primes of any size.""" 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 randfunc is None: randfunc = Random.new().read result = 0 while result == 0: candidate = Integer.random(exact_bits=exact_bits, randfunc=randfunc) | 1 if not prime_filter(candidate): continue result = test_probable_prime(candidate, randfunc) return candidate
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)
def construct(rsa_components, consistency_check=True): r"""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: .. math:: \begin{align} p*q &= n \\ e*d &\equiv 1 ( \text{mod lcm} [(p-1)(q-1)]) \\ p*u &\equiv 1 ( \text{mod } q) \end{align} Args: rsa_components (tuple): A tuple of 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 the other factor *q* must also be present. 5. Second factor of *n* (*q*). Optional. 6. CRT coefficient *q*, that is :math:`p^{-1} \text{mod }q`. Optional. consistency_check (boolean): If ``True``, the library will verify that the provided components fulfil the main RSA properties. Raises: ValueError: when the key being imported fails the most basic RSA validity checks. Returns: An RSA key object (:class:`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) # Verify consistency of the key if consistency_check: # Modulus and public exponent must be coprime if e <= 1 or e >= n: raise ValueError("Invalid RSA public exponent") if Integer(n).gcd(e) != 1: raise ValueError("RSA public exponent is not coprime to modulus") # For RSA, modulus must be odd if not n & 1: raise ValueError("RSA modulus is not odd") if key.has_private(): # Modulus and private exponent must be coprime if d <= 1 or d >= n: raise ValueError("Invalid RSA private exponent") if Integer(n).gcd(d) != 1: raise ValueError( "RSA private exponent is not coprime to modulus") # Modulus must be product of 2 primes if p * q != n: raise ValueError("RSA factors do not match modulus") if test_probable_prime(p) == COMPOSITE: raise ValueError("RSA factor p is composite") if test_probable_prime(q) == COMPOSITE: raise ValueError("RSA factor q is composite") # See Carmichael theorem phi = (p - 1) * (q - 1) lcm = phi // (p - 1).gcd(q - 1) if (e * d % int(lcm)) != 1: raise ValueError("Invalid RSA condition") if hasattr(key, 'u'): # CRT coefficient if u <= 1 or u >= q: raise ValueError("Invalid RSA component u") if (p * u % q) != 1: raise ValueError("Invalid RSA component u with p") return key
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
def construct(rsa_components, consistency_check=True): r"""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: .. math:: \begin{align} p*q &= n \\ e*d &\equiv 1 ( \text{mod lcm} [(p-1)(q-1)]) \\ p*u &\equiv 1 ( \text{mod } q) \end{align} Args: rsa_components (tuple): A tuple of 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 the other factor *q* must also be present. 5. Second factor of *n* (*q*). Optional. 6. CRT coefficient *q*, that is :math:`p^{-1} \text{mod }q`. Optional. consistency_check (boolean): If ``True``, the library will verify that the provided components fulfil the main RSA properties. Raises: ValueError: when the key being imported fails the most basic RSA validity checks. Returns: An RSA key object (:class:`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) # Verify consistency of the key if consistency_check: # Modulus and public exponent must be coprime if e <= 1 or e >= n: raise ValueError("Invalid RSA public exponent") if Integer(n).gcd(e) != 1: raise ValueError("RSA public exponent is not coprime to modulus") # For RSA, modulus must be odd if not n & 1: raise ValueError("RSA modulus is not odd") if key.has_private(): # Modulus and private exponent must be coprime if d <= 1 or d >= n: raise ValueError("Invalid RSA private exponent") if Integer(n).gcd(d) != 1: raise ValueError("RSA private exponent is not coprime to modulus") # Modulus must be product of 2 primes if p * q != n: raise ValueError("RSA factors do not match modulus") if test_probable_prime(p) == COMPOSITE: raise ValueError("RSA factor p is composite") if test_probable_prime(q) == COMPOSITE: raise ValueError("RSA factor q is composite") # See Carmichael theorem phi = (p - 1) * (q - 1) lcm = phi // (p - 1).gcd(q - 1) if (e * d % int(lcm)) != 1: raise ValueError("Invalid RSA condition") if hasattr(key, 'u'): # CRT coefficient if u <= 1 or u >= q: raise ValueError("Invalid RSA component u") if (p * u % q) != 1: raise ValueError("Invalid RSA component u with p") return key
from Cryptodome.Math.Primality import test_probable_prime, PROBABLY_PRIME if __name__ == '__main__': def test_is_prime(self): primes = (170141183460469231731687303715884105727, 19175002942688032928599, 1363005552434666078217421284621279933627102780881053358473, 2 ** 521 - 1) for p in primes: self.assertEqual(test_probable_prime(p), PROBABLY_PRIME) not_primes = ( 4754868377601046732119933839981363081972014948522510826417784001, 1334733877147062382486934807105197899496002201113849920496510541601, 260849323075371835669784094383812120359260783810157225730623388382401, ) for np in not_primes: print("Testing: " + str(np)) self.assertEqual(test_probable_prime(np), COMPOSITE) test_probable_prime(154743920677524552878070707053653332164299660841830017929219293685667568749444998811975815665714544229961357864264853363027916649474815493349075187664296498790933188677300801346467014816215858961315576749068407287703797236061946292920294032557578225336038654226866190187355275296415885620268049747332071961711)