예제 #1
0
def rsa_construct(n, e, d=None, p=None, q=None, u=None):
    """Construct an RSAKey object"""
    assert isinstance(n, int)
    assert isinstance(e, int)
    assert isinstance(d, (int, type(None)))
    assert isinstance(p, (int, type(None)))
    assert isinstance(q, (int, type(None)))
    assert isinstance(u, (int, type(None)))
    obj = _RSAKey()
    obj.n = n
    obj.e = e
    if d is None:
        return obj
    obj.d = d
    if p is not None and q is not None:
        obj.p = p
        obj.q = 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 = divmod(t, 2)[0]
        # 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 = 0
        a = 2
        while not spotted and a < 100:
            k = 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.
                    obj.p = GCD(cand + 1, n)
                    spotted = 1
                    break
                k = k * 2
            # This value was not any good... let's try another!
            a = a + 2
        if not spotted:
            raise ValueError(
                "Unable to compute factors p and q from exponent d.")
        # Found !
        assert ((n % obj.p) == 0)
        obj.q = divmod(n, obj.p)[0]
    if u is not None:
        obj.u = u
    else:
        obj.u = inverse(obj.p, obj.q)
    return obj
예제 #2
0
 def _decrypt(self, M):
     if (not hasattr(self, 'x')):
         raise TypeError('Private key not available in this object')
     r = number.getRandomRange(2, self.p - 1, self._randfunc)
     a_blind = (M[0] * pow(self.g, r, self.p)) % self.p
     ax = pow(a_blind, self.x, self.p)
     plaintext_blind = (M[1] * number.inverse(ax, self.p)) % self.p
     plaintext = (plaintext_blind * pow(self.y, r, self.p)) % self.p
     return plaintext
예제 #3
0
 def _verify(self, m, r, s):
     # SECURITY TODO - We _should_ be computing SHA1(m), but we don't because that's the API.
     if not (0 < r < self.q) or not (0 < s < self.q):
         return False
     w = inverse(s, self.q)
     u1 = (m * w) % self.q
     u2 = (r * w) % self.q
     v = (pow(self.g, u1, self.p) * pow(self.y, u2, self.p) %
          self.p) % self.q
     return v == r
예제 #4
0
 def _sign(self, m, k):  # alias for _decrypt
     # SECURITY TODO - We _should_ be computing SHA1(m), but we don't because that's the API.
     if not self.has_private():
         raise TypeError("No private key")
     if not (1 < k < self.q):
         raise ValueError("k is not between 2 and q-1")
     inv_k = inverse(k, self.q)  # Compute k**-1 mod q
     r = pow(self.g, k, self.p) % self.q  # r = (g**k mod p) mod q
     s = (inv_k * (m + self.x * r)) % self.q
     return (r, s)
예제 #5
0
 def _sign(self, M, K):
     if (not hasattr(self, 'x')):
         raise TypeError('Private key not available in this object')
     p1 = self.p - 1
     if (number.GCD(K, p1) != 1):
         raise ValueError('Bad K value: GCD(K,p-1)!=1')
     a = pow(self.g, K, self.p)
     t = (M - self.x * a) % p1
     while t < 0:
         t = t + p1
     b = (t * number.inverse(K, p1)) % p1
     return (a, b)
예제 #6
0
    def _importKeyDER(self, externKey):
        """Import an RSA key (public or private half), encoded in DER form."""

        try:

            der = DerSequence()
            der.decode(externKey, True)

            # Try PKCS#1 first, for a private key
            if len(der) == 9 and der.hasOnlyInts() and der[0] == 0:
                # ASN.1 RSAPrivateKey element
                del der[
                    6:]  # Remove d mod (p-1), d mod (q-1), and q^{-1} mod p
                der.append(inverse(der[4], der[5]))  # Add p^{-1} mod q
                del der[0]  # Remove version
                return self.construct(der[:])

            # Keep on trying PKCS#1, but now for a public key
            if len(der) == 2:
                # The DER object is an RSAPublicKey SEQUENCE with two elements
                if der.hasOnlyInts():
                    return self.construct(der[:])
                # The DER object is a SubjectPublicKeyInfo SEQUENCE with two elements:
                # an 'algorithm' (or 'algorithmIdentifier') SEQUENCE and a 'subjectPublicKey' BIT STRING.
                # 'algorithm' takes the value given a few lines above.
                # 'subjectPublicKey' encapsulates the actual ASN.1 RSAPublicKey element.
                if der[0] == algorithmIdentifier:
                    bitmap = DerObject()
                    bitmap.decode(der[1], True)
                    if bitmap.isType('BIT STRING') and bord(
                            bitmap.payload[0]) == 0x00:
                        der.decode(bitmap.payload[1:], True)
                        if len(der) == 2 and der.hasOnlyInts():
                            return self.construct(der[:])

            # Try unencrypted PKCS#8
            if der[0] == 0:
                # The second element in the SEQUENCE is algorithmIdentifier.
                # It must say RSA (see above for description).
                if der[1] == algorithmIdentifier:
                    privateKey = DerObject()
                    privateKey.decode(der[2], True)
                    if privateKey.isType('OCTET STRING'):
                        return self._importKeyDER(privateKey.payload)

        except ValueError as IndexError:
            pass

        raise ValueError("RSA key format is not supported")
예제 #7
0
 def _unblind(self, m, r):
     # compute m / r (mod n)
     return inverse(r, self.n) * m % self.n
예제 #8
0
    def exportKey(self, format='PEM', passphrase=None, pkcs=1):
        """Export this RSA key.

        :Parameter format: The format to use for wrapping the key.

            - *'DER'*. Binary encoding, always unencrypted.
            - *'PEM'*. Textual encoding, done according to `RFC1421`_/`RFC1423`_.
              Unencrypted (default) or encrypted.
            - *'OpenSSH'*. Textual encoding, done according to OpenSSH specification.
              Only suitable for public keys (not private keys).
        :Type format: string

        :Parameter passphrase: In case of PEM, the pass phrase to derive the encryption key from.
        :Type passphrase: string 

        :Parameter pkcs: The PKCS standard to follow for assembling the key.
         You have two choices:

          - with **1**, the public key is embedded into an X.509 `SubjectPublicKeyInfo` DER SEQUENCE.
            The private key is embedded into a `PKCS#1`_ `RSAPrivateKey` DER SEQUENCE.
            This mode is the default.
          - with **8**, the private key is embedded into a `PKCS#8`_ `PrivateKeyInfo` DER SEQUENCE.
            This mode is not available for public keys.

         PKCS standards are not relevant for the *OpenSSH* format.
        :Type pkcs: integer

        :Return: A byte string with the encoded public or private half.
        :Raise ValueError:
            When the format is unknown.

        .. _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
        """
        if passphrase is not None:
            passphrase = tobytes(passphrase)
        if format == 'OpenSSH':
            eb = long_to_bytes(self.e)
            nb = long_to_bytes(self.n)
            if bord(eb[0]) & 0x80: eb = bchr(0x00) + eb
            if bord(nb[0]) & 0x80: nb = bchr(0x00) + nb
            keyparts = ['ssh-rsa', eb, nb]
            keystring = ''.join(
                [struct.pack(">I", len(kp)) + kp for kp in keyparts])
            return 'ssh-rsa ' + binascii.b2a_base64(keystring)[:-1]

        # DER format is always used, even in case of PEM, which simply
        # encodes it into BASE64.
        der = DerSequence()
        if self.has_private():
            keyType = {1: 'RSA PRIVATE', 8: 'PRIVATE'}[pkcs]
            der[:] = [
                0, self.n, self.e, self.d, self.p, self.q,
                self.d % (self.p - 1), self.d % (self.q - 1),
                inverse(self.q, self.p)
            ]
            if pkcs == 8:
                derkey = der.encode()
                der = DerSequence([0])
                der.append(algorithmIdentifier)
                der.append(DerObject('OCTET STRING', derkey).encode())
        else:
            keyType = "PUBLIC"
            der.append(algorithmIdentifier)
            bitmap = DerObject('BIT STRING')
            derPK = DerSequence([self.n, self.e])
            bitmap.payload = bchr(0x00) + derPK.encode()
            der.append(bitmap.encode())
        if format == 'DER':
            return der.encode()
        if format == 'PEM':
            pem = b("-----BEGIN " + keyType + " KEY-----\n")
            objenc = None
            if passphrase and keyType.endswith('PRIVATE'):
                # We only support 3DES for encryption
                import Crypto.Hash.MD5
                from Crypto.Cipher import DES3
                from Crypto.Protocol.KDF import PBKDF1
                salt = self._randfunc(8)
                key = PBKDF1(passphrase, salt, 16, 1, Crypto.Hash.MD5)
                key += PBKDF1(key + passphrase, salt, 8, 1, Crypto.Hash.MD5)
                objenc = DES3.new(key, Crypto.Cipher.DES3.MODE_CBC, salt)
                pem += b('Proc-Type: 4,ENCRYPTED\n')
                pem += b('DEK-Info: DES-EDE3-CBC,') + binascii.b2a_hex(
                    salt).upper() + b('\n\n')

            binaryKey = der.encode()
            if objenc:
                # Add PKCS#7-like padding
                padding = objenc.block_size - len(
                    binaryKey) % objenc.block_size
                binaryKey = objenc.encrypt(binaryKey + bchr(padding) * padding)

            # Each BASE64 line can take up to 64 characters (=48 bytes of data)
            chunks = [
                binascii.b2a_base64(binaryKey[i:i + 48])
                for i in range(0, len(binaryKey), 48)
            ]
            pem += b('').join(chunks)
            pem += b("-----END " + keyType + " KEY-----")
            return pem
        return ValueError(
            "Unknown key format '%s'. Cannot export the RSA key." % format)
