29

I try to find a script to decrypt (unhash) the ssh hostnames in the known_hosts file by passing a list of the hostnamses.

So, to do exactly the reverse of:

ssh-keygen -H -f known_hosts

Or also, to do the same as this if the ssh config HashKnownHosts is set to No:

ssh-keygen -R know-host.com -f known_hosts
ssh-keyscan -H know-host.com >> known_hosts

But without re-downloading the host key (caused by ssh-keyscan).

Something like:

ssh-keygen --decrypt -f known_hosts --hostnames hostnames.txt

Where hostnames.txt contains a list of hostnames.

Xorax
  • 515
  • 1
  • 5
  • 9
  • The hostnames are part of the entries in `known_hosts`. What's to decrypt? – muru Dec 19 '14 at 18:21
  • 3
    I mean for a crypted known_hosts file. Where the ssh config HashKnownHosts is to Yes. I modified the title. – Xorax Dec 19 '14 at 18:26

3 Answers3

41

Lines in the known_hosts file are not encrypted, they are hashed. You can't decrypt them, because they're not encrypted. You can't “unhash” them, because that what a hash is all about — given the hash, it's impossible¹ to discover the original string. The only way to “unhash” is to guess the original string and verify your guess.

If you have a list of host names, you can pass them to ssh-keygen -F and replace them by the host name.

while read host comment; do
  found=$(ssh-keygen -F "$host" | grep -v '^#' | sed "s/^[^ ]*/$host/")
  if [ -n "$found" ]; then
    ssh-keygen -R "$host"
    echo "$found" >>~/.ssh/known_hosts
  fi
done <hostnames.txt

¹ In a practical sense, i.e. it would take all the computers existing today longer than the present age of the universe to do it.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
  • +1. I have a bash_completion file with a list of ssh files. The host keys for a lot of servers had changed, so I modified your script to give me a list of files which was 1) in my host list (generated) 2) in my known_hosts file (connected to at some point), so to know which hosts I most likely had to get new host keys for. Ended up with: `grep "^..[dtn]" .ssh/ssh_hosts | while read H; do [ -n "$(ssh-keygen -F "$H")" ] && echo $H; done`. Basically I knew the host name pattern most likely to be affected, and sent those server names through the script, outputting those in the know_hosts file. – sastorsl Nov 05 '20 at 07:58
  • Good answer. But hashing is just irreversible encryption. Unlike block ciphers and some other forms of reversible encryption, which are reversible encryption. – Edward Ned Harvey Jan 13 '23 at 21:10
  • 2
    @EdwardNedHarvey Encryption is reversible, by definition. – Gilles 'SO- stop being evil' Jan 13 '23 at 22:22
22

The ssh-keygen(1) man page says for the -F hostname option:

Search for the specified hostname in a known_hosts file, listing any occurrences found. This option is useful to find hashed host names or addresses and may also be used in conjunction with the -H option to print found keys in a hashed format.

This seems to be what you want.

vinc17
  • 11,912
  • 38
  • 45
  • This return the line with the hashed hostname. I want to unhash it to replace it in the known_hosts file. It need a script to parse each line, un-hash it, and then replace it in the known_hosts file. – Xorax Dec 19 '14 at 18:34
  • 2
    @Xorax Yes, but with this command, you can retrieve the hashed hostname, and replace it in the `known_hosts` file with `sed`. – vinc17 Dec 19 '14 at 18:38
0

Im finding with these new encrypted files is to simply rm the known_hosts. Copy and paste the text to another location and put a comment above the encrypted known_hosts line about what ip is and the device. Trying to decrypt them just doesn't provide the info you need.