1
$\begingroup$

When exporting a private key with PyCryptodome, DER format, PKCS#8 and a suitably strong passphrase, is the resulting exported key secure enough to place somewhere that you would not normally want sensitive information stored, such as a database or on a hard drive?

From PyCryptodome.readthedocs.io:

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.
$\endgroup$
2
  • $\begingroup$ It's hard to tell you the security of a library because we would have to audit the whole code, which would take a long time. If PyCryptodome's implementation of RSA is secure, than your use should be fine. The only thing I'm worried about is that it uses PBKDF2, not argon2. $\endgroup$
    – Evan Su
    Feb 15, 2021 at 20:07
  • 1
    $\begingroup$ There are some issues: Triple DES has been deprecated by NIST due to it being less secure than AES. The 8 bytes of salt is small, NIST recommends a minimum size of twice that amount. Finally, the 1,000 iterations is on the low end, particular for HMAC. Now, is that insecure? Not to my knowledge, but it could damn sure be a lot more secure with some better choices. $\endgroup$ Feb 15, 2021 at 20:16

2 Answers 2

3
$\begingroup$

Well, it's sort of secure. There are no serious issues, but there are a few problems:

  • 3DES - A cipher composed of three rounds of the DES cipher. DES has a key size much too low at only 56 bits, but running it three times (first in the encryption direction, then the decryption direction, then the encryption again, hence the acronym "EDE") brings the key size up to 168 bits, although the effective keyspace is only 112 bits due to a meet-in-the-middle attack that applies to this type of construction. Although it's deprecated, 3DES is not considered breakable like DES. It's just that there are faster and more secure alternatives.

    The other issue with 3DES is the fact that it has a small block size of 64 bits. This causes severe security issues to open up as more data is encrypted under a single key. Because a private key is small (the size is measured in mere kilobytes), the small block size is a non-issue.

  • Small salt - The salt size is too small at only 8 bytes (64 bits). This is unlikely to be a serious issue in practice. An attacker would need to build an incredibly large rainbow table to attack a 64-bit salt. Building a rainbow table for hashes with a random salt was possible back in the days when a 12-bit salt was used, but not today with a 64-bit salt. I'd recommend 128 bits though.

  • Low PBKDF2 iterations - PBKDF2 is a function that hashes a password slowly, forcing anyone trying to crack the hash to use the same slow function. 1000 iterations of PBKDF2 is not much. It's far better than using a hash of the password directly, but it's not ideal. It would be better to use at least 100,000 iterations, or even to switch to a superior memory-hard KDF like Argon2.

Overall I'd say it's likely secure enough, but it's not ideal and isn't something I would use if I could help it.

$\endgroup$
2
  • $\begingroup$ The HMAC-SHA1 is used as the PRF in PBKDF2 -- it is not applied to the encryption. PKCS8 format does not provide for any authentication at the data level, although the PKCS5/7 padding used for CBC will catch most accidental errors, and the DER structures in PKCS8 have enough constraints I doubt malleating CBC-sized blocks (here 8 bytes) will be successful. $\endgroup$ Feb 16, 2021 at 5:19
  • $\begingroup$ @dave_thompson_085 Thanks for correcting my oversight. You're right, there is no cryptographic protection of integrity, but it's not likely to matter for encrypting keys. But HMAC-SHA1 is secure either way since the HMAC construction is not vulnerable to the collision attacks in SHA1. $\endgroup$
    – forest
    Feb 20, 2021 at 23:40
1
$\begingroup$

Password cracking evolves pretty quickly, so in general you should always question the defaults of any library.

In this case, I think you can use the export_key() function, but with a more modern password derivation algorithm like scrypt:

key.export_key(pkcs=8, protection='scryptAndAES256-CBC', passphrase='my secret')

This will still use the default scrypt parameters, which are probably still good enough (16000 iterations, block size 8, no parallelization).

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.