예제 #9
0
def generate(bits, randfunc, progress_func=None):
    """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).

    :Parameters:
        bits : int
            Key length, or size (in bits) of the modulus *p*.
            Recommended value is 2048.
        randfunc : callable
            Random number generation function; it should accept
            a single integer N and return a string of random data
            N bytes long.
        progress_func : callable
            Optional function that will be called with a short string
            containing the key parameter currently being generated;
            it's useful for interactive applications where a user is
            waiting for a key to be generated.

    :attention: You should always use a cryptographically secure random number generator,
        such as the one defined in the ``Crypto.Random`` module; **don't** just use the
        current time and the ``random`` module.

    :Return: An ElGamal key object (`ElGamalobj`).
    """
    obj = ElGamalobj()
    # Generate a safe prime p
    # See Algorithm 4.86 in Handbook of Applied Cryptography
    if progress_func:
        progress_func('p\n')
    while 1:
        q = int(number.getPrime(bits - 1, randfunc))
        obj.p = 2 * q + 1
        if number.isPrime(obj.p, randfunc=randfunc):
            break
    # Generate generator g
    # See Algorithm 4.80 in Handbook of Applied Cryptography
    # Note that the order of the group is n=p-1=2q, where q is prime
    if progress_func:
        progress_func('g\n')
    while 1:
        # We must avoid g=2 because of Bleichenbacher's attack described
        # in "Generating ElGamal signatures without knowning the secret key",
        # 1996
        #
        obj.g = number.getRandomRange(3, obj.p, randfunc)
        safe = 1
        if pow(obj.g, 2, obj.p) == 1:
            safe = 0
        if safe and pow(obj.g, q, obj.p) == 1:
            safe = 0
        # Discard g if it divides p-1 because of the attack described
        # in Note 11.67 (iii) in HAC
        if safe and divmod(obj.p - 1, obj.g)[1] == 0:
            safe = 0
        # g^{-1} must not divide p-1 because of Khadir's attack
        # described in "Conditions of the generator for forging ElGamal
        # signature", 2011
        ginv = number.inverse(obj.g, obj.p)
        if safe and divmod(obj.p - 1, ginv)[1] == 0:
            safe = 0
        if safe:
            break
    # Generate private key x
    if progress_func:
        progress_func('x\n')
    obj.x = number.getRandomRange(2, obj.p - 1, randfunc)
    # Generate public key y
    if progress_func:
        progress_func('y\n')
    obj.y = pow(obj.g, obj.x, obj.p)
    return obj