Let's say I have access to the private portion of an RSA key-pair. How can I check if this key has associated passphrase or not?
5 Answers
The keyfile will have a different header if it is password protected. Here's the top of a key without a passphrase:
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA3qKD/4PAc6PMb1yCckTduFl5fA1OpURLR5Z+T4xY1JQt3eTM
And here's the top of a key which is passphrase-protected:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,556C1115CDA822F5
AHi/3++6PEIBv4kfpM57McyoSAAaT2ECxNOA5DRKxJQ9pr2D3aUeMBaBfWGrxd/Q
Unfortunately, that only works looking at the files. I know of no way for a server to be able to tell if the keys being presented to it were protected with a passphrase, which is the most useful place to be able to leverage that sort of info.
-
3A solution based on the timing could work. In case of an unencrypted key, the response is usually sent instantly as soon as the server sends the challenge, where as for an encrypted one it takes at least a few seconds for the user to enter the passphrase to decrypt the key. Commented Jul 12, 2016 at 0:04
-
11@AndreBorie, unfortunately the client can't be trusted. Normal usage may have no delay if a key agent is caching the (phrased) key, and a malicious client could introduce fake delays to "mimic" unlocking the key... We went through the same thing 20 years ago with "timing analysis of password entry" on protocols like telnet :) Commented Jul 12, 2016 at 0:25
-
12More generally, encryption of the key is a totally client-side operation. If you want to know that the key is encrypted, it needs to live and be decrypted server-side. But then the server has the decrypted private key, which rather defeats the point of asymmetric cryptography.– KevinCommented Jul 12, 2016 at 4:08
-
9This answer is not correct (anymore). A priv key not showing the
proc-type
andDEK
headers can very well be encrypted.– GerardJPCommented Feb 7, 2019 at 13:27 -
@GerardJP I interpret the answer as saying that if the
proc-type
andDEK
header lines are missing, then it is not password protected. I don't think it is talking about whether or not something is encrypted.– bgoodrCommented Dec 20, 2019 at 22:03
It is not always so easy as described in the other answers. It works only with the old PEM keys. New openssh
format of the keys (generated with -o
option, more secure, since openssh-6.5) looks the same if you check the headers:
$ head rsa_enc
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABCYdi7MhY
$ head rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
The easiest way in this case is to run some operation on them using ssh-keygen
. If it will ask for a passphrase, it has one (or it is not a ssh key), if not it does not have a passphrase:
$ ssh-keygen -yf rsa_enc
Enter passphrase:
$ ssh-keygen -yf rsa
ssh-rsa AAAAB3NzaC1y...
Maybe even better is the following example, since it doesn't ask for input: -P specifies the passphrase to use, an unprotected key opens with an empty passphrase.
$ ssh-keygen -y -P "" -f rsa_enc
Load key "path_to_key": incorrect passphrase supplied to decrypt private key`
$ ssh-keygen -y -P "" -f rsa
ssh-rsa AAAAB3NzaC1y...
-
More secure but less compatible: they perceived the fact that the known ASN.1 structure was also encrypted as facilitating the brute-force attacks, and therefore left out the standard storage to create their own storage format where the attacker can rely on no previously known text. Thanks! Commented Jul 11, 2016 at 13:20
-
45The base64-encoded data does contain information about whether the key is encrypted, though: The first decodes to
openssh-key-v1.....aes256-cbc....bcrypt.........v..
and the second decodes toopenssh-key-v1.....none....none................ssh-
Commented Jul 11, 2016 at 15:34 -
2@Random832 you are right. Thanks. But it is not so obvious as in the first case where it is in ASCII.– JakujeCommented Jul 11, 2016 at 15:36
-
5
-
2And in 2018 (beginning with 7.8) new format is now the default and
-o
is not needed (you can still get old=OpenSSL format except for ed25519 with-m pem
) FWIW PuTTY has its own 'ppk' format (also text+base64, but not PEM) with the second line specifying encryption or not. Commented Feb 11, 2019 at 4:56
The "RSA key" is actually a set of values stored as an ASN.1 structure in the standardized DER binary format, then encoded in base-64 to get the final PEM file.
A very easy way to determine whether a key is encoded or not is simply to check whether the ASN.1 header is present, and this is usually as simple as checking if the "key" begins with the letters MII
as in the example below:
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCWxk9djtgA/t7n6M8g1d2fk3exyCSu1uubpxUkoFLJBKjLYiaa
[...]
eCrpRFHxhPICHI4db+I8GZ9QDmlbCN/bl3BBNNTn3w==
-----END RSA PRIVATE KEY-----
In password protected files, the whole ASN.1 structure being encrypted, it all appears as random characters.
-
1But this could lead to false positives if the encrypted string also starts with MII ?– FalcoCommented Jul 11, 2016 at 13:49
-
4@Falco: Yes. On a practical basis, it is a good heuristic for instance to quickly check a set of unknown keys, but the only way to have a 100% guaranty about the key status (encrypted, corrupted, etc.) is by by using the method provided in Jakuje's answer (
ssh-keygen -yf <keyfile>
). Commented Jul 11, 2016 at 15:12 -
Simpler and robust: OpenSSL 'traditional' format PEM-level encryption has two header lines plus a blank line before the encrypted&base64'd data, as shown in gowenfawr's answe Commented Feb 11, 2019 at 4:52
Private keys should be secured, trying to set the password just declares if it is yet password protected. With ssh-keygen
on the protected key:
~/.ssh$ ssh-keygen -p -f id_rsa_password_protected
Enter old passphrase:
And with not protected:
~/.ssh$ ssh-keygen -p -f id_rsa_not_protected
Enter new passphrase (empty for no passphrase):
So if it is not password protected, just set the password.
-
1
-
I applaud. For the typical user, this is the best way to ensure their key is protected, and protect it if it's not, all with one command. Commented Aug 8 at 14:47
While the other answers give valid answers to achieve this manually, the following approach can be used within a shell script for automation.
The following command's exit code determines whether the key file found at $path_to_keyfile
has a password:
ssh-keygen -y -P "" -f "$path_to_keyfile" &>/dev/null
To use this command within a script that checks for this you could either use the following snippet
if ssh-keygen -y -P "" -f "$path_to_keyfile" &>/dev/null; then
echo "unprotected"
else
echo "protected"
fi
or use &&
and ||
as shorthands like so:
ssh-keygen -y -P "" -f "$path_to_keyfile" &>/dev/null && echo "Unprotected" || echo "Protected"
-
This is a good answer. Only problem is not the guard against the case the file doesn't exist. In this case you'll also get a non zero status. Maybe it's best to parse the output of
incorrect passphrase supplied to decrypt private key
to double-check it.– strboulCommented Jul 24, 2022 at 8:13 -
@strbout I would check for the file before executing the line with
ssh-keygen
, e.g. usingtest -f "$path_to_keyfile" || exit 1
to abort, when the file does not exist.– FelixCommented Aug 4, 2022 at 21:48 -
There are other failure cases, too, such as "Permission denied". So, the command shown really distinguishes if the file is readable and unprotected or if it is not. If you want to distinguish protected vs not exists or not readable (or other such failures), then use extra tests as @Felix suggests.– jrw32982Commented Mar 14 at 14:45
ssh
process prematurely from a script after matching the string asking for a password.