jose 0.3.1 → 1.0.0

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.
@@ -89,7 +89,7 @@ class JOSE::JWE::ALG_AES_GCM_KW < Struct.new(:cipher_name, :bits, :iv, :tag)
89
89
  end
90
90
 
91
91
  def next_cek(key, enc)
92
- return enc.next_cek
92
+ return enc.next_cek, self
93
93
  end
94
94
 
95
95
  # API functions
@@ -45,7 +45,7 @@ class JOSE::JWE::ALG_AES_KW < Struct.new(:bits)
45
45
  end
46
46
 
47
47
  def next_cek(key, enc)
48
- return enc.next_cek
48
+ return enc.next_cek, self
49
49
  end
50
50
 
51
51
  # API functions
@@ -1,11 +1,11 @@
1
- class JOSE::JWE::ALG_dir
1
+ class JOSE::JWE::ALG_dir < Struct.new(:direct)
2
2
 
3
3
  # JOSE::JWE callbacks
4
4
 
5
5
  def self.from_map(fields)
6
6
  case fields['alg']
7
7
  when 'dir'
8
- return new(), fields.delete('alg')
8
+ return new(true), fields.delete('alg')
9
9
  else
10
10
  raise ArgumentError, "invalid 'alg' for JWE: #{fields['alg'].inspect}"
11
11
  end
@@ -35,9 +35,9 @@ class JOSE::JWE::ALG_dir
35
35
 
36
36
  def next_cek(key, enc)
37
37
  if key.is_a?(String)
38
- return key
38
+ return key, self
39
39
  else
40
- return key.kty.derive_key
40
+ return key.kty.derive_key, self
41
41
  end
42
42
  end
43
43
 
@@ -57,26 +57,31 @@ class JOSE::JWE::ALG_ECDH_ES < Struct.new(:bits, :epk, :apu, :apv)
57
57
 
58
58
  def key_decrypt(box_keys, enc, encrypted_key)
59
59
  other_public_key, my_private_key = box_keys
60
- if my_private_key and epk and epk.to_key != other_public_key.to_key
61
- raise ArgumentError, "other and ephemeral public key mismatch"
62
- elsif epk and my_private_key.nil?
60
+ if my_private_key.nil?
63
61
  my_private_key = other_public_key
64
- other_public_key = epk
65
- else
66
- raise ArgumentError, "missing 'epk' or my_private_key"
62
+ other_public_key = nil
63
+ end
64
+ if epk.nil? and other_public_key.nil?
65
+ raise ArgumentError, "missing 'epk' and 'other_public_key'"
66
+ elsif epk and other_public_key and epk.thumbprint != other_public_key.thumbprint
67
+ raise ArgumentError, "other and ephemeral public key mismatch"
68
+ end
69
+ new_alg = self
70
+ if epk.nil?
71
+ new_alg = JOSE::JWE::ALG_ECDH_ES.new(bits, other_public_key.to_public, apu, apv)
67
72
  end
68
- z = other_public_key.derive_key(my_private_key)
73
+ z = new_alg.epk.derive_key(my_private_key)
69
74
  if bits.nil?
70
75
  algorithm_id = enc.algorithm
71
76
  key_data_len = enc.bits
72
77
  supp_pub_info = [key_data_len].pack('N')
73
- derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, apu, apv, supp_pub_info], key_data_len)
78
+ derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, new_alg.apu, new_alg.apv, supp_pub_info], key_data_len)
74
79
  return derived_key
75
80
  else
76
- algorithm_id = algorithm
77
- key_data_len = bits
81
+ algorithm_id = new_alg.algorithm
82
+ key_data_len = new_alg.bits
78
83
  supp_pub_info = [key_data_len].pack('N')
79
- derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, apu, apv, supp_pub_info], key_data_len)
84
+ derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, new_alg.apu, new_alg.apv, supp_pub_info], key_data_len)
80
85
  decrypted_key = JOSE::JWA::AES_KW.unwrap(encrypted_key, derived_key)
81
86
  return decrypted_key
82
87
  end
@@ -87,27 +92,49 @@ class JOSE::JWE::ALG_ECDH_ES < Struct.new(:bits, :epk, :apu, :apv)
87
92
  return '', self
88
93
  else
89
94
  other_public_key, my_private_key = box_keys
95
+ if my_private_key.nil?
96
+ raise ArgumentError, "missing 'my_private_key'"
97
+ elsif other_public_key.nil?
98
+ raise ArgumentError, "missing 'other_public_key'"
99
+ elsif epk and my_private_key and epk.thumbprint != my_private_key.thumbprint
100
+ raise ArgumentError, "private and ephemeral public key mismatch"
101
+ end
102
+ new_alg = self
103
+ if epk.nil?
104
+ new_alg = JOSE::JWE::ALG_ECDH_ES.new(bits, my_private_key.to_public, apu, apv)
105
+ end
90
106
  z = other_public_key.derive_key(my_private_key)
91
- algorithm_id = algorithm
92
- key_data_len = bits
107
+ algorithm_id = new_alg.algorithm
108
+ key_data_len = new_alg.bits
93
109
  supp_pub_info = [key_data_len].pack('N')
94
- derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, apu, apv, supp_pub_info], key_data_len)
110
+ derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, new_alg.apu, new_alg.apv, supp_pub_info], key_data_len)
95
111
  encrypted_key = JOSE::JWA::AES_KW.wrap(decrypted_key, derived_key)
96
- return encrypted_key, self
112
+ return encrypted_key, new_alg
97
113
  end
98
114
  end
99
115
 
100
116
  def next_cek(box_keys, enc)
101
117
  if bits.nil?
102
118
  other_public_key, my_private_key = box_keys
119
+ if my_private_key.nil?
120
+ raise ArgumentError, "missing 'my_private_key'"
121
+ elsif other_public_key.nil?
122
+ raise ArgumentError, "missing 'other_public_key'"
123
+ elsif epk and my_private_key and epk.thumbprint != my_private_key.thumbprint
124
+ raise ArgumentError, "private and ephemeral public key mismatch"
125
+ end
126
+ new_alg = self
127
+ if epk.nil?
128
+ new_alg = JOSE::JWE::ALG_ECDH_ES.new(bits, my_private_key.to_public, apu, apv)
129
+ end
103
130
  z = other_public_key.derive_key(my_private_key)
104
131
  algorithm_id = enc.algorithm
105
132
  key_data_len = enc.bits
106
133
  supp_pub_info = [key_data_len].pack('N')
107
- derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, apu, apv, supp_pub_info], key_data_len)
108
- return derived_key
134
+ derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, new_alg.apu, new_alg.apv, supp_pub_info], key_data_len)
135
+ return derived_key, new_alg
109
136
  else
110
- return enc.next_cek
137
+ return enc.next_cek, self
111
138
  end
