ssh-publickey 0.1

Sign up to get free protection for your applications and to get access to all the features.
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,4 @@
1
+ class SSHPublicKey
2
+ # Current version
3
+ VERSION = '0.1'
4
+ 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: []