ssh-publickey 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +15 -0
- data/lib/ssh-publickey.rb +131 -0
- data/lib/ssh-publickey/version.rb +4 -0
- data/ssh-publickey.gemspec +18 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b36f93c81f7da614c5cee2607f98884dafdc571cf1b1e9f6ae648e2ffbd9563f
|
4
|
+
data.tar.gz: 77567cac8bd9eaf0fb657beb16aa64fb5aad11943314858d68ab1513483eaec2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 623fb771883a64e32b2de5ea98639e98df9160fcd0bee2e0688eb5fcd86a38d8d3c30b4140d0ca55de8befeb361f1dab32f01478a05a089d7962e6af2f361b6f
|
7
|
+
data.tar.gz: c27a6629d01d0a9b45934d6abc6fdc46ead9ad7e80ac0604e85343f59b320694550e3008729c193ea8b2cf3c2716bd80ae9c2bbed662b599f62d91bb25c551d4
|
data/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# Convert SSH public key from/to RFC4716/OpenSSH format
|
2
|
+
|
3
|
+
Examples:
|
4
|
+
|
5
|
+
~~~ruby
|
6
|
+
require 'ssh-publickey'
|
7
|
+
|
8
|
+
# Convert key
|
9
|
+
SSHPublicKey.openssh_to_rfc4716(k_openssh)
|
10
|
+
SSHPublicKey.rfc4716_to_openssh(k_rfc4716)
|
11
|
+
|
12
|
+
# Test key
|
13
|
+
SSHPublicKey.is_openssh?(k)
|
14
|
+
SSHPublicKey.is_rfc4716?(k)
|
15
|
+
~~~
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require_relative 'ssh-publickey/version'
|
2
|
+
|
3
|
+
# Convert SSH public key from/to RFC4716/OpenSSH format
|
4
|
+
#
|
5
|
+
class SSHPublicKey
|
6
|
+
# Report public key processing error
|
7
|
+
class PublicKeyError < StandardError
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
# Maximum text size in a line for PEM format
|
12
|
+
LINE_BREAK = 70
|
13
|
+
|
14
|
+
|
15
|
+
# Regex for authorized key
|
16
|
+
AUTHORIZED_KEY_REGEX =
|
17
|
+
/^(?: (?<directives>(?:[!-~]|\s(?=.*"))+) \s+ )? # Options
|
18
|
+
(?<type> [a-z0-9_-]+) \s+ # Type
|
19
|
+
(?<key> [A-Za-z0-9+\/]+=*) # Key
|
20
|
+
(?:\s+ (?<comment>.*?) \s* )? # Comments
|
21
|
+
$/x
|
22
|
+
|
23
|
+
|
24
|
+
# Regex for OpenSSH public key
|
25
|
+
# Same as authorized keys but without directives
|
26
|
+
PUBKEY_OPENSSH_REGEX =
|
27
|
+
/^ (?<type> [a-z0-9_-]+) \s+ # Type
|
28
|
+
(?<key> [A-Za-z0-9+\/]+=*) # Key
|
29
|
+
(?:\s+ (?<comment>.*?) \s* )? # Comments
|
30
|
+
$/x
|
31
|
+
|
32
|
+
|
33
|
+
# Regex for RFC4716 public key
|
34
|
+
PUBKEY_RFC4716_REGEX =
|
35
|
+
/^----\sBEGIN\sSSH2\sPUBLIC\sKEY\s----\R
|
36
|
+
(?<tags> (?:[^:\p{Space}\p{Cntrl}]{1,64} # Tags
|
37
|
+
\s*:\s*
|
38
|
+
(?:[^\\\r\n]*\\\R)* [^\\\r\n]+\R)*)
|
39
|
+
(?<key> (?:[A-Za-z0-9+\/]+\R)* # Key
|
40
|
+
[A-Za-z0-9+\/]+=*\R)
|
41
|
+
----\sEND\sSSH2\sPUBLIC\sKEY\s----
|
42
|
+
$/xmu
|
43
|
+
|
44
|
+
|
45
|
+
# :nodoc:
|
46
|
+
PUBKEY_RFC4716_HEADERTAG_REGEX =
|
47
|
+
/[^:\p{Space}\p{Cntrl}]{1,64}
|
48
|
+
\s*:\s*
|
49
|
+
(?:[^\\\r\n]*\\\R)*[^\\\r\n]+\R/xmu
|
50
|
+
|
51
|
+
|
52
|
+
# Convert a public key in OpenSSH format to RFC4716 format
|
53
|
+
#
|
54
|
+
# @param [String] pubkey public key in OpenSSH format
|
55
|
+
#
|
56
|
+
# @return [String] public key in RFC4716 format
|
57
|
+
#
|
58
|
+
def self.openssh_to_rfc4716(pubkey)
|
59
|
+
unless m = AUTHORIZED_KEY_REGEX.match(pubkey)
|
60
|
+
raise PublicKeyError, "invalid OpenSSH public key"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Lines are limited to 72 8-bytes char
|
64
|
+
# - limit ourselves to 70 to keep room for \\ and \n
|
65
|
+
# - comment part can be unicode so 1 char can be more that 1 byte
|
66
|
+
linesize = 0
|
67
|
+
comment = "Comment: #{m[:comment]}"
|
68
|
+
.each_char.slice_before {|c|
|
69
|
+
bytesize = c.bytes.size
|
70
|
+
if linesize + bytesize > LINE_BREAK
|
71
|
+
then linesize = 0 ; true
|
72
|
+
else linesize += bytesize ; false
|
73
|
+
end
|
74
|
+
}.map(&:join).join("\\\n")
|
75
|
+
key = m[:key].scan(/.{1,70}/).join("\n")
|
76
|
+
|
77
|
+
reskey = []
|
78
|
+
reskey << "---- BEGIN SSH2 PUBLIC KEY ----"
|
79
|
+
reskey << comment
|
80
|
+
reskey << key
|
81
|
+
reskey << "---- END SSH2 PUBLIC KEY ----"
|
82
|
+
reskey.join("\n")
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# Convert a public key in RFC4716 format to OpenSSH format
|
87
|
+
#
|
88
|
+
# @param [String] pubkey public key in RFC4716 format
|
89
|
+
#
|
90
|
+
# @return [String] public key in OpenSSH format
|
91
|
+
#
|
92
|
+
def self.rfc4716_to_openssh(pubkey)
|
93
|
+
unless m = PUBKEY_RFC4716_REGEX.match(pubkey)
|
94
|
+
raise PublicKeyError, "invalid RFC4716 public key"
|
95
|
+
end
|
96
|
+
|
97
|
+
key = m[:key].gsub(/\R/, '')
|
98
|
+
keydata = m[:key].unpack1('m')
|
99
|
+
len = keydata.unpack1('N')
|
100
|
+
type = keydata[4,len]
|
101
|
+
tags = Hash[m[:tags].scan(PUBKEY_RFC4716_HEADERTAG_REGEX)
|
102
|
+
.map {|tag| tag.gsub(/\\\R/, '').strip }
|
103
|
+
.map {|tag| tag.split(/\s*:\s*/, 2) }]
|
104
|
+
comment = tags.transform_keys {|k| k.downcase }['comment']
|
105
|
+
directives = nil
|
106
|
+
|
107
|
+
[directives, type, key, comment ].compact.join(' ')
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# Test if a public key is in OpenSSH format
|
112
|
+
#
|
113
|
+
# @param [String] pubkey public key in RFC4716 format
|
114
|
+
#
|
115
|
+
# @return [Boolean]
|
116
|
+
#
|
117
|
+
def self.is_openssh?(pubkey)
|
118
|
+
PUBKEY_RFC4716_REGEX.match?(pubkey)
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
# Test if a public key is in RFC4716 format
|
123
|
+
#
|
124
|
+
# @param [String] pubkey public key in RFC4716 format
|
125
|
+
#
|
126
|
+
# @return [Boolean]
|
127
|
+
#
|
128
|
+
def self.is_rfc4716?(pubkey)
|
129
|
+
PUBKEY_RFC4716_REGEX.match?(pubkey)
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require_relative 'lib/ssh-publickey/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'ssh-publickey'
|
7
|
+
s.version = SSHPublicKey::VERSION
|
8
|
+
s.summary = "SSH public key conversion"
|
9
|
+
s.description = "Convert SSH public key from/to RFC4716/OpenSSH format"
|
10
|
+
s.authors = [ "Stéphane D'Alu" ]
|
11
|
+
s.email = [ 'stephane.dalu@insa-lyon.fr' ]
|
12
|
+
s.files = %w[ README.md ssh-publickey.gemspec ] + Dir['lib/**/*.rb']
|
13
|
+
s.homepage = 'https://gitlab.com/sdalu/ssh-publickey'
|
14
|
+
s.license = 'MIT'
|
15
|
+
|
16
|
+
s.add_development_dependency 'yard', '~>0'
|
17
|
+
s.add_development_dependency 'rake', '~>13'
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ssh-publickey
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stéphane D'Alu
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-04-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: yard
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '13'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '13'
|
41
|
+
description: Convert SSH public key from/to RFC4716/OpenSSH format
|
42
|
+
email:
|
43
|
+
- stephane.dalu@insa-lyon.fr
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- README.md
|
49
|
+
- lib/ssh-publickey.rb
|
50
|
+
- lib/ssh-publickey/version.rb
|
51
|
+
- ssh-publickey.gemspec
|
52
|
+
homepage: https://gitlab.com/sdalu/ssh-publickey
|
53
|
+
licenses:
|
54
|
+
- MIT
|
55
|
+
metadata: {}
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options: []
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirements: []
|
71
|
+
rubygems_version: 3.0.8
|
72
|
+
signing_key:
|
73
|
+
specification_version: 4
|
74
|
+
summary: SSH public key conversion
|
75
|
+
test_files: []
|