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 MGF1(mgfSeed, maskLen, hash_gen): """Mask Generation Function, described in `B.2.1 of RFC8017 <https://tools.ietf.org/html/rfc8017>`_. :param mfgSeed: seed from which the mask is generated :type mfgSeed: byte string :param maskLen: intended length in bytes of the mask :type maskLen: integer :param hash_gen: A module or a hash object from :mod:`crypto.Hash` :type hash_object: :return: the mask, as a *byte string* """ T = b"" for counter in iter_range(ceil_div(maskLen, hash_gen.digest_size)): c = long_to_bytes(counter, 4) hobj = hash_gen.new() hobj.update(mgfSeed + c) T = T + hobj.digest() assert (len(T) >= maskLen) return T[:maskLen]
def _tonelli_shanks(n, p): """Tonelli-shanks algorithm for computing the square root of n modulo a prime p. n must be in the range [0..p-1]. p must be at least even. The return value r is the square root of modulo p. If non-zero, another solution will also exist (p-r). Note we cannot assume that p is really a prime: if it's not, we can either raise an exception or return the correct value. """ # See https://rosettacode.org/wiki/Tonelli-Shanks_algorithm if n in (0, 1): return n if p % 4 == 3: root = pow(n, (p + 1) // 4, p) if pow(root, 2, p) != n: raise ValueError("Cannot compute square root") return root s = 1 q = (p - 1) // 2 while not (q & 1): s += 1 q >>= 1 z = n.__class__(2) while True: euler = pow(z, (p - 1) // 2, p) if euler == 1: z += 1 continue if euler == p - 1: break # Most probably p is not a prime raise ValueError("Cannot compute square root") m = s c = pow(z, q, p) t = pow(n, q, p) r = pow(n, (q + 1) // 2, p) while t != 1: for i in iter_range(0, m): if pow(t, 2**i, p) == 1: break if i == m: raise ValueError("Cannot compute square root of %d mod %d" % (n, p)) b = pow(c, 2**(m - i - 1), p) m = i c = b**2 % p t = (t * b**2) % p r = (r * b) % p if pow(r, 2, p) != n: raise ValueError("Cannot compute square root") return r
def _EMSA_PSS_VERIFY(mhash, em, emBits, mgf, sLen): """ Implement the ``EMSA-PSS-VERIFY`` function, as defined in PKCS#1 v2.1 (RFC3447, 9.1.2). ``EMSA-PSS-VERIFY`` actually accepts the message ``M`` as input, and hash it internally. Here, we expect that the message has already been hashed instead. :Parameters: mhash : hash object The hash object that holds the digest of the message to be verified. em : string The signature to verify, therefore proving that the sender really signed the message that was received. emBits : int Length of the final encoding (em), in bits. mgf : callable A mask generation function that accepts two parameters: a string to use as seed, and the lenth of the mask to generate, in bytes. sLen : int Length of the salt, in bytes. :Raise ValueError: When the encoding is inconsistent, or the digest or salt lengths are too big. """ emLen = ceil_div(emBits, 8) # Bitmask of digits that fill up lmask = 0 for i in iter_range(8 * emLen - emBits): lmask = lmask >> 1 | 0x80 # Step 1 and 2 have been already done # Step 3 if emLen < mhash.digest_size + sLen + 2: raise ValueError("Incorrect signature") # Step 4 if ord(em[-1:]) != 0xBC: raise ValueError("Incorrect signature") # Step 5 maskedDB = em[:emLen - mhash.digest_size - 1] h = em[emLen - mhash.digest_size - 1:-1] # Step 6 if lmask & bord(em[0]): raise ValueError("Incorrect signature") # Step 7 dbMask = mgf(h, emLen - mhash.digest_size - 1) # Step 8 db = strxor(maskedDB, dbMask) # Step 9 db = bchr(bord(db[0]) & ~lmask) + db[1:] # Step 10 if not db.startswith( bchr(0) * (emLen - mhash.digest_size - sLen - 2) + bchr(1)): raise ValueError("Incorrect signature") # Step 11 if sLen > 0: salt = db[-sLen:] else: salt = b"" # Step 12 m_prime = bchr(0) * 8 + mhash.digest() + salt # Step 13 hobj = mhash.new() hobj.update(m_prime) hp = hobj.digest() # Step 14 if h != hp: raise ValueError("Incorrect signature")
def _EMSA_PSS_ENCODE(mhash, emBits, randFunc, mgf, sLen): r""" Implement the ``EMSA-PSS-ENCODE`` function, as defined in PKCS#1 v2.1 (RFC3447, 9.1.1). The original ``EMSA-PSS-ENCODE`` actually accepts the message ``M`` as input, and hash it internally. Here, we expect that the message has already been hashed instead. :Parameters: mhash : hash object The hash object that holds the digest of the message being signed. emBits : int Maximum length of the final encoding, in bits. randFunc : callable An RNG function that accepts as only parameter an int, and returns a string of random bytes, to be used as salt. mgf : callable A mask generation function that accepts two parameters: a string to use as seed, and the lenth of the mask to generate, in bytes. sLen : int Length of the salt, in bytes. :Return: An ``emLen`` byte long string that encodes the hash (with ``emLen = \ceil(emBits/8)``). :Raise ValueError: When digest or salt length are too big. """ emLen = ceil_div(emBits, 8) # Bitmask of digits that fill up lmask = 0 for i in iter_range(8 * emLen - emBits): lmask = lmask >> 1 | 0x80 # Step 1 and 2 have been already done # Step 3 if emLen < mhash.digest_size + sLen + 2: raise ValueError("Digest or salt length are too long" " for given key size.") # Step 4 salt = randFunc(sLen) # Step 5 m_prime = bchr(0) * 8 + mhash.digest() + salt # Step 6 h = mhash.new() h.update(m_prime) # Step 7 ps = bchr(0) * (emLen - sLen - mhash.digest_size - 2) # Step 8 db = ps + bchr(1) + salt # Step 9 dbMask = mgf(h.digest(), emLen - mhash.digest_size - 1) # Step 10 maskedDB = strxor(db, dbMask) # Step 11 maskedDB = bchr(bord(maskedDB[0]) & ~lmask) + maskedDB[1:] # Step 12 em = maskedDB + h.digest() + bchr(0xBC) return em
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 in (1, 2, 3, 5): return PROBABLY_PRIME 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 iter_range(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 iter_range(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
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 in (1, 2, 3, 5): return PROBABLY_PRIME if candidate.is_even() or candidate.is_perfect_square(): return COMPOSITE # Step 2 def alternate(): value = 5 while True: yield value if value > 0: value += 2 else: value -= 2 value = -value for D in alternate(): if candidate in (D, -D): continue js = Integer.jacobi_symbol(D, candidate) if js == 0: return COMPOSITE if js == -1: break # 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 iter_range(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