112
139
  end
113
140
 
@@ -20,7 +20,7 @@ class JOSE::JWE::ALG_PBES2 < Struct.new(:hmac, :bits, :salt, :iter)
20
20
  end
21
21
  iter = nil
22
22
  if not fields.has_key?('p2c')
23
- iter = 1000
23
+ iter = bits * 32
24
24
  elsif fields['p2c'].is_a?(Integer) and fields['p2c'] >= 0
25
25
  iter = fields['p2c']
26
26
  else
@@ -76,7 +76,7 @@ class JOSE::JWE::ALG_PBES2 < Struct.new(:hmac, :bits, :salt, :iter)
76
76
  end
77
77
  new_alg = self
78
78
  if new_alg.salt.nil?
79
- new_alg = JOSE::JWE::ALG_PBES2.new(hmac, bits, wrap_salt(SecureRandom.random_bytes(8)), iter)
79
+ new_alg = JOSE::JWE::ALG_PBES2.new(hmac, bits, wrap_salt(SecureRandom.random_bytes(bits.div(8))), iter)
80
80
  end
81
81
  derived_key = OpenSSL::PKCS5.pbkdf2_hmac(key, new_alg.salt, new_alg.iter, new_alg.bits.div(8) + (new_alg.bits % 8), new_alg.hmac.new)
82
82
  encrypted_key = JOSE::JWA::AES_KW.wrap(decrypted_key, derived_key)
@@ -84,7 +84,7 @@ class JOSE::JWE::ALG_PBES2 < Struct.new(:hmac, :bits, :salt, :iter)
84
84
  end
85
85
 
86
86
  def next_cek(key, enc)
87
- return enc.next_cek
87
+ return enc.next_cek, self
88
88
  end
89
89
 
90
90
  # API functions
@@ -47,7 +47,7 @@ class JOSE::JWE::ALG_RSA < Struct.new(:rsa_padding, :rsa_oaep_md)
47
47
  end
48
48
 
49
49
  def next_cek(key, enc)
50
- return enc.next_cek
50
+ return enc.next_cek, self
51
51
  end
52
52
 
53
53
  # API functions
@@ -1,8 +1,45 @@
1
1
  module JOSE
2
+ # JWK stands for JSON Web Key which is defined in [RFC 7517](https://tools.ietf.org/html/rfc7517).
2
3
  class JWK < Struct.new(:keys, :kty, :fields)
3
4
 
4
5
  # Decode API
5
6
 
7
+ # Converts a binary or map into a `JOSE.JWK`.
8
+ #
9
+ # !!!ruby
10
+ # JOSE::JWK.from({"k" => "", "kty" => "oct"})
11
+ # # => #<struct JOSE::JWK keys=nil, kty=#<struct JOSE::JWK::KTY_oct oct="">, fields=JOSE::Map[]>
12
+ # JOSE::JWK.from("{\"k\":\"\",\"kty\":\"oct\"}")
13
+ # # => #<struct JOSE::JWK keys=nil, kty=#<struct JOSE::JWK::KTY_oct oct="">, fields=JOSE::Map[]>
14
+ #
15
+ # The `"kty"` field may be overridden with a custom module that implements the {JOSE::JWK::KTY JOSE::JWK::KTY} behaviours.
16
+ #
17
+ # For example:
18
+ #
19
+ # !!!ruby
20
+ # JOSE::JWK.from({ "kty" => "custom" }, { kty: MyCustomKey })
21
+ # # => #<struct JOSE::JWK keys=nil, kty=#<MyCustomKey:0x007f8c5419ff68>, fields=JOSE::Map[]>
22
+ #
23
+ # If a `key` has been specified, it will decrypt an encrypted binary or map into a {JOSE::JWK JOSE::JWK} using the specified `key`.
24
+ #
25
+ # !!!ruby
26
+ # JOSE::JWK.from("eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkExMjhHQ00iLCJwMmMiOjQwOTYsInAycyI6Im5OQ1ZNQUktNTU5UVFtbWRFcnBsZFEifQ.Ucye69ii4dxd1ykNFlJyBVeA6xeNu4aV.2pZ4nBoxBjmdrneS.boqwdFZVNAFHk1M5P6kPYgBUgGwW32QuKzHuFA.wL9Hy6dcE_DPkUW9s5iwKA", "password")
27
+ # # => [#<struct JOSE::JWK keys=nil, kty=#<struct JOSE::JWK::KTY_oct oct="secret">, fields=JOSE::Map[]>,
28
+ # # #<struct JOSE::JWE
29
+ # # alg=
30
+ # # #<struct JOSE::JWE::ALG_PBES2
31
+ # # hmac=OpenSSL::Digest::SHA256,
32
+ # # bits=128,
33
+ # # salt="PBES2-HS256+A128KW\x00\x9C\xD0\x950\x02>\xE7\x9FPBi\x9D\x12\xBAeu",
34
+ # # iter=4096>,
35
+ # # enc=#<struct JOSE::JWE::ENC_AES_GCM cipher_name="aes-128-gcm", bits=128, cek_len=16, iv_len=12>,
36
+ # # zip=nil,
37
+ # # fields=JOSE::Map["cty" => "jwk+json"]>]
38
+ #
39
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] object
40
+ # @param [Hash] modules
41
+ # @param [String] key
42
+ # @return [JOSE::JWK, Array<JOSE::JWK>]
6
43
  def self.from(object, modules = nil, key = nil)
7
44
  case object
8
45
  when JOSE::Map, Hash
@@ -11,11 +48,19 @@ module JOSE
11
48
  return from_binary(object, modules, key)
12
49
  when JOSE::JWK
13
50
  return object
51
+ when Array
52
+ return object.map { |obj| from(obj, modules, key) }
14
53
  else
15
- raise ArgumentError, "'object' must be a Hash, String, or JOSE::JWK"
54
+ raise ArgumentError, "'object' must be a Hash, String, JOSE::JWK, or Array"
16
55
  end
17
56
  end
18
57
 
58
+ # Converts a binary into a {JOSE::JWK JOSE::JWK}.
59
+ #
60
+ # @param [String, Array<String>] object
61
+ # @param [Hash] modules
62
+ # @param [String] key
63
+ # @return [JOSE::JWK, Array<JOSE::JWK>]
19
64
  def self.from_binary(object, modules = nil, key = nil)
20
65
  if (modules.is_a?(String) or modules.is_a?(JOSE::JWK)) and key.nil?
21
66
  key = modules
@@ -30,20 +75,39 @@ module JOSE
30
75
  else
31
76
  return from_map(JOSE.decode(object), modules)
32
77
  end
78
+ when Array
79
+ return object.map { |obj| from_binary(obj, modules, key) }
33
80
  else
