diff options
-rwxr-xr-x | ssh_gen_fprint | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/ssh_gen_fprint b/ssh_gen_fprint new file mode 100755 index 0000000..ccea1b2 --- /dev/null +++ b/ssh_gen_fprint @@ -0,0 +1,85 @@ +#!/usr/bin/env ruby + +require 'openssl' +require 'base64' + +# Parse SSH keys to be used by OpenSSL lib +# Taken from Zerg Support project. +# See: https://github.com/pwnall/zerg_support/blob/faaa5dd140c95588a1db2a25f6c9d9cacb4f9b0a/lib/zerg_support/open_ssh.rb +module OpenSSHKeyConverter + # The components in a openssh .pub / known_host RSA public key. + RSA_COMPONENTS = ['ssh-rsa', :e, :n] + # The components in a openssh .pub / known_host DSA public key. + DSA_COMPONENTS = ['ssh-dss', :p, :q, :g, :pub_key] + + # Decodes an openssh public key from the format of .pub & known_hosts files. + def self.decode_pubkey(string) + components = unpack_pubkey_components Base64.decode64(string) + case components.first + when RSA_COMPONENTS.first + ops = RSA_COMPONENTS.zip components + key = OpenSSL::PKey::RSA.new + when DSA_COMPONENTS.first + ops = DSA_COMPONENTS.zip components + key = OpenSSL::PKey::DSA.new + else + fail "Unsupported key type #{components.first}" + end + ops.each do |o| + next unless o.first.is_a? Symbol + key.send "#{o.first}=", decode_mpi(o.last) + end + key + end + + # Loads a serialized key from an IO instance (File, StringIO). + def self.load_key(io) + serialized_key = io.read + header = first_line serialized_key + if header.index 'RSA' + OpenSSL::PKey::RSA.new serialized_key + elsif header.index 'DSA' + OpenSSL::PKey::DSA.new serialized_key + else + fail 'Unknown key type' + end + end + + # Extracts the first line of a string. + def self.first_line(string) + string[0, string.index(/\r|\n/) || string.len] + end + + # Unpacks the string components in an openssh-encoded pubkey. + def self.unpack_pubkey_components(str) + cs = [] + i = 0 + while i < str.length + len = str[i, 4].unpack('N').first + cs << str[i + 4, len] + i += 4 + len + end + cs + end + + # Decodes an openssh-mpi-encoded integer. + def self.decode_mpi(mpi_str) + mpi_str.unpack('C*').inject(0) { |a, e| (a << 8) | e } + end +end + +path_to_key = ARGV[0] + +key = File.read(path_to_key).split[1] +key = OpenSSHKeyConverter.decode_pubkey(key) +key = OpenSSL::PKey::RSA.new(key) + +data_string = [7].pack('N') + 'ssh-rsa' + key.public_key.e.to_s(0) + key.public_key.n.to_s(0) + +sha_digest = OpenSSL::Digest::SHA256.digest(data_string) +sha_fingerprint = Base64.encode64(sha_digest) + +md5_fingerprint = OpenSSL::Digest::MD5.hexdigest(data_string).scan(/../).join(':') + +puts('MD5: ' + md5_fingerprint) +puts('SHA256: ' + sha_fingerprint) |