Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save JPvRiel/5160e4dbc98d40a6624b9d9ce83ef435 to your computer and use it in GitHub Desktop.
Save JPvRiel/5160e4dbc98d40a6624b9d9ce83ef435 to your computer and use it in GitHub Desktop.
Convert Old Weakly Encrypted SSH Private Keys to the Newer PKCS8 Format

Convert Old Weakly Encrypted SSH Private Keys to the Newer PKCS8 Format

The default password-based encryption for openSSH RSA private keys (generated with ssh-keygen -t rsa) has inadequate protection against brute forcing due to a weak Password-Based Key Derivation Function (PBKDF) because it used OpenSSL's key derivation with just one round of MD5.

TL;DR: Rather generate new keys with ssh-keygen -t ed25519 which by default should use the more secure PBKDF with the PKCS8 format. RSA key generation defaults to the weak PBKDF stored in the PEM format.

However, if you still need RSA to work with older Unix systems, network devices, and other systems' SSH servers are not yet upgraded with Ed25519 support, this provides info to avoid the less secure default of saving private keys in the legacy PEM format when generating RSA keys. Backward compatibility is not that much of a concern since only the SSH client needs a reasonably modern version of SSH.

Identify if the old PEM format is in use

The older PEM format with weak private key encryption looks like this:

 -----BEGIN RSA PRIVATE KEY-----
 Proc-Type: 4,ENCRYPTED
 DEK-Info: DES-EDE3-CBC,3F215EB97E7B45D4

Note:

  • The 3F215EB97E7B45D4 hex part is used as the IV and salt for the non-standard PBKDF.
  • Only one round of hashing makes this very susceptible to brute force attacks.
  • In the above example, older 3DES isn't the main issue. Even if using AES-128-CBC, it's still got the single hash round problem.
  • Sharing the IV as a SALT is also a fairly minor issue compared to forcing just one round of hashing.

Override the default and use the new PKCS8 format

To convert old keys to the new PKCS8 format with bcrypt, the following worked for me:

ssh-keygen -i -p -f id_rsa -o

When creating new RSA keys, using -o is also the way to go else you default to the less secure PBKDF and legacy PEM format:

ssh-keygen -t rsa -o

Validating the cipher, key and mode used with bcrypt

To check what encryption scheme is in use in the new PKCS8 format, run:

openssl base64 -d < ~/.ssh/id_rsa | strings

To see more detail:

openssl base64 -d  < ~/.ssh/id_rsa | hexdump -C

By default, mine was using aes256-ctr:

00000000  6f 70 65 6e 73 73 68 2d  6b 65 79 2d 76 31 00 00  |openssh-key-v1..|
00000010  00 00 0a 61 65 73 32 35  36 2d 63 74 72 00 00 00  |...aes256-ctr...|
00000020  06 62 63 72 79 70 74 <snip>                       |.bcrypt...<snip>|

Alternate ways to look into the header and see which algorithm and key size is in use:

  • grep -oP '^[A-Za-z0-9+/]*={0,2}$' ~/.ssh/id_rsa | base64 -d | hexdump -C
  • openssl base64 -d < ~/.ssh/id_rsa | od -c

Notes:

  • Keys are encoded using ASN.1, but cannot be parsed as ASN.1 until decrypted using a paraphrase.
  • grep -oP '^[A-Za-z0-9+/]*={0,2}$' selects only lines that contain valid base64 encoding and skips file headers and footers like -----BEGIN OPENSSH PRIVATE KEY----- and -----END OPENSSH PRIVATE KEY-----.

OpenSSH versions and backward-compatible default with RSA keys

OpenSSH v8.1 release notes (~Oct 2019):

  • All: support PKCS8 as an optional format for storage of private keys to disk. The OpenSSH native key format remains the default, but PKCS8 is a superior format to PEM if interoperability with non-OpenSSH software is required, as it may use a less insecure key derivation function than PEM's.

The wording is cumbersome, but basically, 8.1+ allows for using this more secure PBKDF format.

I tested a version of OpenSSH 7.6 (~Dec 2017) and noted it generates RSA keys by default using the older weak PEM format. However, you can force the newer format with the ssh-keygen -o option. As per the man page for on Ubuntu 18.04 LTS:

-o      Causes ssh-keygen to save private keys using the new OpenSSH for‐
         mat rather than the more compatible PEM format.  The new format
         has increased resistance to brute-force password cracking but is
         not supported by versions of OpenSSH prior to 6.5.  Ed25519 keys
         always use the new private key format.

So the PKCS8 format should work with openssh client versions >= 6.5.

Related

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment