Ejemplo n.º 1
0
 def testEncode4(self):
     # One very long integer
     der = DerSequence()
     der.append(2**2048)
     self.assertEqual(
         der.encode(),
         b('0\x82\x01\x05') +
         b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +
         b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
Ejemplo n.º 2
0
 def testEncode6(self):
     # One integer and another type (no matter what it is)
     der = DerSequence()
     der.append(0x180)
     der.append(b('\x00\x02\x00\x00'))
     self.assertEqual(der.encode(),
                      b('0\x08\x02\x02\x01\x80\x00\x02\x00\x00'))
     self.assertFalse(der.hasOnlyInts())
Ejemplo n.º 3
0
 def testEncode1(self):
     # Empty sequence
     der = DerSequence()
     self.assertEqual(der.encode(), b('0\x00'))
     self.assertFalse(der.hasOnlyInts())
     # One single-byte integer (zero)
     der.append(0)
     self.assertEqual(der.encode(), b('0\x03\x02\x01\x00'))
     self.assertTrue(der.hasOnlyInts())
     # Invariant
     self.assertEqual(der.encode(), b('0\x03\x02\x01\x00'))
Ejemplo n.º 4
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")
Ejemplo n.º 5
0
 def testEncode2(self):
     # One single-byte integer (non-zero)
     der = DerSequence()
     der.append(127)
     self.assertEqual(der.encode(), b('0\x03\x02\x01\x7f'))
     # Indexing
     der[0] = 1
     self.assertEqual(len(der), 1)
     self.assertEqual(der[0], 1)
     self.assertEqual(der[-1], 1)
     self.assertEqual(der.encode(), b('0\x03\x02\x01\x01'))
     #
     der[:] = [1]
     self.assertEqual(len(der), 1)
     self.assertEqual(der[0], 1)
     self.assertEqual(der.encode(), b('0\x03\x02\x01\x01'))
Ejemplo n.º 6
0
 def testEncode6(self):
     # Two integers
     der = DerSequence()
     der.append(0x180)
     der.append(0xFF)
     self.assertEqual(der.encode(),
                      b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff'))
     self.assertTrue(der.hasOnlyInts())
     #
     der.append(0x01)
     der[1:] = [9, 8]
     self.assertEqual(len(der), 3)
     self.assertEqual(der[1:], [9, 8])
     self.assertEqual(der[1:-1], [9])
     self.assertEqual(der.encode(),
                      b('0\x0A\x02\x02\x01\x80\x02\x01\x09\x02\x01\x08'))
Ejemplo n.º 7
0
 def testEncode5(self):
     # One single-byte integer (looks negative)
     der = DerSequence()
     der.append(0xFF)
     self.assertEqual(der.encode(), b('0\x04\x02\x02\x00\xff'))
Ejemplo n.º 8
0
 def testEncode3(self):
     # One multi-byte integer (non-zero)
     der = DerSequence()
     der.append(0x180)
     self.assertEqual(der.encode(), b('0\x04\x02\x02\x01\x80'))
Ejemplo n.º 9
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 Crypro.Hash.MD5
                from Crypro.Cipher import DES3
                from Crypro.Protocol.KDF import PBKDF1
                salt = self._randfunc(8)
                key = PBKDF1(passphrase, salt, 16, 1, Crypro.Hash.MD5)
                key += PBKDF1(key + passphrase, salt, 8, 1, Crypro.Hash.MD5)
                objenc = DES3.new(key, Crypro.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)