34
- raise ArgumentError, "'object' must be a String"
81
+ raise ArgumentError, "'object' must be a String or Array"
35
82
  end
36
83
  end
37
84
 
85
+ # Reads file and calls {.from_binary} to convert into a {JOSE::JWK JOSE::JWK}.
86
+ #
87
+ # @param [String] file
88
+ # @param [Hash] modules
89
+ # @param [String] key
90
+ # @return [JOSE::JWK]
38
91
  def self.from_file(file, modules = nil, key = nil)
39
92
  return from_binary(File.binread(file), modules, key)
40
93
  end
41
94
 
95
+ # Converts Ruby records for EC and RSA keys into a {JOSE::JWK JOSE::JWK}.
96
+ #
97
+ # @param [OpenSSL::PKey] object
98
+ # @param [Hash] modules
99
+ # @return [JOSE::JWK]
42
100
  def self.from_key(object, modules = {})
43
101
  kty = modules[:kty] || JOSE::JWK::KTY
44
102
  return JOSE::JWK.new(nil, *kty.from_key(object))
45
103
  end
46
104
 
105
+ # Converts a map into a {JOSE::JWK JOSE::JWK}.
106
+ #
107
+ # @param [JOSE::Map, Hash, Array<JOSE::Map, Hash>] object
108
+ # @param [Hash] modules
109
+ # @param [String] key
110
+ # @return [JOSE::JWK, Array<JOSE::JWK>]
47
111
  def self.from_map(object, modules = nil, key = nil)
48
112
  if (modules.is_a?(String) or modules.is_a?(JOSE::JWK)) and key.nil?
49
113
  key = modules
@@ -58,34 +122,37 @@ module JOSE
58
122
  else
59
123
  return from_fields(JOSE::JWK.new(nil, nil, JOSE::Map.new(object)), modules)
60
124
  end
125
+ when Array
126
+ return object.map { |obj| from_map(obj, modules, key) }
61
127
  else
62
- raise ArgumentError, "'object' must be a String"
63
- end
64
- end
65
-
66
- def self.from_pem(object, modules = nil, password = nil)
67
- if modules.is_a?(String) and password.nil?
68
- password = modules
69
- modules = {}
128
+ raise ArgumentError, "'object' must be a JOSE::Map, Hash, or Array"
70
129
  end
71
- modules ||= {}
72
- kty = modules[:kty] || JOSE::JWK::PEM
73
- return JOSE::JWK.new(nil, *kty.from_binary(object, password))
74
- end
75
-
76
- def self.from_pem_file(file, modules = nil, password = nil)
77
- return from_pem(File.binread(file), modules, password)
78
130
  end
79
131
 
132
+ # Converts an arbitrary binary into a {JOSE::JWK JOSE::JWK} with `"kty"` of `"oct"`.
133
+ #
134
+ # @param [String] object
135
+ # @param [Hash] modules
136
+ # @return [JOSE::JWK]
80
137
  def self.from_oct(object, modules = {})
81
138
  kty = modules[:kty] || JOSE::JWK::KTY_oct
82
139
  return JOSE::JWK.new(nil, *kty.from_oct(object))
83
140
  end
84
141
 
142
+ # Reads file and calls {JOSE::JWK.from_oct JOSE::JWK.from_oct} to convert into a {JOSE::JWK JOSE::JWK}.
143
+ #
144
+ # @param [String] file
145
+ # @param [Hash] modules
146
+ # @return [JOSE::JWK]
85
147
  def self.from_oct_file(file, modules = {})
86
148
  return from_oct(File.binread(file), modules)
87
149
  end
88
150
 
151
+ # Converts an octet key pair into a {JOSE::JWK JOSE::JWK} with `"kty"` of `"OKP"`.
152
+ #
153
+ # @param [Array] object
154
+ # @param [Hash] modules
155
+ # @return [JOSE::JWK]
89
156
  def self.from_okp(object, modules = {})
90
157
  raise ArgumentError, "object must be an Array of length 2" if not object.is_a?(Array) or object.length != 2
91
158
  kty = modules[:kty] || case object[0]
@@ -107,12 +174,100 @@ module JOSE
107
174
  return JOSE::JWK.new(nil, *kty.from_okp(object))
108
175
  end
109
176
 
177
+ # Converts an openssh key into a {JOSE::JWK JOSE::JWK} with `"kty"` of `"OKP"`.
178
+ #
179
+ # @param [String, Array] object
180
+ # @param [Hash] modules
181
+ # @return [JOSE::JWK]
182
+ def self.from_openssh_key(object, modules = {})
183
+ raise ArgumentError, "object must be a String or Array" if not object.is_a?(String) and not object.is_a?(Array)
184
+ keys = object
185
+ if object.is_a?(String)
186
+ keys = JOSE::JWK::OpenSSHKey.from_binary(object)
187
+ end
188
+ ((pk_type, pk), key), = keys[0]
189
+ sk_type, sk_pk, = key
190
+ if pk_type and pk and key and sk_type and sk_pk and pk_type == sk_type and pk == sk_pk
191
+ kty = modules[:kty] || case pk_type
192
+ when 'ssh-ed25519'
193
+ JOSE::JWK::KTY_OKP_Ed25519
194
+ when 'ssh-ed25519ph'
195
+ JOSE::JWK::KTY_OKP_Ed25519ph
196
+ when 'ssh-ed448'
197
+ JOSE::JWK::KTY_OKP_Ed448
198
+ when 'ssh-ed448ph'
199
+ JOSE::JWK::KTY_OKP_Ed448ph
200
+ when 'ssh-x25519'
201
+ JOSE::JWK::KTY_OKP_X25519
202
+ when 'ssh-x448'
203
+ JOSE::JWK::KTY_OKP_X448
204
+ else
205
+ raise ArgumentError, "unrecognized openssh key type: #{pk_type.inspect}"
206
+ end
207
+ return JOSE::JWK.new(nil, *kty.from_openssh_key(key))
208
+ else
209
+ raise ArgumentError, "unrecognized openssh key format"
210
+ end
211
+ end
212
+
213
+ # Reads file and calls {JOSE::JWK.from_openssh_key JOSE::JWK.from_openssh_key} to convert into a {JOSE::JWK JOSE::JWK}.
214
+ #
215
+ # @param [String] file
216
+ # @param [Hash] modules
217
+ # @return [JOSE::JWK]
218
+ def self.from_openssh_key_file(file, modules = {})
219
+ return from_openssh_key(File.binread(file), modules)
220
+ end
221
+
222
+ # Converts a PEM (Privacy Enhanced Email) binary into a {JOSE::JWK JOSE::JWK}.
223
+ #
224
+ # If `password` is present, decrypts an encrypted PEM (Privacy Enhanced Email) binary into a {JOSE::JWK JOSE::JWK} using `password`.
225
+ #
226
+ # @param [String] object
227
+ # @param [Hash] modules
228
+ # @param [String] password
229
+ # @return [JOSE::JWK]
230
+ def self.from_pem(object, modules = nil, password = nil)
231
+ if modules.is_a?(String) and password.nil?
232
+ password = modules
233
+ modules = {}
234
+ end
235
+ modules ||= {}
236
+ kty = modules[:kty] || JOSE::JWK::PEM
237
+ return JOSE::JWK.new(nil, *kty.from_binary(object, password))
238
+ end
239
+
240
+ # Reads file and calls {JOSE::JWK.from_pem JOSE::JWK.from_pem} to convert into a {JOSE::JWK JOSE::JWK}.
241
+ #
242
+ # @param [String] file
243
+ # @param [Hash] modules
244
+ # @param [String] password
245
+ # @return [JOSE::JWK]
246
+ def self.from_pem_file(file, modules = nil, password = nil)
247
+ return from_pem(File.binread(file), modules, password)
248
+ end
249
+
110
250
  # Encode API
111
251
 
252
+ # Converts a {JOSE::JWK JOSE::JWK} into a binary.
253
+ #
254
+ # @param [JOSE::JWK, Array<JOSE::JWK>] jwk
255
+ # @param [String] key
256
+ # @param [JOSE::JWE] jwe
257
+ # @return [String, JOSE::EncryptedBinary, Array<String, JOSE::EncryptedBinary>]
112
258
  def self.to_binary(jwk, key = nil, jwe = nil)
113
- return from(jwk).to_binary(key, jwe)
259
+ if jwk.is_a?(Array)
260
+ return jwk.map { |obj| from(obj).to_binary(key, jwe) }
261
+ else
262
+ return from(jwk).to_binary(key, jwe)
263
+ end
114
264
  end
115
265
 
266
+ # Converts a {JOSE::JWK JOSE::JWK} into a binary.
267
+ #
268
+ # @param [String] key
269
+ # @param [JOSE::JWE] jwe
270
+ # @return [String, JOSE::EncryptedBinary]
116
271
  def to_binary(key = nil, jwe = nil)
117
272
  if not key.nil?
118
273
  jwe ||= kty.key_encryptor(fields, key)
@@ -124,26 +279,61 @@ module JOSE
124
279
  end
125
280
  end
126
281
 
282
+ # Calls {JOSE::JWK.to_binary JOSE::JWK.to_binary} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
283
+ #
284
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] jwk
285
+ # @param [String] file
286
+ # @param [String] key
287
+ # @param [JOSE::JWE] jwe
288
+ # @return [Fixnum] bytes written
127
289
  def self.to_file(jwk, file, key = nil, jwe = nil)
128
290
  return from(jwk).to_file(file, key, jwe)
129
291
  end
130
292
 
293
+ # Calls {JOSE::JWK.to_binary JOSE::JWK.to_binary} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
294
+ #
295
+ # @param [String] file
296
+ # @param [String] key
297
+ # @param [JOSE::JWE] jwe
298
+ # @return [Fixnum] bytes written
131
299
  def to_file(file, key = nil, jwe = nil)
132
300
  return File.binwrite(file, to_binary(key, jwe))
133
301
  end
134
302
 
303
+ # Converts a {JOSE::JWK JOSE::JWK} into the raw key format.
304
+ #
305
+ # @param [JOSE::JWK] jwk
306
+ # @return [OpenSSL::PKey, Object]
135
307
  def self.to_key(jwk)
136
308
  return from(jwk).to_key
137
309
  end
138
310
 
311
+ # Converts a {JOSE::JWK JOSE::JWK} into the raw key format.
312
+ #
313
+ # @return [OpenSSL::PKey, Object]
139
314
  def to_key
140
315
  return kty.to_key
141
316
  end
142
317
 
318
+ # Converts a {JOSE::JWK JOSE::JWK} into a map.
319
+ #
320
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
321
+ # @param [String] key
322
+ # @param [JOSE::JWE] jwe
323
+ # @return [JOSE::Map, Array<JOSE::Map>]
143
324
  def self.to_map(jwk, key = nil, jwe = nil)
144
- return from(jwk).to_map(key, jwe)
325
+ if jwk.is_a?(Array)
326
+ return from(jwk).map { |obj| obj.to_map(key, jwe) }
327
+ else
328
+ return from(jwk).to_map(key, jwe)
329
+ end
145
330
  end
146
331
 
332
+ # Converts a {JOSE::JWK JOSE::JWK} into a map.
333
+ #
334
+ # @param [String] key
335
+ # @param [JOSE::JWE] jwe
336
+ # @return [JOSE::Map]
147
337
  def to_map(key = nil, jwe = nil)
148
338
  if not key.nil?
149
339
  jwe ||= kty.key_encryptor(fields, key)
@@ -155,98 +345,363 @@ module JOSE
155
345
  end
156
346
  end
157
347
 
348
+ # Converts a {JOSE::JWK JOSE::JWK} into a raw binary octet.
349
+ #
350
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
351
+ # @return [String, Array<String>]
158
352
  def self.to_oct(jwk)
159
- return from(jwk).to_oct
353
+ if jwk.is_a?(Array)
354
+ return from(jwk).map { |obj| obj.to_oct }
355
+ else
356
+ return from(jwk).to_oct
357
+ end
160
358
  end
161
359
 
360
+ # Converts a {JOSE::JWK JOSE::JWK} into a raw binary octet.
361
+ #
362
+ # @return [String]
162
363
  def to_oct
163
364
  return kty.to_oct
164
365
  end
165
366
 
367
+ # Calls {JOSE::JWK.to_oct JOSE::JWK.to_oct} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
368
+ #
369
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] jwk
370
+ # @param [String] file
371
+ # @return [Fixnum] bytes written
372
+ def self.to_oct_file(jwk, file)
373
+ return from(jwk).to_file(file)
374
+ end
375
+
376
+ # Calls {JOSE::JWK#to_oct JOSE::JWK#to_oct} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
377
+ #
378
+ # @param [String] file
379
+ # @return [Fixnum] bytes written
380
+ def to_oct_file(file)
381
+ return File.binwrite(file, to_oct)
382
+ end
383
+
384
+ # Converts a {JOSE::JWK JOSE::JWK} into an octet key pair.
385
+ #
386
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
387
+ # @return [Object, Array<Object>]
166
388
  def self.to_okp(jwk)
167
- return from(jwk).to_okp
389
+ if jwk.is_a?(Array)
390
+ return from(jwk).map { |obj| obj.to_okp }
391
+ else
392
+ return from(jwk).to_okp
393
+ end
168
394
  end
169
395
 
396
+ # Converts a {JOSE::JWK JOSE::JWK} into an octet key pair.
397
+ #
398
+ # @return [String]
170
399
  def to_okp
