Class: SSHKey
- Inherits:
-
Object
- Object
- SSHKey
- Defined in:
- lib/sshkey.rb,
lib/sshkey/version.rb
Constant Summary collapse
- SSH_TYPES =
{"rsa" => "ssh-rsa", "dsa" => "ssh-dss"}
- SSH_CONVERSION =
{"rsa" => ["e", "n"], "dsa" => ["p", "q", "g", "pub_key"]}
- VERSION =
"1.4.0"
Instance Attribute Summary collapse
-
#comment ⇒ Object
Returns the value of attribute comment.
-
#key_object ⇒ Object
readonly
Returns the value of attribute key_object.
-
#passphrase ⇒ Object
Returns the value of attribute passphrase.
-
#type ⇒ Object
readonly
Returns the value of attribute type.
Class Method Summary collapse
-
.fingerprint ⇒ Object
Fingerprints.
-
.generate(options = {}) ⇒ Object
Generate a new keypair and return an SSHKey object.
-
.md5_fingerprint(key) ⇒ Object
Fingerprints.
-
.sha1_fingerprint(key) ⇒ Object
SHA1 fingerprint for the given SSH key.
-
.valid_ssh_public_key?(ssh_public_key) ⇒ Boolean
Validate an existing SSH public key.
Instance Method Summary collapse
-
#bits ⇒ Object
Determine the length (bits) of the key as an integer.
-
#encrypted_private_key ⇒ Object
Fetch the encrypted RSA/DSA private key using the passphrase provided.
-
#initialize(private_key, options = {}) ⇒ SSHKey
constructor
Create a new SSHKey object.
-
#md5_fingerprint ⇒ Object
(also: #fingerprint)
Fingerprints.
-
#private_key ⇒ Object
(also: #rsa_private_key, #dsa_private_key)
Fetch the RSA/DSA private key.
-
#public_key ⇒ Object
(also: #rsa_public_key, #dsa_public_key)
Fetch the RSA/DSA public key.
-
#randomart ⇒ Object
Randomart.
-
#sha1_fingerprint ⇒ Object
SHA1 fingerprint for the given SSH public key.
-
#ssh_public_key ⇒ Object
SSH public key.
Constructor Details
#initialize(private_key, options = {}) ⇒ SSHKey
Create a new SSHKey object
Parameters
-
private_key - Existing RSA or DSA private key
-
options<~Hash>
-
:comment<~String> - Comment to use for the public key, defaults to “”
-
:passphrase<~String> - If the key is encrypted, supply the passphrase
-
135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/sshkey.rb', line 135 def initialize(private_key, = {}) @passphrase = [:passphrase] @comment = [:comment] || "" begin @key_object = OpenSSL::PKey::RSA.new(private_key, passphrase) @type = "rsa" rescue @key_object = OpenSSL::PKey::DSA.new(private_key, passphrase) @type = "dsa" end end |
Instance Attribute Details
#comment ⇒ Object
Returns the value of attribute comment.
11 12 13 |
# File 'lib/sshkey.rb', line 11 def comment @comment end |
#key_object ⇒ Object (readonly)
Returns the value of attribute key_object.
10 11 12 |
# File 'lib/sshkey.rb', line 10 def key_object @key_object end |
#passphrase ⇒ Object
Returns the value of attribute passphrase.
11 12 13 |
# File 'lib/sshkey.rb', line 11 def passphrase @passphrase end |
#type ⇒ Object (readonly)
Returns the value of attribute type.
10 11 12 |
# File 'lib/sshkey.rb', line 10 def type @type end |
Class Method Details
.fingerprint ⇒ Object
Fingerprints
Accepts either a public or private key
MD5 fingerprint for the given SSH key
89 90 91 92 93 94 95 |
# File 'lib/sshkey.rb', line 89 def md5_fingerprint(key) if key.match(/PRIVATE/) new(key).md5_fingerprint else Digest::MD5.hexdigest(decoded_key(key)).gsub(fingerprint_regex, '\1:\2') end end |
.generate(options = {}) ⇒ Object
Generate a new keypair and return an SSHKey object
The default behavior when providing no options will generate a 2048-bit RSA keypair.
Parameters
-
options<~Hash>:
-
:type<~String> - “rsa” or “dsa”, “rsa” by default
-
:bits<~Integer> - Bit length
-
:comment<~String> - Comment to use for the public key, defaults to “”
-
:passphrase<~String> - Encrypt the key with this passphrase
-
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/sshkey.rb', line 26 def generate( = {}) type = [:type] || "rsa" # JRuby modulus size must range from 512 to 1024 default_bits = type == "rsa" ? 2048 : 1024 bits = [:bits] || default_bits cipher = OpenSSL::Cipher::Cipher.new("AES-128-CBC") if [:passphrase] case type.downcase when "rsa" then new(OpenSSL::PKey::RSA.generate(bits).to_pem(cipher, [:passphrase]), ) when "dsa" then new(OpenSSL::PKey::DSA.generate(bits).to_pem(cipher, [:passphrase]), ) else raise "Unknown key type: #{type}" end end |
.md5_fingerprint(key) ⇒ Object
Fingerprints
Accepts either a public or private key
MD5 fingerprint for the given SSH key
82 83 84 85 86 87 88 |
# File 'lib/sshkey.rb', line 82 def md5_fingerprint(key) if key.match(/PRIVATE/) new(key).md5_fingerprint else Digest::MD5.hexdigest(decoded_key(key)).gsub(fingerprint_regex, '\1:\2') end end |
.sha1_fingerprint(key) ⇒ Object
SHA1 fingerprint for the given SSH key
92 93 94 95 96 97 98 |
# File 'lib/sshkey.rb', line 92 def sha1_fingerprint(key) if key.match(/PRIVATE/) new(key).sha1_fingerprint else Digest::SHA1.hexdigest(decoded_key(key)).gsub(fingerprint_regex, '\1:\2') end end |
.valid_ssh_public_key?(ssh_public_key) ⇒ Boolean
Validate an existing SSH public key
Returns true or false depending on the validity of the public key provided
Parameters
-
ssh_public_key<~String> - “ssh-rsa AAAAB3NzaC1yc2EA.…”
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/sshkey.rb', line 50 def valid_ssh_public_key?(ssh_public_key) ssh_type, encoded_key = parse_ssh_public_key(ssh_public_key) type = SSH_TYPES.invert[ssh_type] prefix = [0,0,0,7].pack("C*") decoded = Base64.decode64(encoded_key) # Base64 decoding is too permissive, so we should validate if encoding is correct return false unless Base64.encode64(decoded).gsub("\n", "") == encoded_key return false unless decoded.sub!(/^#{prefix}#{ssh_type}/, "") unpacked = decoded.unpack("C*") data = [] index = 0 until unpacked[index].nil? datum_size = from_byte_array unpacked[index..index+4-1], 4 index = index + 4 datum = from_byte_array unpacked[index..index+datum_size-1], datum_size data << datum index = index + datum_size end SSH_CONVERSION[type].size == data.size rescue false end |
Instance Method Details
#bits ⇒ Object
Determine the length (bits) of the key as an integer
192 193 194 |
# File 'lib/sshkey.rb', line 192 def bits key_object.to_text.match(/Private-Key:\s\((\d*)\sbit\)/)[1].to_i end |
#encrypted_private_key ⇒ Object
Fetch the encrypted RSA/DSA private key using the passphrase provided
If no passphrase is set, returns the unencrypted private key
159 160 161 162 |
# File 'lib/sshkey.rb', line 159 def encrypted_private_key return private_key unless passphrase key_object.to_pem(OpenSSL::Cipher::Cipher.new("AES-128-CBC"), passphrase) end |
#md5_fingerprint ⇒ Object Also known as: fingerprint
Fingerprints
MD5 fingerprint for the given SSH public key
181 182 183 |
# File 'lib/sshkey.rb', line 181 def md5_fingerprint Digest::MD5.hexdigest(ssh_public_key_conversion).gsub(/(.{2})(?=.)/, '\1:\2') end |
#private_key ⇒ Object Also known as: rsa_private_key, dsa_private_key
Fetch the RSA/DSA private key
rsa_private_key and dsa_private_key are aliased for backward compatibility
150 151 152 |
# File 'lib/sshkey.rb', line 150 def private_key key_object.to_pem end |
#public_key ⇒ Object Also known as: rsa_public_key, dsa_public_key
Fetch the RSA/DSA public key
rsa_public_key and dsa_public_key are aliased for backward compatibility
167 168 169 |
# File 'lib/sshkey.rb', line 167 def public_key key_object.public_key.to_pem end |
#randomart ⇒ Object
Randomart
Generate OpenSSH compatible ASCII art fingerprints See www.opensource.apple.com/source/OpenSSH/OpenSSH-175/openssh/key.c (key_fingerprint_randomart function)
Example: –[ RSA 2048]—- |o+ o.. | |..+.o | | ooo | |.++. o | |o
+ S | |.. + o . | | . + . | | . . | | Eo. | -----------------
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/sshkey.rb', line 213 def randomart fieldsize_x = 17 fieldsize_y = 9 x = fieldsize_x / 2 y = fieldsize_y / 2 raw_digest = Digest::MD5.digest(ssh_public_key_conversion) num_bytes = raw_digest.bytesize field = Array.new(fieldsize_x) { Array.new(fieldsize_y) {0} } raw_digest.bytes.each do |byte| 4.times do x += (byte & 0x1 != 0) ? 1 : -1 y += (byte & 0x2 != 0) ? 1 : -1 x = [[x, 0].max, fieldsize_x - 1].min y = [[y, 0].max, fieldsize_y - 1].min field[x][y] += 1 if (field[x][y] < num_bytes - 2) byte >>= 2 end end field[fieldsize_x / 2][fieldsize_y / 2] = num_bytes - 1 field[x][y] = num_bytes augmentation_string = " .o+=*BOX@%&#/^SE" output = "+--#{sprintf("[%4s %4u]", type.upcase, bits)}----+\n" fieldsize_y.times do |y| output << "|" fieldsize_x.times do |x| output << augmentation_string[[field[x][y], num_bytes].min] end output << "|" output << "\n" end output << "+#{"-" * fieldsize_x}+" output end |
#sha1_fingerprint ⇒ Object
SHA1 fingerprint for the given SSH public key
187 188 189 |
# File 'lib/sshkey.rb', line 187 def sha1_fingerprint Digest::SHA1.hexdigest(ssh_public_key_conversion).gsub(/(.{2})(?=.)/, '\1:\2') end |
#ssh_public_key ⇒ Object
SSH public key
174 175 176 |
# File 'lib/sshkey.rb', line 174 def ssh_public_key [SSH_TYPES[type], Base64.encode64(ssh_public_key_conversion).gsub("\n", ""), comment].join(" ").strip end |