def exportKey(self, format='PEM', pkcs8=None, passphrase=None, protection=None, randfunc=None): """Export this DSA key. :Parameters: format : string The format to use for wrapping the key: - *'DER'*. Binary encoding. - *'PEM'*. Textual encoding, done according to `RFC1421`_/ `RFC1423`_ (default). - *'OpenSSH'*. Textual encoding, one line of text, see `RFC4253`_. Only suitable for public keys, not private keys. passphrase : string For private keys only. The pass phrase to use for deriving the encryption key. pkcs8 : boolean For private keys only. If ``True`` (default), the key is arranged according to `PKCS#8`_ and if `False`, according to the custom OpenSSL/OpenSSH encoding. protection : string The encryption scheme to use for protecting the private key. It is only meaningful when a pass phrase is present too. If ``pkcs8`` takes value ``True``, ``protection`` is the PKCS#8 algorithm to use for deriving the secret and encrypting the private DSA key. For a complete list of algorithms, see `Crypto.IO.PKCS8`. The default is *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC*. If ``pkcs8`` is ``False``, the obsolete PEM encryption scheme is used. It is based on MD5 for key derivation, and Triple DES for encryption. Parameter ``protection`` is ignored. The combination ``format='DER'`` and ``pkcs8=False`` is not allowed if a passphrase is present. randfunc : callable A function that returns random bytes. By default it is `Crypto.Random.get_random_bytes`. :Return: A byte string with the encoded public or private half of the key. :Raise ValueError: When the format is unknown or when you try to encrypt a private key with *DER* format and OpenSSL/OpenSSH. :attention: If you don't provide a pass phrase, the private key will be exported in the clear! .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _RFC4253: http://www.ietf.org/rfc/rfc4253.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt """ if passphrase is not None: passphrase = tobytes(passphrase) if randfunc is None: randfunc = Random.get_random_bytes if format == 'OpenSSH': tup1 = [self._key[x].to_bytes() for x in 'p', 'q', 'g', 'y'] def func(x): if (bord(x[0]) & 0x80): return bchr(0) + x else: return x tup2 = map(func, tup1) keyparts = [b('ssh-dss')] + tup2 keystring = b('').join( [struct.pack(">I", len(kp)) + kp for kp in keyparts] ) return b('ssh-dss ') + binascii.b2a_base64(keystring)[:-1] # DER format is always used, even in case of PEM, which simply # encodes it into BASE64. params = newDerSequence(self.p, self.q, self.g) if self.has_private(): if pkcs8 is None: pkcs8 = True if pkcs8: if not protection: protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' private_key = DerInteger(self.x).encode() binary_key = PKCS8.wrap( private_key, oid, passphrase, protection, key_params=params, randfunc=randfunc ) if passphrase: key_type = 'ENCRYPTED PRIVATE' else: key_type = 'PRIVATE' passphrase = None else: if format != 'PEM' and passphrase: raise ValueError("DSA private key cannot be encrypted") ints = [0, self.p, self.q, self.g, self.y, self.x] binary_key = newDerSequence(*ints).encode() key_type = "DSA PRIVATE" else: if pkcs8: raise ValueError("PKCS#8 is only meaningful for private keys") binary_key = newDerSequence( newDerSequence(DerObjectId(oid), params), newDerBitString(DerInteger(self.y)) ).encode() key_type = "DSA PUBLIC" if format == 'DER': return binary_key if format == 'PEM': pem_str = PEM.encode( binary_key, key_type + " KEY", passphrase, randfunc ) return tobytes(pem_str) raise ValueError("Unknown key format '%s'. Cannot export the DSA key." % format)
def exportKey(self, format='PEM', passphrase=None, pkcs=1, protection=None, randfunc=None): """Export this RSA key. :Parameters: format : string The format to use for wrapping the key: - *'DER'*. Binary encoding. - *'PEM'*. Textual encoding, done according to `RFC1421`_/`RFC1423`_. - *'OpenSSH'*. Textual encoding, done according to OpenSSH specification. Only suitable for public keys (not private keys). passphrase : string For private keys only. The pass phrase used for deriving the encryption key. pkcs : integer For *DER* and *PEM* format only. The PKCS standard to follow for assembling the components of the key. You have two choices: - **1** (default): the public key is embedded into an X.509 ``SubjectPublicKeyInfo`` DER SEQUENCE. The private key is embedded into a `PKCS#1`_ ``RSAPrivateKey`` DER SEQUENCE. - **8**: the private key is embedded into a `PKCS#8`_ ``PrivateKeyInfo`` DER SEQUENCE. This value cannot be used for public keys. protection : string The encryption scheme to use for protecting the private key. If ``None`` (default), the behavior depends on ``format``: - For *DER*, the *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC* scheme is used. The following operations are performed: 1. A 16 byte Triple DES key is derived from the passphrase using `Crypto.Protocol.KDF.PBKDF2` with 8 bytes salt, and 1 000 iterations of `Crypto.Hash.HMAC`. 2. The private key is encrypted using CBC. 3. The encrypted key is encoded according to PKCS#8. - For *PEM*, the obsolete PEM encryption scheme is used. It is based on MD5 for key derivation, and Triple DES for encryption. Specifying a value for ``protection`` is only meaningful for PKCS#8 (that is, ``pkcs=8``) and only if a pass phrase is present too. The supported schemes for PKCS#8 are listed in the `Crypto.IO.PKCS8` module (see ``wrap_algo`` parameter). randfunc : callable A function that provides random bytes. Only used for PEM encoding. The default is `Crypto.Random.get_random_bytes`. :Return: A byte string with the encoded public or private half of the key. :Raise ValueError: When the format is unknown or when you try to encrypt a private key with *DER* format and PKCS#1. :attention: If you don't provide a pass phrase, the private key will be exported in the clear! .. _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 randfunc is None: randfunc = Random.get_random_bytes if format=='OpenSSH': eb, nb = [self._key[comp].to_bytes() for comp in 'e', 'n'] if bord(eb[0]) & 0x80: eb=bchr(0x00)+eb if bord(nb[0]) & 0x80: nb=bchr(0x00)+nb keyparts = [ b('ssh-rsa'), eb, nb ] keystring = b('').join([ struct.pack(">I",len(kp))+kp for kp in keyparts]) return b('ssh-rsa ')+binascii.b2a_base64(keystring)[:-1] # DER format is always used, even in case of PEM, which simply # encodes it into BASE64. if self.has_private(): binary_key = newDerSequence( 0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p-1), self.d % (self.q-1), Integer(self.q).inverse(self.p) ).encode() if pkcs==1: keyType = 'RSA PRIVATE' if format=='DER' and passphrase: raise ValueError("PKCS#1 private key cannot be encrypted") else: # PKCS#8 if format=='PEM' and protection is None: keyType = 'PRIVATE' binary_key = PKCS8.wrap(binary_key, oid, None) else: keyType = 'ENCRYPTED PRIVATE' if not protection: protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' binary_key = PKCS8.wrap(binary_key, oid, passphrase, protection) passphrase = None else: keyType = "RSA PUBLIC" binary_key = newDerSequence( algorithmIdentifier, newDerBitString( newDerSequence( self.n, self.e ) ) ).encode() if format=='DER': return binary_key if format=='PEM': pem_str = PEM.encode(binary_key, keyType+" KEY", passphrase, randfunc) return tobytes(pem_str) raise ValueError("Unknown key format '%s'. Cannot export the RSA key." % format)
def exportKey(self, format='PEM', passphrase=None, pkcs=1, protection=None, randfunc=None): """Export this RSA key. :Parameters: format : string The format to use for wrapping the key: - *'DER'*. Binary encoding. - *'PEM'*. Textual encoding, done according to `RFC1421`_/`RFC1423`_. - *'OpenSSH'*. Textual encoding, done according to OpenSSH specification. Only suitable for public keys (not private keys). passphrase : string For private keys only. The pass phrase used for deriving the encryption key. pkcs : integer For *DER* and *PEM* format only. The PKCS standard to follow for assembling the components of the key. You have two choices: - **1** (default): the public key is embedded into an X.509 ``SubjectPublicKeyInfo`` DER SEQUENCE. The private key is embedded into a `PKCS#1`_ ``RSAPrivateKey`` DER SEQUENCE. - **8**: the private key is embedded into a `PKCS#8`_ ``PrivateKeyInfo`` DER SEQUENCE. This value cannot be used for public keys. protection : string The encryption scheme to use for protecting the private key. If ``None`` (default), the behavior depends on ``format``: - For *DER*, the *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC* scheme is used. The following operations are performed: 1. A 16 byte Triple DES key is derived from the passphrase using `Crypto.Protocol.KDF.PBKDF2` with 8 bytes salt, and 1 000 iterations of `Crypto.Hash.HMAC`. 2. The private key is encrypted using CBC. 3. The encrypted key is encoded according to PKCS#8. - For *PEM*, the obsolete PEM encryption scheme is used. It is based on MD5 for key derivation, and Triple DES for encryption. Specifying a value for ``protection`` is only meaningful for PKCS#8 (that is, ``pkcs=8``) and only if a pass phrase is present too. The supported schemes for PKCS#8 are listed in the `Crypto.IO.PKCS8` module (see ``wrap_algo`` parameter). randfunc : callable A function that provides random bytes. Only used for PEM encoding. The default is `Crypto.Random.get_random_bytes`. :Return: A byte string with the encoded public or private half of the key. :Raise ValueError: When the format is unknown or when you try to encrypt a private key with *DER* format and PKCS#1. :attention: If you don't provide a pass phrase, the private key will be exported in the clear! .. _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 randfunc is None: randfunc = Random.get_random_bytes if format == 'OpenSSH': eb, nb = [self._key[comp].to_bytes() for comp in 'e', 'n'] if bord(eb[0]) & 0x80: eb = bchr(0x00) + eb if bord(nb[0]) & 0x80: nb = bchr(0x00) + nb keyparts = [b('ssh-rsa'), eb, nb] keystring = b('').join( [struct.pack(">I", len(kp)) + kp for kp in keyparts]) return b('ssh-rsa ') + binascii.b2a_base64(keystring)[:-1] # DER format is always used, even in case of PEM, which simply # encodes it into BASE64. if self.has_private(): binary_key = newDerSequence( 0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p - 1), self.d % (self.q - 1), Integer(self.q).inverse(self.p)).encode() if pkcs == 1: keyType = 'RSA PRIVATE' if format == 'DER' and passphrase: raise ValueError("PKCS#1 private key cannot be encrypted") else: # PKCS#8 if format == 'PEM' and protection is None: keyType = 'PRIVATE' binary_key = PKCS8.wrap(binary_key, oid, None) else: keyType = 'ENCRYPTED PRIVATE' if not protection: protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' binary_key = PKCS8.wrap(binary_key, oid, passphrase, protection) passphrase = None else: keyType = "RSA PUBLIC" binary_key = newDerSequence( algorithmIdentifier, newDerBitString(newDerSequence(self.n, self.e))).encode() if format == 'DER': return binary_key if format == 'PEM': pem_str = PEM.encode(binary_key, keyType + " KEY", passphrase, randfunc) return tobytes(pem_str) raise ValueError( "Unknown key format '%s'. Cannot export the RSA key." % format)
def encrypt(data, passphrase, protection, prot_params=None, randfunc=None): """Encrypt a piece of data using a passphrase and *PBES2*. :Parameters: data : byte string The piece of data to encrypt. passphrase : byte string The passphrase to use for encrypting the data. protection : string The identifier of the encryption algorithm to use. The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'. prot_params : dictionary Parameters of the protection algorithm. +------------------+-----------------------------------------------+ | Key | Description | +==================+===============================================+ | iteration_count | The KDF algorithm is repeated several times to| | | slow down brute force attacks on passwords | | | (called *N* or CPU/memory cost in scrypt). | | | | | | The default value for PBKDF2 is 1 000. | | | The default value for scrypt is 16 384. | +------------------+-----------------------------------------------+ | salt_size | Salt is used to thwart dictionary and rainbow | | | attacks on passwords. The default value is 8 | | | bytes. | +------------------+-----------------------------------------------+ | block_size | *(scrypt only)* Memory-cost (r). The default | | | value is 8. | +------------------+-----------------------------------------------+ | parallelization | *(scrypt only)* CPU-cost (p). The default | | | value is 1. | +------------------+-----------------------------------------------+ randfunc : callable Random number generation function; it should accept a single integer N and return a string of random data, N bytes long. If not specified, a new RNG will be instantiated from ``Crypto.Random``. :Returns: The encrypted data, as a binary string. """ if prot_params is None: prot_params = {} if randfunc is None: randfunc = Random.new().read if protection == 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC': key_size = 24 module = DES3 cipher_mode = DES3.MODE_CBC enc_oid = "1.2.840.113549.3.7" elif protection in ('PBKDF2WithHMAC-SHA1AndAES128-CBC', 'scryptAndAES128-CBC'): key_size = 16 module = AES cipher_mode = AES.MODE_CBC enc_oid = "2.16.840.1.101.3.4.1.2" elif protection in ('PBKDF2WithHMAC-SHA1AndAES192-CBC', 'scryptAndAES192-CBC'): key_size = 24 module = AES cipher_mode = AES.MODE_CBC enc_oid = "2.16.840.1.101.3.4.1.22" elif protection in ('PBKDF2WithHMAC-SHA1AndAES256-CBC', 'scryptAndAES256-CBC'): key_size = 32 module = AES cipher_mode = AES.MODE_CBC enc_oid = "2.16.840.1.101.3.4.1.42" else: raise ValueError("Unknown mode") # Get random data iv = randfunc(module.block_size) salt = randfunc(prot_params.get("salt_size", 8)) # Derive key from password if protection.startswith('PBKDF2'): count = prot_params.get("iteration_count", 1000) key = PBKDF2(passphrase, salt, key_size, count) key_derivation_func = newDerSequence( DerObjectId("1.2.840.113549.1.5.12"), # PBKDF2 newDerSequence(DerOctetString(salt), DerInteger(count))) else: # It must be scrypt count = prot_params.get("iteration_count", 16384) scrypt_r = prot_params.get('block_size', 8) scrypt_p = prot_params.get('parallelization', 1) key = scrypt(passphrase, salt, key_size, count, scrypt_r, scrypt_p) key_derivation_func = newDerSequence( DerObjectId("1.3.6.1.4.1.11591.4.11"), # scrypt newDerSequence(DerOctetString(salt), DerInteger(count), DerInteger(scrypt_r), DerInteger(scrypt_p))) # Create cipher and use it cipher = module.new(key, cipher_mode, iv) encrypted_data = cipher.encrypt(pad(data, cipher.block_size)) encryption_scheme = newDerSequence(DerObjectId(enc_oid), DerOctetString(iv)) # Result encrypted_private_key_info = newDerSequence( # encryptionAlgorithm newDerSequence( DerObjectId("1.2.840.113549.1.5.13"), # PBES2 newDerSequence(key_derivation_func, encryption_scheme), ), DerOctetString(encrypted_data)) return encrypted_private_key_info.encode()
def wrap(private_key, key_oid, passphrase=None, protection=None, prot_params=None, key_params=None, randfunc=None): """Wrap a private key into a PKCS#8 blob (clear or encrypted). :Parameters: private_key : byte string The private key encoded in binary form. The actual encoding is algorithm specific. In most cases, it is DER. key_oid : string The object identifier (OID) of the private key to wrap. It is a dotted string, like "``1.2.840.113549.1.1.1``" (for RSA keys). passphrase : (binary) string The secret passphrase from which the wrapping key is derived. Set it only if encryption is required. protection : string The identifier of the algorithm to use for securely wrapping the key. The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'. prot_params : dictionary Parameters for the protection algorithm. +------------------+-----------------------------------------------+ | Key | Description | +==================+===============================================+ | iteration_count | The KDF algorithm is repeated several times to| | | slow down brute force attacks on passwords | | | (called *N* or CPU/memory cost in scrypt). | | | | | | The default value for PBKDF2 is 1 000. | | | The default value for scrypt is 16 384. | +------------------+-----------------------------------------------+ | salt_size | Salt is used to thwart dictionary and rainbow | | | attacks on passwords. The default value is 8 | | | bytes. | +------------------+-----------------------------------------------+ | block_size | *(scrypt only)* Memory-cost (r). The default | | | value is 8. | +------------------+-----------------------------------------------+ | parallelization | *(scrypt only)* CPU-cost (p). The default | | | value is 1. | +------------------+-----------------------------------------------+ key_params : DER object The algorithm parameters associated to the private key. It is required for algorithms like DSA, but not for others like RSA. randfunc : callable Random number generation function; it should accept a single integer N and return a string of random data, N bytes long. If not specified, a new RNG will be instantiated from ``Crypto.Random``. :Return: The PKCS#8-wrapped private key (possibly encrypted), as a binary string. """ if key_params is None: key_params = DerNull() # # PrivateKeyInfo ::= SEQUENCE { # version Version, # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, # privateKey PrivateKey, # attributes [0] IMPLICIT Attributes OPTIONAL # } # pk_info = newDerSequence( 0, newDerSequence( DerObjectId(key_oid), key_params ), newDerOctetString(private_key) ) pk_info_der = pk_info.encode() if not passphrase: return pk_info_der # Encryption with PBES2 passphrase = tobytes(passphrase) if protection is None: protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' return PBES2.encrypt(pk_info_der, passphrase, protection, prot_params, randfunc)
def testInit1(self): der = newDerSequence(1, DerInteger(2), '0\x00') self.assertEqual(der.encode(), b('0\x08\x02\x01\x01\x02\x01\x020\x00'))
def exportKey(self, format='PEM', pkcs8=None, passphrase=None, protection=None): if passphrase is not None: passphrase = tobytes(passphrase) if format == 'OpenSSH': tup1 = [long_to_bytes(x) for x in (self.p, self.q, self.g, self.y)] def func(x): if bord(x[0]) & 128: return bchr(0) + x else: return x tup2 = map(func, tup1) keyparts = [b('ssh-dss')] + tup2 keystring = b('').join( [struct.pack('>I', len(kp)) + kp for kp in keyparts]) return b('ssh-dss ') + binascii.b2a_base64(keystring)[:-1] else: params = newDerSequence(self.p, self.q, self.g) if self.has_private(): if pkcs8 is None: pkcs8 = True if pkcs8: if not protection: protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' private_key = DerInteger(self.x).encode() binary_key = PKCS8.wrap(private_key, oid, passphrase, protection, key_params=params, randfunc=self._randfunc) if passphrase: key_type = 'ENCRYPTED PRIVATE' else: key_type = 'PRIVATE' passphrase = None else: if format != 'PEM' and passphrase: raise ValueError('DSA private key cannot be encrypted') ints = [0, self.p, self.q, self.g, self.y, self.x] binary_key = newDerSequence(*ints).encode() key_type = 'DSA PRIVATE' else: if pkcs8: raise ValueError( 'PKCS#8 is only meaningful for private keys') binary_key = newDerSequence( newDerSequence(DerObjectId(oid), params), newDerBitString(DerInteger(self.y))).encode() key_type = 'DSA PUBLIC' if format == 'DER': return binary_key if format == 'PEM': pem_str = PEM.encode(binary_key, key_type + ' KEY', passphrase, self._randfunc) return tobytes(pem_str) raise ValueError( "Unknown key format '%s'. Cannot export the DSA key." % format) return
def encrypt(data, passphrase, protection, prot_params=None, randfunc=None): """Encrypt a piece of data using a passphrase and *PBES2*. :Parameters: data : byte string The piece of data to encrypt. passphrase : byte string The passphrase to use for encrypting the data. protection : string The identifier of the encryption algorithm to use. The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'. prot_params : dictionary Parameters of the protection algorithm. +------------------+-----------------------------------------------+ | Key | Description | +==================+===============================================+ | iteration_count | The KDF algorithm is repeated several times to| | | slow down brute force attacks on passwords | | | (called *N* or CPU/memory cost in scrypt). | | | | | | The default value for PBKDF2 is 1 000. | | | The default value for scrypt is 16 384. | +------------------+-----------------------------------------------+ | salt_size | Salt is used to thwart dictionary and rainbow | | | attacks on passwords. The default value is 8 | | | bytes. | +------------------+-----------------------------------------------+ | block_size | *(scrypt only)* Memory-cost (r). The default | | | value is 8. | +------------------+-----------------------------------------------+ | parallelization | *(scrypt only)* CPU-cost (p). The default | | | value is 1. | +------------------+-----------------------------------------------+ randfunc : callable Random number generation function; it should accept a single integer N and return a string of random data, N bytes long. If not specified, a new RNG will be instantiated from ``Crypto.Random``. :Returns: The encrypted data, as a binary string. """ if prot_params is None: prot_params = {} if randfunc is None: randfunc = Random.new().read if protection == 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC': key_size = 24 module = DES3 cipher_mode = DES3.MODE_CBC enc_oid = "1.2.840.113549.3.7" elif protection in ('PBKDF2WithHMAC-SHA1AndAES128-CBC', 'scryptAndAES128-CBC'): key_size = 16 module = AES cipher_mode = AES.MODE_CBC enc_oid = "2.16.840.1.101.3.4.1.2" elif protection in ('PBKDF2WithHMAC-SHA1AndAES192-CBC', 'scryptAndAES192-CBC'): key_size = 24 module = AES cipher_mode = AES.MODE_CBC enc_oid = "2.16.840.1.101.3.4.1.22" elif protection in ('PBKDF2WithHMAC-SHA1AndAES256-CBC', 'scryptAndAES256-CBC'): key_size = 32 module = AES cipher_mode = AES.MODE_CBC enc_oid = "2.16.840.1.101.3.4.1.42" else: raise ValueError("Unknown PBES2 mode") # Get random data iv = randfunc(module.block_size) salt = randfunc(prot_params.get("salt_size", 8)) # Derive key from password if protection.startswith('PBKDF2'): count = prot_params.get("iteration_count", 1000) key = PBKDF2(passphrase, salt, key_size, count) key_derivation_func = newDerSequence( DerObjectId("1.2.840.113549.1.5.12"), # PBKDF2 newDerSequence( DerOctetString(salt), DerInteger(count) ) ) else: # It must be scrypt count = prot_params.get("iteration_count", 16384) scrypt_r = prot_params.get('block_size', 8) scrypt_p = prot_params.get('parallelization', 1) key = scrypt(passphrase, salt, key_size, count, scrypt_r, scrypt_p) key_derivation_func = newDerSequence( DerObjectId("1.3.6.1.4.1.11591.4.11"), # scrypt newDerSequence( DerOctetString(salt), DerInteger(count), DerInteger(scrypt_r), DerInteger(scrypt_p) ) ) # Create cipher and use it cipher = module.new(key, cipher_mode, iv) encrypted_data = cipher.encrypt(pad(data, cipher.block_size)) encryption_scheme = newDerSequence( DerObjectId(enc_oid), DerOctetString(iv) ) # Result encrypted_private_key_info = newDerSequence( # encryptionAlgorithm newDerSequence( DerObjectId("1.2.840.113549.1.5.13"), # PBES2 newDerSequence( key_derivation_func, encryption_scheme ), ), DerOctetString(encrypted_data) ) return encrypted_private_key_info.encode()
def testInit1(self): der = newDerSequence(1, DerInteger(2), b('0\x00')) self.assertEquals(der.encode(), b('0\x08\x02\x01\x01\x02\x01\x020\x00'))