171
400
  return kty.to_okp
172
401
  end
173
402
 
403
+ # Converts a {JOSE::JWK JOSE::JWK} into an OpenSSH key binary.
404
+ #
405
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
406
+ # @return [Object, Array<Object>]
407
+ def self.to_openssh_key(jwk)
408
+ if jwk.is_a?(Array)
409
+ return from(jwk).map { |obj| obj.to_openssh_key }
410
+ else
411
+ return from(jwk).to_openssh_key
412
+ end
413
+ end
414
+
415
+ # Converts a {JOSE::JWK JOSE::JWK} into an OpenSSH key binary.
416
+ #
417
+ # @return [Object]
418
+ def to_openssh_key
419
+ return kty.to_openssh_key(fields)
420
+ end
421
+
422
+ # Calls {JOSE::JWK.to_openssh_key JOSE::JWK.to_openssh_key} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
423
+ #
424
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] jwk
425
+ # @param [String] file
426
+ # @return [Fixnum] bytes written
427
+ def self.to_openssh_key_file(jwk, file)
428
+ return from(jwk).to_file(file)
429
+ end
430
+
431
+ # Calls {JOSE::JWK#to_openssh_key JOSE::JWK#to_openssh_key} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
432
+ #
433
+ # @param [String] file
434
+ # @return [Fixnum] bytes written
435
+ def to_openssh_key_file(file)
436
+ return File.binwrite(file, to_openssh_key)
437
+ end
438
+
439
+ # Converts a {JOSE::JWK JOSE::JWK} into a PEM (Privacy Enhanced Email) binary.
440
+ #
441
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
442
+ # @param [String] password
443
+ # @return [String, Array<String>]
174
444
  def self.to_pem(jwk, password = nil)
175
- return from(jwk).to_pem(password)
445
+ if jwk.is_a?(Array)
446
+ return from(jwk).map { |obj| obj.to_pem(password) }
447
+ else
448
+ return from(jwk).to_pem(password)
449
+ end
176
450
  end
177
451
 
452
+ # Converts a {JOSE::JWK JOSE::JWK} into a PEM (Privacy Enhanced Email) binary.
453
+ #
454
+ # @param [String] password
455
+ # @return [String]
178
456
  def to_pem(password = nil)
179
457
  return kty.to_pem(password)
180
458
  end
181
459
 
460
+ # Calls {JOSE::JWK.to_pem JOSE::JWK.to_pem} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
461
+ #
462
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] jwk
463
+ # @param [String] file
464
+ # @param [String] password
465
+ # @return [Fixnum] bytes written
466
+ def self.to_pem_file(jwk, file, password = nil)
467
+ return from(jwk).to_file(file, password)
468
+ end
469
+
470
+ # Calls {JOSE::JWK#to_pem JOSE::JWK#to_pem} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
471
+ #
472
+ # @param [String] file
473
+ # @param [String] password
474
+ # @return [Fixnum] bytes written
475
+ def to_pem_file(file, password = nil)
476
+ return File.binwrite(file, to_pem(password))
477
+ end
478
+
479
+ # Converts a private {JOSE::JWK JOSE::JWK} into a public {JOSE::JWK JOSE::JWK}.
480
+ #
481
+ # !!!ruby
482
+ # jwk_rsa = JOSE::JWK.generate_key([:rsa, 256]).to_map
483
+ # # => JOSE::Map[
484
+ # # "dq" => "Iv_BghpjRyv8hk4AgsX_3w",
485
+ # # "e" => "AQAB",
486
+ # # "d" => "imiCh2gK77pDAa_NuQbHN1hZdLY0eTl8tp4WLfe1uQ0",
487
+ # # "p" => "-eKE_wk7O5JWw_1fw-rciw",
488
+ # # "qi" => "MqCwIoTTCkYmGQHsOM7IuA",
489
+ # # "n" => "vj2WbxlGF1yU9SoQJMqKw6c2asTks_cVuXEAO3x_yOU",
490
+ # # "kty" => "RSA",
491
+ # # "q" => "wuVog_0-60w7_56y8wZuTw",
492
+ # # "dp" => "lU_9GEdz1UzD-6hSqMaVsQ"]
493
+ # JOSE::JWK.to_public(jwk_rsa).to_map
494
+ # # => JOSE::Map[
495
+ # # "e" => "AQAB",
496
+ # # "n" => "vj2WbxlGF1yU9SoQJMqKw6c2asTks_cVuXEAO3x_yOU",
497
+ # # "kty" => "RSA"]
498
+ #
499
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
500
+ # @return [JOSE::JWK, Array<JOSE::JWK>]
182
501
  def self.to_public(jwk)
183
- return from(jwk).to_public
502
+ if jwk.is_a?(Array)
503
+ return from(jwk).map { |obj| obj.to_public }
504
+ else
505
+ return from(jwk).to_public
506
+ end
184
507
  end
185
508
 
509
+ # Converts a private {JOSE::JWK JOSE::JWK} into a public {JOSE::JWK JOSE::JWK}.
510
+ #
511
+ # @see JOSE::JWK.to_public
512
+ # @return [JOSE::JWK]
186
513
  def to_public
187
514
  return JOSE::JWK.from_map(to_public_map)
188
515
  end
189
516
 
517
+ # Calls {JOSE::JWK.to_binary JOSE::JWK.to_binary} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
518
+ #
519
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] jwk
520
+ # @param [String] file
521
+ # @return [Fixnum] bytes written
522
+ def self.to_public_file(jwk, file)
523
+ return from(jwk).to_public_file(file)
524
+ end
525
+
526
+ # Calls {JOSE::JWK.to_public JOSE::JWK.to_public} on a {JOSE::JWK JOSE::JWK} and then writes the binary to `file`.
527
+ #
528
+ # @param [String] file
529
+ # @return [Fixnum] bytes written
530
+ def to_public_file(file)
531
+ return File.binwrite(file, to_public.to_binary)
532
+ end
533
+
534
+ # Calls {JOSE::JWK.to_public JOSE::JWK.to_public} and then {JOSE::JWK.to_key JOSE::JWK.to_key} on a {JOSE::JWK JOSE::JWK}.
535
+ #
536
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
537
+ # @return [OpenSSL::PKey, Object, Array<OpenSSL::PKey, Object>]
190
538
  def self.to_public_key(jwk)
191
- return from(jwk).to_public_key
539
+ if jwk.is_a?(Array)
540
+ return from(jwk).map { |obj| obj.to_public_key }
541
+ else
542
+ return from(jwk).to_public_key
543
+ end
192
544
  end
193
545
 
