Skip to content

Instantly share code, notes, and snippets.

@paranoiq
Last active January 3, 2024 14:30
Show Gist options
  • Star 27 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save paranoiq/1932126 to your computer and use it in GitHub Desktop.
Save paranoiq/1932126 to your computer and use it in GitHub Desktop.
public RSA key validation regexp
#ssh-rsa AAAA[0-9A-Za-z+/]+[=]{0,3} ([^@]+@[^@]+)#
// this is the most simple case. see more complete regexps in coments below
// http://generator.my-addr.com/generate_ssh_public_rsa_key-private_rsa_key-ssh_pair_online_tool.php
// https://help.ubuntu.com/community/SSH/OpenSSH/Keys
// http://www.ietf.org/rfc/rfc4716.txt
@peconi
Copy link

peconi commented Jul 24, 2015

Thanks! 👍

@arjunnayak
Copy link

Thank you!

@filidorwiese
Copy link

Sweet 👍

@abdoulrahim
Copy link

thanks

@zbuckholz
Copy link

zbuckholz commented Mar 1, 2017

Yes, Thank you.
also adding sanity check with ssh-keygen -v -l -f .pub

@yfgeek
Copy link

yfgeek commented Jul 18, 2017

Thank you!

@Santinell
Copy link

public key without email must be valid, but in this regex email is required

@tubalmartin
Copy link

tubalmartin commented Aug 24, 2017

#ssh-rsa AAAA[0-9A-Za-z+/]+[=]{0,3}( [^@]+@[^@]+)?#

Optional email version.

@akshayapte
Copy link

Thanks!

@MaPePeR
Copy link

MaPePeR commented Aug 1, 2018

I tried to expand on this and an idea from https://stackoverflow.com/a/2494645/2256700 to include the possible headers in the Regex:

#^(ssh-rsa AAAAB3NzaC1yc2|ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNT|ssh-ed25519 AAAAC3NzaC1lZDI1NTE5|ssh-dss AAAAB3NzaC1kc3)[0-9A-Za-z+/]+[=]{0,3}( [^@]+@[^@]+)?$#
$ echo -n "\0\0\0\x07ssh-rsa" | base64
AAAAB3NzaC1yc2E=
$ echo -n "\0\0\0\x13ecdsa-sha2-nistp256" | base64
AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY=
$ echo -n "\0\0\0\x0bssh-ed25519" | base64
AAAAC3NzaC1lZDI1NTE5
$ echo -n "\0\0\0\x07ssh-dss" | base64
AAAAB3NzaC1kc3M=

@notorand-it
Copy link

#^(ssh-rsa AAAAB3NzaC1yc2|ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNT|ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzOD|ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1Mj|ssh-ed25519 AAAAC3NzaC1lZDI1NTE5|ssh-dss AAAAB3NzaC1kc3)[0-9A-Za-z+/]+[=]{0,3}( .*)?$#

  1. Ecdsa can have 521 bit key
  2. The comment can be anything, not just email.

@paranoiq
Copy link
Author

paranoiq commented Mar 14, 2020

thanks guys : ]

@alxtalend
Copy link

cool thanks !!

@nemchik
Copy link

nemchik commented Jun 18, 2022

OpenSSH 8.2+ now supports a new type of key that uses security keys (ex: yubikey) and begin with sk-

Using @notorand-it 's comment, this should validate keypairs with the sk- prefix:
^(sk-)?(ssh-rsa AAAAB3NzaC1yc2|ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNT|ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzOD|ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1Mj|ssh-ed25519 AAAAC3NzaC1lZDI1NTE5|ssh-dss AAAAB3NzaC1kc3)[0-9A-Za-z+/]+[=]{0,3}( .*)?$

