Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for PKCS#8 encoding of private keys #32

wants to merge 3 commits into from


None yet
2 participants
Copy link

Legrandin commented Jan 21, 2013

Hi Dwayne,

The main goal of this set of patches is to introduce support for password-based PKCS#8 encoding of private keys (only RSA for now, but PKCS#8 is also applicable to DSA, etc). Today, the only way to encrypt a private key relies on the old PEM encryption, which is not very widespread, it uses weak ciphers, and it is in general under-specified.

With these changes, one can do:

rsaKey.exportKey('DER', 'my_password', pkcs=8)


rsaKey.exportKey('PEM', 'my_password', pkcs=8, 'PBKDF2WithHMAC-SHA1AndAES128-CBC')

And obtain a solid PBKDF2-based PKCS#8 container. Ideally, it would have been nice to have PKCS#8 encryption as the new default over PEM encryption, but in this way the interface remains backward compatible. The following password based encryption schemes are supported:

  • pbeWithMD5AndRC2-CBC (import only)
  • pbeWithMD5AndDES-CBC (import only)
  • pbeWithSHA1AndRC2-CBC (import only)
  • pbeWithSHA1AndDES-CBC (import only)

The first group of patches are actually a refactoring of the asn1 module. Now I think it is much easier to write code that parses DER, plus I added the relevant documentation.

Finally, by having separate modules for PEM and PKCS8, the code in becomes much more compact,


This comment has been minimized.

Copy link
Contributor Author

Legrandin commented Feb 17, 2013

Made a few updates to sync up with your latest work on master branch.

@Legrandin Legrandin closed this Apr 30, 2013


This comment has been minimized.

Copy link
Contributor Author

Legrandin commented May 13, 2013

I reopen this pull request after having it compressed into fewer change sets, and updated according to recent changes to main. API is still the same.

@Legrandin Legrandin reopened this May 13, 2013

Refactoring of the asn1 module
The following changes are included:

- Decoding is a much simpler operation. The internal
  logic is based on stream of binary data, and not
  on string indexing anymore. Additionally,
  decoding used to look like this:

     bitmap = DerObject()
     bitmap.decode(input_buffer, True)
     if bitmap.isType('BIT STRING'):
        ... proceed with parsing ...
        ... error ...

  Whereas now, it is cleaner and more compact:

     bitmap = DerBitString()

  Any error condition will lead to an exception.

- isType() method has been removed because of the above.
- Added examples and documentation
- Added support IMPLICIT tags
- Added support for negative INTEGERs
- Added DerSetOf ASN.1 class
- DerObjectID can be initialized from the dotted representation of
  the Object ID.
- DerBitString has a new member 'value' to hold the binary
  string. The member 'payload' should not be accessed anymore.
- DerObjectID has a new member 'value' to hold the dotted representation
  of the Object ID string. The member 'payload' should not be accessed
- Added operator += to DER SEQUENCE. Now it is possible to do:

      my_str = DerOctetString(b'ZYZ')
      seq = DerSequence()
      seq += 0
      seq += my_str.encode()
- Update to test cases

@Legrandin Legrandin closed this Jun 23, 2013


This comment has been minimized.

Copy link
Contributor Author

Legrandin commented Jun 27, 2013

Re-opening again after another round of refactoring.

Hopefully the code now is easier to review, as it is split across the following 4 modules:

  • Crypto.IO.PKCS8
  • Crypto.IO._PBES (more "linear", and less dynamic than before)
  • Crypto.IO.PEM
  • Crypto.Util.Padding

Legrandin added some commits Jun 15, 2013

Added support for PKCS#8-encrypted private keys.
The patch contains the following changes:

- Private RSA keys can be imported/exported in encrypted form,
  protected according to PKCS#8 and:


  In addition to that, it is possible to import keys i the
  following weak formats:

  * pbeWithMD5AndDES-CBC
  * pbeWithSHA1AndRC2-CBC
  * pbeWithMD5AndRC2-CBC
  * pbeWithSHA1AndDES-CBC

- The following new module (and 1 new package) are added:

  * Crypto.Util.Padding for simple padding/unpadding logic
  * Crypto.IO._PBES for PBE-related PKCS#5 logic
  * Crypto.IO.PEM for PEM wrapping/unwrapping
  * Crypto.IO.PKCS8 for PKCS#8 wrapping/unwrapping

- All Object ID (OIDs) are now in dotted form to increase

- Add AES support to PEM format (decode only).
  The PEM module can decrypt messages protected with AES-CBC.

- Update RSA import test cases.

- Updated to PKCS8 test cases
Add support for import/export of DSA keys
This patch adds methods importKey() to DSA module
and exportKey() to _DSAobj object.

Public and private keys can be imported/exported
in a variety of formats:

* DER vs PEM
* PKCS#8 vs OpenSSL vs OpenSSH/OpenSSL
* Encrypted vs clear

This comment has been minimized.

Copy link

dlitz commented Jul 15, 2013

Thanks. I'm not sure if I'm completely happy with the API yet (seems odd to me that DSA.exportKey takes pkcs8=True and RSA.exportKey takes pkcs=8) but it's still pretty useful already.

I reserve the right to complain about this in the future. ;-)

In the meantime, I've rebased and applied this to master:

I also needed this patch to make it work in Python 3.2:


@dlitz dlitz closed this Jul 15, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.