def testObjEncode5(self): # Encode type with explicit tag der = DerObject(0x10, explicit=5) der.payload = b("xxll") self.assertEqual(der.encode(), b("\xa5\x06\x10\x04xxll"))
def testObjEncode2(self): # Initialize with payload der = DerObject(0x03, b('\x12\x12')) self.assertEquals(der.encode(), b('\x03\x02\x12\x12'))
def testObjEncode3(self): # Long payload der = DerObject(b('\x10')) der.payload = b("0") * 128 self.assertEquals(der.encode(), b('\x10\x81\x80' + "0" * 128))
def testObjDecode6(self): # Arbitrary DER object der = DerObject() der.decode(b('\x65\x01\x88')) self.assertEquals(der._tag_octet, 0x65) self.assertEquals(der.payload, b('\x88'))
def testObjDecode8(self): # Verify that decode returns the object der = DerObject(0x02) self.assertEqual(der, der.decode(b('\x02\x02\x01\x02')))
def testObjDecode2(self): # Decode long payload der = DerObject(0x02) der.decode(b('\x02\x81\x80' + "1" * 128)) self.assertEquals(der.payload, b("1") * 128) self.assertEquals(der._tag_octet, 0x02)
def testObjDecode5(self): # Decode payload with unexpected tag gives error der = DerObject(0x02) self.assertRaises(ValueError, der.decode, b('\x03\x02\x01\x02'))
def testObjDecode1(self): # Decode short payload der = DerObject(0x02) der.decode(b('\x02\x02\x01\x02')) self.assertEqual(der.payload, b("\x01\x02")) self.assertEqual(der._idOctet, 0x02)
def testObjDecode2(self): # Decode short payload der = DerObject() der.decode(b('\x22\x81\x80' + "1"*128)) self.assertEquals(der.payload, b("1")*128) self.assertEquals(der.typeTag, 0x22)
def testObjDecode1(self): # Decode short payload der = DerObject() der.decode(b('\x20\x02\x01\x02')) self.assertEquals(der.payload, b("\x01\x02")) self.assertEquals(der.typeTag, 0x20)
def testObjEncode2(self): # Known types der = DerObject('SEQUENCE') self.assertEquals(der.encode(), b('\x30\x00')) der = DerObject('BIT STRING') self.assertEquals(der.encode(), b('\x03\x00'))
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)