546
+ # Calls {JOSE::JWK#to_public JOSE::JWK#to_public} and then {JOSE::JWK#to_key JOSE::JWK#to_key} on a {JOSE::JWK JOSE::JWK}.
547
+ #
548
+ # @return [OpenSSL::PKey, Object]
194
549
  def to_public_key
195
550
  return to_public.to_key
196
551
  end
197
552
 
553
+ # Calls {JOSE::JWK.to_public JOSE::JWK.to_public} and then {JOSE::JWK.to_map JOSE::JWK.to_map} on a {JOSE::JWK JOSE::JWK}.
554
+ #
555
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
556
+ # @return [JOSE::Map, Array<JOSE::Map>]
198
557
  def self.to_public_map(jwk)
199
- return from(jwk).to_public_map
558
+ if jwk.is_a?(Array)
559
+ return from(jwk).map { |obj| obj.to_public_map }
560
+ else
561
+ return from(jwk).to_public_map
562
+ end
200
563
  end
201
564
 
565
+ # Calls {JOSE::JWK#to_public JOSE::JWK#to_public} and then {JOSE::JWK#to_map JOSE::JWK#to_map} on a {JOSE::JWK JOSE::JWK}.
566
+ #
567
+ # @return [JOSE::Map]
202
568
  def to_public_map
203
569
  return kty.to_public_map(fields)
204
570
  end
205
571
 
572
+ # Converts a {JOSE::JWK JOSE::JWK} into a map that can be used by {JOSE::JWK.thumbprint JOSE::JWK.thumbprint}.
573
+ #
574
+ # @param [JOSE::Map, Hash, String, JOSE::JWK, Array<JOSE::Map, Hash, String, JOSE::JWK>] jwk
575
+ # @return [JOSE::Map, Array<JOSE::Map>]
206
576
  def self.to_thumbprint_map(jwk)
207
- return from(jwk).to_thumbprint_map
577
+ if jwk.is_a?(Array)
578
+ return from(jwk).map { |obj| obj.to_thumbprint_map }
579
+ else
580
+ return from(jwk).to_thumbprint_map
581
+ end
208
582
  end
209
583
 
584
+ # Converts a {JOSE::JWK JOSE::JWK} into a map that can be used by {JOSE::JWK.thumbprint JOSE::JWK.thumbprint}.
585
+ #
586
+ # @return [JOSE::Map]
210
587
  def to_thumbprint_map
211
588
  return kty.to_thumbprint_map(fields)
212
589
  end
213
590
 
214
591
  # API
215
592
 
593
+ # Decrypts the `encrypted` binary or map using the `jwk`.
594
+ #
595
+ # @see JOWE::JWE.block_decrypt
596
+ # @param [JOSE::JWK] jwk
597
+ # @param [JOSE::EncryptedBinary, JOSE::EncryptedMap] encrypted
598
+ # @return [[String, JOSE::JWE]]
216
599
  def self.block_decrypt(jwk, encrypted)
217
600
  return from(jwk).block_decrypt(encrypted)
218
601
  end
219
602
 
603
+ # Decrypts the `encrypted` binary or map using the `jwk`.
604
+ #
605
+ # @see JOWE::JWE.block_decrypt
606
+ # @param [JOSE::EncryptedBinary, JOSE::EncryptedMap] encrypted
607
+ # @return [[String, JOSE::JWE]]
220
608
  def block_decrypt(encrypted)
221
609
  return JOSE::JWE.block_decrypt(self, encrypted)
222
610
  end
223
611
 
612
+ # Encrypts the `plain_text` using the `jwk` and algorithms specified by the `jwe`.
613
+ #
614
+ # @see JOSE::JWE.block_encrypt
615
+ # @param [JOSE::JWK] jwk
616
+ # @param [String] plain_text
617
+ # @param [JOSE::JWE] jwe
618
+ # @return [JOSE::EncryptedMap]
224
619
  def self.block_encrypt(jwk, plain_text, jwe = nil)
225
620
  return from(jwk).block_encrypt(plain_text, jwe)
226
621
  end
227
622
 
623
+ # Encrypts the `plain_text` using the `jwk` and algorithms specified by the `jwe`.
624
+ #
625
+ # @see JOSE::JWE.block_encrypt
626
+ # @param [String] plain_text
627
+ # @param [JOSE::JWE] jwe
628
+ # @return [JOSE::EncryptedMap]
228
629
  def block_encrypt(plain_text, jwe = nil)
229
630
  jwe ||= block_encryptor
230
631
  return JOSE::JWE.block_encrypt(self, plain_text, jwe)
231
632
  end
232
633
 
233
- def self.block_encryptor(jwe)
234
- return from(jwe).block_encryptor
634
+ # Returns a block encryptor map for the key type.
635
+ #
636
+ # @param [JOSE::JWK, Array<JOSE::JWK>] jwk
637
+ # @return [JOSE::Map, Array<JOSE::Map>]
638
+ def self.block_encryptor(jwk)
639
+ if jwk.is_a?(Array)
640
+ return from(jwk).map { |obj| obj.block_encryptor }
641
+ else
642
+ return from(jwk).block_encryptor
643
+ end
235
644
  end
236
645
 
646
+ # Returns a block encryptor map for the key type.
647
+ #
648
+ # @return [JOSE::Map]
237
649
  def block_encryptor
238
650
  return kty.block_encryptor(fields)
239
651
  end
240
652
 
241
- def self.box_decrypt(jwk, encrypted)
242
- return from(jwk).box_decrypt(encrypted)
653
+ # Key Agreement decryption of the `encrypted` binary or map using `my_private_jwk`.
654
+ #
655
+ # @see JOSE::JWK.box_encrypt
656
+ # @see JOSE::JWE.block_decrypt
657
+ # @param [JOSE::JWK] jwk
658
+ # @param [JOSE::EncryptedBinary, JOSE::EncryptedMap] encrypted
659
+ # @param [JOSE::JWK] public_jwk
660
+ # @return [[String, JOSE::JWE]]
661
+ def self.box_decrypt(jwk, encrypted, public_jwk = nil)
662
+ return from(jwk).box_decrypt(encrypted, public_jwk)
243
663
  end
244
664
 
245
- def box_decrypt(encrypted)
246
- return JOSE::JWE.block_decrypt(self, encrypted)
665
+ # Key Agreement decryption of the `encrypted` binary or map using `my_private_jwk`.
666
+ #
667
+ # @see JOSE::JWK.box_encrypt
668
+ # @see JOSE::JWE.block_decrypt
669
+ # @param [JOSE::EncryptedBinary, JOSE::EncryptedMap] encrypted
670
+ # @param [JOSE::JWK] public_jwk
671
+ # @return [[String, JOSE::JWE]]
672
+ def box_decrypt(encrypted, public_jwk = nil)
673
+ if public_jwk
674
+ return JOSE::JWE.block_decrypt([public_jwk, self], encrypted)
675
+ else
676
+ return JOSE::JWE.block_decrypt(self, encrypted)
677
+ end
247
678
  end
