How to verify a wireguard public key?

Jason A. Donenfeld Jason at zx2c4.com
Fri Dec 25 00:30:57 CET 2020


It's probably wisest to ignore differences between public keys and
private keys and set aside any structure they might have by virtue of
being related to elliptic curves, and instead just regard them as
32-byte strings encoded in base64. Not 31 bytes or 33 bytes, but exactly
32. This matters, because 32 does not divide evenly by .75, so there's a
padding character and the penultimate character does not include the
whole base64 alphabet. 43 base64 chars can represent up to 258bits,
which is more than 256bits. So, you can either validate this with a
base64 parser and checking that it returns exactly 32 bytes, or you can
match against this simple regex:

^[A-Za-z0-9+/]{42}[A|E|I|M|Q|U|Y|c|g|k|o|s|w|4|8|0]=$

You can convince yourself that's correct by running this for a while and
seeing that it never fails:

while true; do [[ $(head -c 32 /dev/urandom | base64) =~ ^[A-Za-z0-9+/]{42}[A|E|I|M|Q|U|Y|c|g|k|o|s|w|4|8|0]=$ ]] || echo "FAILURE"; done

The endings are valid because those are the only ones that don't end in
01, 10, or 11, so that the string doesn't exceed 256 bits. And again we
can have bash bruteforce those for us:

for i in {A..Z} {a..z} {0..9} + /; do a="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA$i="; [[ $(echo $a|base64 -d|base64) == $a ]] && echo -n $i; done; echo
AEIMQUYcgkosw048


More information about the WireGuard mailing list