2022-06-16 Update:
I did some more digging and found the sk- key types actually are not just simple prefixes.
I also found the above patterns for ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, and ssh-dss to be incomplete (missing the last character).

  • ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNT
  • ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQ <-- Q
  • ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjE <-- E
  • sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t <-- new
  • ssh-dss AAAAB3NzaC1kc3M <-- M
  • ssh-ed25519 AAAAC3NzaC1lZDI1NTE5
  • ssh-rsa AAAAB3NzaC1yc2E

There are also other sk- prefix types like sk-ssh-ecdsa and surely other non-sk- prefixed types.

All of these string that start with AAA can be base64 decoded and should include some ascii characters and then the string they are encoding, ex:
AAAAC3NzaC1lZDI1NTE5 decodes to ����ssh-ed25519
@MaPePeR 's comment about using echo -n "\0\0\0\x0bssh-ed25519" | base64 (and other examples) is correct, but in his comment with the combined string he stripped off the trailing = (which is correct to do) and then also the character before the = which makes the strings incomplete. The ed25519 example is the only one that did not have a trailing = so that one was correct (not truncated).

I also prefer using (\s.*) instead of ( .*) which should allow any whitespace character (ex: tab) instead of only allowing a standard space.

Here is a full regex pattern with the above (also sorted alphabetically):
^(ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNT|ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQ|ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjE|sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t|ssh-dss AAAAB3NzaC1kc3M|ssh-ed25519 AAAAC3NzaC1lZDI1NTE5|ssh-rsa AAAAB3NzaC1yc2E)[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$

Personally I only plan to use:
^(sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t|ssh-ed25519 AAAAC3NzaC1lZDI1NTE5|ssh-rsa AAAAB3NzaC1yc2E)[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$
because I am only interested in sk-ssh-ed25519@openssh.com, ssh-ed25519, and ssh-rsa.

@MaPePeR
Copy link

MaPePeR commented Jun 19, 2022

@nemchik I left the last character out intentionally, because not all bits in that base64 character are part of the "known header data". There is additionally some padding in there, that determines the character:

\0      \0      \0      \0x7    s       s       h       -       r       s       a
|------||------||------||------||------||------||------||------||------||------||------|PADDING with 0
0000000000000000000000000000011101110011011100110110100000101101011100100111001101100001??
|----||----||----||----||----||----||----||----||----||----||----||----||----||----||----|
A     A     A     A     B     3     N     z     a     C     1     y     c     2     E?

Forcing the last character to be an E also enforces, that the data that follows starts with 00. I didn't know if that was always the case, so I didn't want to add that constraint to the regex. From all I know, these chars could be valid:

Last Header sextet Base64 encoding
000100 E
000101 F
000110 G
000111 H

I didn't see the point going through all of them to determine these extra valid chars, when the regex can only give you a rough guideline anyway. But maybe there is also a constraint, that I don't know of, that forces these bits to always be 0? Keeping the E in the regex would be fine, then.

>>> import base64
>>> base64.b64encode("\0\0\0\x07ssh-rsa\x00")
'AAAAB3NzaC1yc2EA'
>>> base64.b64encode("\0\0\0\x07ssh-rsa\xFF")
'AAAAB3NzaC1yc2H/'
#              ^- last character isn't an E anymore.

(I only picked rsa as the example here, because it was the shortest. But the same applies to all of them, of course)

@nemchik
Copy link

nemchik commented Jun 19, 2022

@MaPePeR thanks for the follow up! That's super helpful! This comment thread is getting a bit large, so I'm considering making a repository where this could be kept up with and issues and pull requests could be opened to improve the information.

I'd want to include information such as removing characters from the end for the reasons you mentioned.

@nemchik
Copy link

nemchik commented Jun 20, 2022

I've put together a repository here https://github.com/nemchik/ssh-key-regex
I've cited credit to @paranoiq for this gist and @MaPePeR for all of the amazing information provided here in the comments.

If I am made aware of new supported key types I will be happy to update the information or accept pull requests to improve.

A potential future goal will be to use GitHub pages to present the information as a webpage with nicer formatting.

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