248
679
 
249
- # Generates an ephemeral private key based on other public key curve.
680
+ # Key Agreement encryption of `plain_text` by generating an ephemeral private key based on `other_public_jwk` curve.
681
+ #
682
+ # If no private key has been specified in `box_keys`, it generates an ephemeral private key based on other public key curve.
683
+ #
684
+ # @see JOSE::JWK.box_decrypt
685
+ # @see JOSE::JWE.block_encrypt
686
+ # @param [String] plain_text
687
+ # @param [JOSE::JWK, [JOSE::JWK, JOSE::JWK]] box_keys
688
+ # @param [JOSE::JWE] jwe
689
+ # @return [JOSE::EncryptedMap, [JOSE::EncryptedMap, JOSE::JWK]]
690
+ def self.box_encrypt(plain_text, box_keys, jwe = nil)
691
+ other_public_key, my_private_key = box_keys
692
+ return from(other_public_key).box_encrypt(plain_text, my_private_jwk, jwe)
693
+ end
694
+
695
+ # Key Agreement encryption of `plain_text` by generating an ephemeral private key based on `other_public_jwk` curve.
696
+ #
697
+ # If no private key has been specified in `my_private_key`, it generates an ephemeral private key based on other public key curve.
698
+ #
699
+ # @see JOSE::JWK.box_decrypt
700
+ # @see JOSE::JWE.block_encrypt
701
+ # @param [String] plain_text
702
+ # @param [JOSE::JWK] my_private_jwk
703
+ # @param [JOSE::JWE] jwe
704
+ # @return [JOSE::EncryptedMap, [JOSE::EncryptedMap, JOSE::JWK]]
250
705
  def box_encrypt(plain_text, my_private_jwk = nil, jwe = nil)
251
706
  generated_jwk = nil
252
707
  other_public_jwk = self
@@ -280,10 +735,32 @@ module JOSE
280
735
  end
281
736
  end
282
737
 
738
+ # Derives a key (typically just returns a binary representation of the key).
739
+ #
740
+ # @param [*Object] args
741
+ # @return [String]
283
742
  def derive_key(*args)
284
743
  return kty.derive_key(*args)
285
744
  end
286
745
 
746
+ # Generates a new {JOSE::JWK JOSE::JWK} based on another {JOSE::JWK JOSE::JWK} or from initialization params provided.
747
+ #
748
+ # Passing another {JOSE::JWK JOSE::JWK} results in different behavior depending on the `"kty"`:
749
+ #
750
+ # * `"EC"` - uses the same named curve to generate a new key
751
+ # * `"oct"` - uses the byte size to generate a new key
752
+ # * `"OKP"` - uses the named curve to generate a new key
753
+ # * `"RSA"` - uses the same modulus and exponent sizes to generate a new key
754
+ #
755
+ # The following initialization params may also be used:
756
+ #
757
+ # * `[:ec, "P-256" | "P-384" | "P-521"]` - generates an `"EC"` key using the `"P-256"`, `"P-384"`, or `"P-521"` curves
758
+ # * `[:oct, bytes]` - generates an `"oct"` key made of a random `bytes` number of bytes
759
+ # * `[:okp, :Ed25519 | :Ed25519ph | :Ed448 | :Ed448ph | :X25519 | :X448]` - generates an `"OKP"` key using the specified curve
760
+ # * `[:rsa, modulus_size] | [:rsa, modulus_size, exponent_size]` - generates an `"RSA"` key using the `modulus_size` and `exponent_size`
761
+ #
762
+ # @param [Array] params
763
+ # @return [JOSE::JWK]
287
764
  def self.generate_key(params)
288
765
  if params.is_a?(Array) and (params.length == 2 or params.length == 3)
289
766
  case params[0]
@@ -322,14 +799,24 @@ module JOSE
322
799
  end
323
800
  end
324
801
 
802
+ # Generates a new key based on the current one.
803
+ #
804
+ # @return [JOSE::JWK]
325
805
  def generate_key
326
806
  return JOSE::JWK.new(nil, *kty.generate_key(fields))
327
807
  end
328
808
 
809
+ # Merges map on right into map on left.
810
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] left
811
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] right
812
+ # @return [JOSE::JWK]
329
813
  def self.merge(left, right)
330
814
  return from(left).merge(right)
331
815
  end
332
816
 
817
+ # Merges object into current map.
818
+ # @param [JOSE::Map, Hash, String, JOSE::JWK] object
819
+ # @return [JOSE::JWK]
333
820
  def merge(object)
334
821
  object = case object
335
822
  when JOSE::Map, Hash
@@ -344,10 +831,23 @@ module JOSE
344
831
  return JOSE::JWK.from_map(self.to_map.merge(object))
345
832
  end
346
833
 
834
+ # Computes the shared secret between two keys.
835
+ #
836
+ # Currently only works for `"EC"` keys and `"OKP"` keys with `"crv"` set to `"X25519"` or `"X448"`.
837
+ #
838
+ # @param [JOSE::JWK] your_jwk
839
+ # @param [JOSE::JWK] my_jwk
840
+ # @return [String]
347
841
  def self.shared_secret(your_jwk, my_jwk)
348
842
  return from(your_jwk).shared_secret(from(my_jwk))
349
843
  end
350
844
 
845
+ # Computes the shared secret between two keys.
846
+ #
847
+ # Currently only works for `"EC"` keys and `"OKP"` keys with `"crv"` set to `"X25519"` or `"X448"`.
848
+ #
849
+ # @param [JOSE::JWK] other_jwk
850
+ # @return [String]
351
851
  def shared_secret(other_jwk)
352
852
  other_jwk = from(other_jwk) if not other_jwk.is_a?(JOSE::JWK)
353
853
  raise ArgumentError, "key types must match" if other_jwk.kty.class != kty.class
@@ -355,54 +855,144 @@ module JOSE
355
855
  return kty.derive_key(other_jwk)
356
856
  end
357
857
 
858
+ # Signs the `plain_text` using the `jwk` and the default signer algorithm `jws` for the key type.
859
+ #
860
+ # @see JOSE::JWS.sign
861
+ # @param [JOSE::JWK] jwk
862
+ # @param [String] plain_text
863
+ # @param [JOSE::JWS] jws
864
+ # @param [JOSE::Map] header
865
+ # @return [JOSE::SignedMap]
358
866
  def self.sign(jwk, plain_text, jws = nil, header = nil)
359
867
  return from(jwk).sign(plain_text, jws, header)
360
868
  end
361
869
 
