This document is intended to provide regular expressions that can be used to confirm if an SSH public key starts with a valid expected value. To help contribute to this information, please open a pull request.
Most of the information collected and presented here was originally discussed in the comments of a gist posted by @paranoiq. Specifically, information provided by @MaPePeR was critical in composing the information here.
The OpenSSH Manual Pages link to ssh-keygen(1) which lists the valid options for the -t flag as:
dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa
Using ssh-keygen -t ...
for each of the above types as follows:
ssh-keygen -t dsa
ssh-keygen -t ecdsa
ssh-keygen -t ecdsa-sha2-nistp256
ssh-keygen -t ecdsa-sha2-nistp384
ssh-keygen -t ecdsa-sha2-nistp521
ssh-keygen -t ecdsa-sk
ssh-keygen -t ed25519
ssh-keygen -t ed25519-sk
ssh-keygen -t rsa
Results in generation of *.pub
files for each key type.
Within each *.pub
file, the string of characters at the beginning is expected to be (in order)
- The key type (this does not always match the value given to the
-t
option when runningssh-keygen
) - A space
- The base64 value of:
\0\0\0
(hex characters)- The hex representation of the length of the key type
- The key type
- The rest of the key
- (optional) A space
- (optional) A comment describing the key
\0\0\0\x0bssh-ed25519
^----------------- \0\0\0 hex characters, always expected
^----------- \x0b the hex representation of the length of ssh-ed25519 (11)
^------- ssh-ed25519 the key type
\0\0\0\x07ssh-rsa
^----------------- \0\0\0 hex characters, always expected
^----------- \x07 the hex representation of the length of ssh-rsa (7)
^------- ssh-rsa the key type
$ echo -ne "\0\0\0\x07ssh-dss" | base64
AAAAB3NzaC1kc3M=
## Catch ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521
$ echo -ne "\0\0\0\x13ecdsa-sha2-nistp" | base64
AAAAE2VjZHNhLXNoYTItbmlzdHA=
$ echo -ne "\0\0\0\[email protected]" | base64
AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20=
$ echo -ne "\0\0\0\x0bssh-ed25519" | base64
AAAAC3NzaC1lZDI1NTE5
$ echo -ne "\0\0\0\[email protected]" | base64
AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t
$ echo -ne "\0\0\0\x07ssh-rsa" | base64
AAAAB3NzaC1yc2E=
In some of the shell output the final character is =
, which base64 uses for padding. When the rest of the key is present after the key type in the encoded string it can change the preceding character output in the encoded string.
Using ssh-rsa
for example:
$ echo -ne "\0\0\0\x07ssh-rsa" | base64
AAAAB3NzaC1yc2E=
$ echo -ne "\0\0\0\x07ssh-rsa\x00" | base64
AAAAB3NzaC1yc2EA
$ echo -ne "\0\0\0\x07ssh-rsa\xff" | base64
AAAAB3NzaC1yc2H/
Because of this, if the base64 output final character is =
the last 2 characters cannot be reliably used in regular expression matching.
^ssh-dss\s+AAAAB3NzaC1kc3[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$
^ecdsa-sha2-nistp(256|384|521)\s+AAAAE2VjZHNhLXNoYTItbmlzdHA[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$
^sk-ecdsa-sha2-nistp256@openssh.com\s+AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb2[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$
^ssh-ed25519\s+AAAAC3NzaC1lZDI1NTE5[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$
^sk-ssh-ed25519@openssh.com\s+AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$
^ssh-rsa\s+AAAAB3NzaC1yc2[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$
^(ssh-dss\s+AAAAB3NzaC1kc3|ecdsa-sha2-nistp(256|384|521)\s+AAAAE2VjZHNhLXNoYTItbmlzdHA|sk-ecdsa-sha2-nistp256@openssh.com\s+AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb2|ssh-ed25519\s+AAAAC3NzaC1lZDI1NTE5|sk-ssh-ed25519@openssh.com\s+AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t|ssh-rsa\s+AAAAB3NzaC1yc2)[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$
dsa
(dss
) and ecdsa
/sk-ecdsa
may not be considered secure.
^(ssh-ed25519\s+AAAAC3NzaC1lZDI1NTE5|sk-ssh-ed25519@openssh.com\s+AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t|ssh-rsa\s+AAAAB3NzaC1yc2)[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$