
Brent- Yes, IOS is storing the MD5 of the binary key data, not the base64 version. I had that wrong. Still a distinction without a difference. The preimage problem still exists. And as you've been clearly ramping up the condescension in the last few messages, I don't feel inclined to debate this with you any further. Take care. On Wed, Sep 3, 2025 at 7:58 AM brent saner <brent.saner@gmail.com> wrote:
On Wed, Sep 3, 2025 at 2:00 AM Tom Beecher <beecher@beecher.cc> wrote:
Brent-
Yes, you are correct about what is transmitted over the wire. Thank you. That being said, I believe it's still a distinction without a difference.
The only information stored on the router is the MD5 hash *of the base64 encoded public key*. Therefore when someone attempts to authenticate, the router *must* convert the presented mpint to base64, then take the md5sum of the result and compare to the config.
No, Tom; still wrong. See Dan Mahoney's Medium post <https://gushi.medium.com/what-i-learned-from-configuring-ssh-pubkey-auth-on-cisco-ios-cbeb1e5b3b77> .
He uploads the key:
switch(config)#username testcase privilege 15 switch(config)#ip ssh pubkey-chain switch(conf-ssh-pubkey)#username testcase switch(conf-ssh-pubkey-user)#key-string switch(conf-ssh-pubkey-data)#AAAAB3NzaC1yc2EAAAADAQABAAABgQDW switch(conf-ssh-pubkey-data)#45rLjxwnPeaZtu5h4PzvFaLqLIb1ozO+BAdDwqIY switch(conf-ssh-pubkey-data)#bbnqFnbhD42wZ6Cx2iQ3UKet4PziupgXLm2Yc69Q switch(conf-ssh-pubkey-data)#3HE6hP2Z23qHhemZG1G7O9liZ/+P40s2QLm2iRIm switch(conf-ssh-pubkey-data)#TZ4vsKoHNo51aQw+ZI+vUc+nKbZLFOzdZHuqhrw2 switch(conf-ssh-pubkey-data)#oG209csH3rVcBS3ItZuN2MP9+86Lr+64z4ls0Cqq switch(conf-ssh-pubkey-data)#MpBTZlgnxGtLfLW8ASASJm5Fh9onm60O2enBXsrP switch(conf-ssh-pubkey-data)#vC5ZKaLu0tecPC8hFwE7Bi7hAhpxzq1m8V3rdFlo switch(conf-ssh-pubkey-data)#8F05FXs1U89Ou4kgImAdwuW4YTUF15rfUSXR+hpM switch(conf-ssh-pubkey-data)#0c+HAf1KVLE+484zh00CJw1pvxLXTumacfjM0hdJ switch(conf-ssh-pubkey-data)#sRRoSru325hjKu+zhjUVlI20qt+K7Eb+qV62mDUn switch(conf-ssh-pubkey-data)#bsvIGfvFVAD0vCOqi3pASDxrrcGUHEU0zMAP8+mG switch(conf-ssh-pubkey-data)#6Ai7NZ+ilQs31NZcECubNDXh8xESyQI7w/r8xd5H switch(conf-ssh-pubkey-data)#CBfLE5VdssqZxflw832RQllS5p+d8sU= switch(conf-ssh-pubkey-data)#exit switch(conf-ssh-pubkey-user)#exit switch(conf-ssh-pubkey)#exit
We can just copy and paste this right into a text file *t.txt* to prove this.
So everyone at home can play along:
$ file t.txt t.txt: ASCII text
$ head -n1 t.txt switch(config)#username testcase privilege 15
$ b3sum t.txt b2caccb61dfd0d8bab4f864befbe6bc62d6bf376e44db2d118dd2e8e3589d6df t.txt
$ head -n1 t.txt | xxd 00000000: 7377 6974 6368 2863 6f6e 6669 6729 2375 switch(config)#u 00000010: 7365 726e 616d 6520 7465 7374 6361 7365 sername testcase 00000020: 2070 7269 7669 6c65 6765 2031 350a privilege 15.
$ tail -n1 t.txt | xxd 00000000: 7377 6974 6368 2863 6f6e 662d 7373 682d switch(conf-ssh- 00000010: 7075 626b 6579 2923 6578 6974 0a pubkey)#exit.
No extra trailing whitespace, pasted just as-is, nothing up my sleeve.
First let's remove the prompt prefixes since those obviously wouldn't be present in the actual uploaded form.
$ sed -i -re 's/^.+#//g' t.txt
You should now have:
$ cat t.txt username testcase privilege 15 ip ssh pubkey-chain username testcase key-string AAAAB3NzaC1yc2EAAAADAQABAAABgQDW 45rLjxwnPeaZtu5h4PzvFaLqLIb1ozO+BAdDwqIY bbnqFnbhD42wZ6Cx2iQ3UKet4PziupgXLm2Yc69Q 3HE6hP2Z23qHhemZG1G7O9liZ/+P40s2QLm2iRIm TZ4vsKoHNo51aQw+ZI+vUc+nKbZLFOzdZHuqhrw2 oG209csH3rVcBS3ItZuN2MP9+86Lr+64z4ls0Cqq MpBTZlgnxGtLfLW8ASASJm5Fh9onm60O2enBXsrP vC5ZKaLu0tecPC8hFwE7Bi7hAhpxzq1m8V3rdFlo 8F05FXs1U89Ou4kgImAdwuW4YTUF15rfUSXR+hpM 0c+HAf1KVLE+484zh00CJw1pvxLXTumacfjM0hdJ sRRoSru325hjKu+zhjUVlI20qt+K7Eb+qV62mDUn bsvIGfvFVAD0vCOqi3pASDxrrcGUHEU0zMAP8+mG 6Ai7NZ+ilQs31NZcECubNDXh8xESyQI7w/r8xd5H CBfLE5VdssqZxflw832RQllS5p+d8sU= exit exit exit
Let's of course get rid of the commands as well. Those aren't part of the base64 of the key.
$ sed -i -e '19,21d' -e '1,4d' t.txt
$ cat t.txt AAAAB3NzaC1yc2EAAAADAQABAAABgQDW 45rLjxwnPeaZtu5h4PzvFaLqLIb1ozO+BAdDwqIY bbnqFnbhD42wZ6Cx2iQ3UKet4PziupgXLm2Yc69Q 3HE6hP2Z23qHhemZG1G7O9liZ/+P40s2QLm2iRIm TZ4vsKoHNo51aQw+ZI+vUc+nKbZLFOzdZHuqhrw2 oG209csH3rVcBS3ItZuN2MP9+86Lr+64z4ls0Cqq MpBTZlgnxGtLfLW8ASASJm5Fh9onm60O2enBXsrP vC5ZKaLu0tecPC8hFwE7Bi7hAhpxzq1m8V3rdFlo 8F05FXs1U89Ou4kgImAdwuW4YTUF15rfUSXR+hpM 0c+HAf1KVLE+484zh00CJw1pvxLXTumacfjM0hdJ sRRoSru325hjKu+zhjUVlI20qt+K7Eb+qV62mDUn bsvIGfvFVAD0vCOqi3pASDxrrcGUHEU0zMAP8+mG 6Ai7NZ+ilQs31NZcECubNDXh8xESyQI7w/r8xd5H CBfLE5VdssqZxflw832RQllS5p+d8sU=
Say, there we go! That's looking VERY base64-y! Now, we're looking for the MD5 sum *270C78AD8FB00FD98FEDF00C0E8F4D35* (or *270c78ad8fb00fd98fedf00c0e8f4d35,* same thing; hashes are binary, they're just usually represented in hex because it's a lot easier for human eyes than a lot of 0's and 1's).
ip ssh pubkey-chain username testcase key-hash ssh-rsa 270C78AD8FB00FD98FEDF00C0E8F4D35 quit
Let's make a standard GNU md5sum check file format.
$ cat t.md5 270c78ad8fb00fd98fedf00c0e8f4d35 t.txt
Ok! Let's check for that MD5!
$ md5sum t.txt ea327a2f162f4ba8d6a9f1fff6f7cc0e t.txt
Wow... That's really, really weird, Tom. You keep saying it stores the MD5 of the *base64 encoding* of the key, but that's a totally different checksum. Well, maybe it strips the newlines?
$ cat t.txt | tr -d '\n' | md5sum bf91a39b8ff4ce69850dcd945f1319d5 -
$ cat t.txt | tr -d '\n' > t.stripped ; mv t.stripped t.txt $ md5sum -c t.md5 t.txt: FAILED md5sum: WARNING: 1 computed checksum did NOT match
Huh. No dice, Tom.
Hey, you don't suppose it maybe... decodes the base64, and *stores the MD5 checksum of what the pubkey would look like on the wire*?
(Sidenote, base64(1) is newline-agnostic when decoding; *cat t.txt | tr -d '\n' | base64 -d | b3sum* will return the same exact sum as *cat t.txt | base64 -d | b3sum*. Still no funny business, promise!)
$ cat t.txt | base64 -d | md5sum 270c78ad8fb00fd98fedf00c0e8f4d35 -
$ cat t.txt | base64 -d > t.bin ; mv t.bin t.txt $ md5sum -c t.md5 t.txt: OK
Holy cats, Tom! Would ya look at that? It looks like it's *storing the MD5 sum of the actual real public key*, not the base64 encoded version! Who could have ever possibly guessed such a thing?
$ cat t.txt | head -c 15 | xxd 00000000: 0000 0007 7373 682d 7273 6100 0000 03 ....ssh-rsa....
]$ cat t.txt | head -c 15 | xxd -ps -c 0 000000077373682d72736100000003
Crazy! That DEFINITELY looks like the straight byte-packed over-the-wire form <https://sshref.dev/#bkdn_rsa_pub_struct>! Man, that's really weird, Tom. It's almost as if *IOS would what to keep the checksum of the actual bytes it'd be checking it against*, rather than *a base64-encoded version of the data it'd be checking it against*, so it wouldn't have to *base64-encode the bytes every time* they were sent during session establishment.