870
+ # Signs the `plain_text` using the `jwk` and the default signer algorithm `jws` for the key type.
871
+ #
872
+ # @see JOSE::JWS.sign
873
+ # @param [String] plain_text
874
+ # @param [JOSE::JWS] jws
875
+ # @param [JOSE::Map] header
876
+ # @return [JOSE::SignedMap]
362
877
  def sign(plain_text, jws = nil, header = nil)
363
878
  jws ||= signer
364
879
  return JOSE::JWS.sign(self, plain_text, jws, header)
365
880
  end
366
881
 
882
+ # Returns a signer map for the key type.
883
+ #
884
+ # @param [JOSE::JWK] jwk
885
+ # @return [JOSE::Map]
367
886
  def self.signer(jwk)
368
887
  return from(jwk).signer
369
888
  end
370
889
 
890
+ # Returns a signer map for the key type.
891
+ #
892
+ # @return [JOSE::Map]
371
893
  def signer
372
894
  return kty.signer(fields)
373
895
  end
374
896
 
897
+ # Returns the unique thumbprint for a {JOSE::JWK JOSE::JWK} using the `digest_type`.
898
+ #
899
+ # !!!ruby
900
+ # # let's define two different keys that will have the same thumbprint
901
+ # jwk1 = JOSE::JWK.from_oct("secret")
902
+ # jwk2 = JOSE::JWK.from({ "use" => "sig", "k" => "c2VjcmV0", "kty" => "oct" })
903
+ #
904
+ # JOSE::JWK.thumbprint(jwk1)
905
+ # # => "DWBh0SEIAPYh1x5uvot4z3AhaikHkxNJa3Ada2fT-Cg"
906
+ # JOSE::JWK.thumbprint(jwk2)
907
+ # # => "DWBh0SEIAPYh1x5uvot4z3AhaikHkxNJa3Ada2fT-Cg"
908
+ # JOSE::JWK.thumbprint('MD5', jwk1)
909
+ # # => "Kldz8k5PQm7y1E3aNBlMiA"
910
+ # JOSE::JWK.thumbprint('MD5', jwk2)
911
+ # # => "Kldz8k5PQm7y1E3aNBlMiA"
912
+ #
913
+ # @see https://tools.ietf.org/html/rfc7638 RFC 7638 - JSON Web Key (JWK) Thumbprint
914
+ # @param [String] digest_type
915
+ # @param [JOSE::JWK] jwk
916
+ # @return [String]
917
+ def self.thumbprint(digest_type, jwk = nil)
918
+ if jwk.nil?
919
+ jwk = digest_type
920
+ digest_type = nil
921
+ end
922
+ return from(jwk).thumbprint(digest_type)
923
+ end
924
+
925
+ # Returns the unique thumbprint for a {JOSE::JWK JOSE::JWK} using the `digest_type`.
926
+ #
927
+ # @see JOSE::JWK.thumbprint
928
+ # @see https://tools.ietf.org/html/rfc7638 RFC 7638 - JSON Web Key (JWK) Thumbprint
929
+ # @param [String] digest_type
930
+ # @return [String]
931
+ def thumbprint(digest_type = nil)
932
+ digest_type ||= 'SHA256'
933
+ thumbprint_binary = JOSE.encode(to_thumbprint_map)
934
+ return JOSE.urlsafe_encode64(OpenSSL::Digest.new(digest_type).digest(thumbprint_binary))
935
+ end
936
+
937
+ # Returns a verifier algorithm list for the key type.
938
+ #
939
+ # @param [JOSE::JWK] jwk
940
+ # @return [Array<String>]
941
+ def self.verifier(jwk)
942
+ if jwk.is_a?(Array)
943
+ return from(jwk).map { |obj| obj.verifier }
944
+ else
945
+ return from(jwk).verifier
946
+ end
947
+ end
948
+
949
+ # Returns a verifier algorithm list for the key type.
950
+ #
951
+ # @return [Array<String>]
952
+ def verifier
953
+ return kty.verifier(fields)
954
+ end
955
+
956
+ # Verifies the `signed` using the `jwk`.
957
+ #
958
+ # @see JOSE::JWS.verify
959
+ # @param [JOSE::SignedBinary, JOSE::SignedMap] signed
960
+ # @param [JOSE::JWK] jwk
961
+ # @return [[Boolean, String, JOSE::JWS]]
375
962
  def self.verify(signed, jwk)
376
963
  return from(jwk).verify(signed)
377
964
  end
378
965
 
966
+ # Verifies the `signed` using the `jwk`.
967
+ #
968
+ # @see JOSE::JWS.verify
969
+ # @param [JOSE::SignedBinary, JOSE::SignedMap] signed
970
+ # @return [[Boolean, String, JOSE::JWS]]
379
971
  def verify(signed)
380
972
  return JOSE::JWS.verify(self, signed)
381
973
  end
382
974
 
975
+ # Verifies the `signed` using the `jwk` and whitelists the `"alg"` using `allow`.
976
+ #
977
+ # @see JOSE::JWS.verify_strict
978
+ # @param [JOSE::SignedBinary, JOSE::SignedMap] signed
979
+ # @param [Array<String>] allow
980
+ # @param [JOSE::JWK] jwk
981
+ # @return [[Boolean, String, JOSE::JWS]]
383
982
  def self.verify_strict(signed, allow, jwk)
384
983
  return from(jwk).verify_strict(signed, allow)
385
984
  end
386
985
 
986
+ # Verifies the `signed` using the `jwk` and whitelists the `"alg"` using `allow`.
987
+ #
988
+ # @see JOSE::JWS.verify_strict
989
+ # @param [JOSE::SignedBinary, JOSE::SignedMap] signed
990
+ # @param [Array<String>] allow
991
+ # @return [[Boolean, String, JOSE::JWS]]
387
992
  def verify_strict(signed, allow)
388
993
  return JOSE::JWS.verify_strict(self, allow, signed)
389
994
  end
390
995
 
391
- # See https://tools.ietf.org/html/rfc7638
392
- def self.thumbprint(digest_type, jwk = nil)
393
- if jwk.nil?
394
- jwk = digest_type
395
- digest_type = nil
396
- end
397
- return from(jwk).thumbprint(digest_type)
398
- end
399
-
400
- def thumbprint(digest_type = nil)
401
- digest_type ||= 'SHA256'
402
- thumbprint_binary = JOSE.encode(to_thumbprint_map)
403
- return JOSE.urlsafe_encode64(OpenSSL::Digest.new(digest_type).digest(thumbprint_binary))
404
- end
405
-
406
996
  private
407
997
 
408
998
  def self.from_fields(jwk, modules)
@@ -451,5 +1041,6 @@ module JOSE
451
1041
  end
452
1042
 
453
1043
  require 'jose/jwk/pem'
1044
+ require 'jose/jwk/openssh_key'
454
1045
  require 'jose/jwk/set'
455
1046
  require 'jose/jwk/kty'