jose 0.2.0 → 0.3.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.
@@ -21,25 +21,15 @@ class JOSE::JWE::ALG_RSA < Struct.new(:rsa_padding, :rsa_oaep_md)
21
21
  end
22
22
 
23
23
  def to_map(fields)
24
- alg = nil
25
- if rsa_padding == :rsa_pkcs1_padding
26
- alg = 'RSA1_5'
27
- elsif rsa_padding == :rsa_pkcs1_oaep_padding
28
- if rsa_oaep_md == OpenSSL::Digest::SHA1
29
- alg = 'RSA-OAEP'
30
- elsif rsa_oaep_md == OpenSSL::Digest::SHA256
31
- alg = 'RSA-OAEP-256'
32
- else
33
- raise ArgumentError, "unhandled JOSE::JWE::ALG_RSA rsa_oaep_md: #{rsa_oaep_md.inspect}"
34
- end
35
- else
36
- raise ArgumentError, "unhandled JOSE::JWE::ALG_RSA rsa_padding: #{rsa_padding.inspect}"
37
- end
38
- return fields.put('alg', alg)
24
+ return fields.put('alg', algorithm)
39
25
  end
40
26
 
41
27
  # JOSE::JWE::ALG callbacks
42
28
 
29
+ def generate_key(fields, enc)
30
+ return JOSE::JWE::ALG.generate_key([:rsa, 2048], algorithm, enc.algorithm)
31
+ end
32
+
43
33
  def key_decrypt(key, enc, encrypted_key)
44
34
  if key.is_a?(JOSE::JWK)
45
35
  return key.kty.decrypt_private(encrypted_key, rsa_padding: rsa_padding, rsa_oaep_md: rsa_oaep_md)
@@ -60,4 +50,22 @@ class JOSE::JWE::ALG_RSA < Struct.new(:rsa_padding, :rsa_oaep_md)
60
50
  return enc.next_cek
61
51
  end
62
52
 
53
+ # API functions
54
+
55
+ def algorithm
56
+ if rsa_padding == :rsa_pkcs1_padding
57
+ 'RSA1_5'
58
+ elsif rsa_padding == :rsa_pkcs1_oaep_padding
59
+ if rsa_oaep_md == OpenSSL::Digest::SHA1
60
+ 'RSA-OAEP'
61
+ elsif rsa_oaep_md == OpenSSL::Digest::SHA256
62
+ 'RSA-OAEP-256'
63
+ else
64
+ raise ArgumentError, "unhandled JOSE::JWE::ALG_RSA rsa_oaep_md: #{rsa_oaep_md.inspect}"
65
+ end
66
+ else
67
+ raise ArgumentError, "unhandled JOSE::JWE::ALG_RSA rsa_padding: #{rsa_padding.inspect}"
68
+ end
69
+ end
70
+
63
71
  end
@@ -41,13 +41,14 @@ class JOSE::JWE::ENC_AES_CBC_HMAC < Struct.new(:cipher_name, :bits, :cek_len, :i
41
41
  enc_key = cek_s.read(enc_len)
42
42
  aad_len = [(aad.bytesize * 8)].pack('Q>')
43
43
  mac_data = [aad, iv, cipher_text, aad_len].pack('a*a*a*a*')
44
- if cipher_tag != OpenSSL::HMAC.digest(hmac.new, mac_key, mac_data)[0..tag_len]
44
+ if cipher_tag != OpenSSL::HMAC.digest(hmac.new, mac_key, mac_data)[0...tag_len]
45
45
  raise ArgumentError, "decryption error"
46
46
  else
47
47
  cipher = OpenSSL::Cipher.new(cipher_name)
48
48
  cipher.decrypt
49
- cipher.key = cek
49
+ cipher.key = enc_key
50
50
  cipher.iv = iv
51
+ cipher.padding = 0
51
52
  plain_text = JOSE::JWA::PKCS7.unpad(cipher.update(cipher_text) + cipher.final)
52
53
  return plain_text
53
54
  end
@@ -60,12 +61,13 @@ class JOSE::JWE::ENC_AES_CBC_HMAC < Struct.new(:cipher_name, :bits, :cek_len, :i
60
61
  enc_key = cek_s.read(enc_len)
61
62
  cipher = OpenSSL::Cipher.new(cipher_name)
62
63
  cipher.encrypt
63
- cipher.key = cek
64
+ cipher.key = enc_key
64
65
  cipher.iv = iv
66
+ cipher.padding = 0
65
67
  cipher_text = cipher.update(JOSE::JWA::PKCS7.pad(plain_text)) + cipher.final
66
68
  aad_len = [(aad.bytesize * 8)].pack('Q>')
67
69
  mac_data = [aad, iv, cipher_text, aad_len].pack('a*a*a*a*')
68
- cipher_tag = OpenSSL::HMAC.digest(hmac.new, mac_key, mac_data)[0..tag_len]
70
+ cipher_tag = OpenSSL::HMAC.digest(hmac.new, mac_key, mac_data)[0...tag_len]
69
71
  return cipher_text, cipher_tag
70
72
  end
71
73
 
@@ -40,6 +40,7 @@ class JOSE::JWE::ENC_AES_GCM < Struct.new(:cipher_name, :bits, :cek_len, :iv_len
40
40
  cipher.decrypt
41
41
  cipher.key = cek
42
42
  cipher.iv = iv
43
+ cipher.padding = 0
43
44
  cipher.auth_data = aad
44
45
  cipher.auth_tag = cipher_tag
45
46
  plain_text = cipher.update(cipher_text) + cipher.final
@@ -52,6 +53,7 @@ class JOSE::JWE::ENC_AES_GCM < Struct.new(:cipher_name, :bits, :cek_len, :iv_len
52
53
  cipher.encrypt
53
54
  cipher.key = cek
54
55
  cipher.iv = iv
56
+ cipher.padding = 0
55
57
  cipher.auth_data = aad
56
58
  cipher_text = cipher.update(plain_text) + cipher.final
57
59
  return cipher_text, cipher.auth_tag
@@ -226,10 +226,18 @@ module JOSE
226
226
  end
227
227
 
228
228
  def block_encrypt(plain_text, jwe = nil)
229
- jwe ||= kty.block_encryptor(fields, plain_text)
229
+ jwe ||= block_encryptor
230
230
  return JOSE::JWE.block_encrypt(self, plain_text, jwe)
231
231
  end
232
232
 
233
+ def self.block_encryptor(jwe)
234
+ return from(jwe).block_encryptor
235
+ end
236
+
237
+ def block_encryptor
238
+ return kty.block_encryptor(fields)
239
+ end
240
+
233
241
  def self.box_decrypt(jwk, encrypted)
234
242
  return from(jwk).box_decrypt(encrypted)
235
243
  end
@@ -249,7 +257,7 @@ module JOSE
249
257
  my_private_jwk = JOSE::JWK.from(my_private_jwk)
250
258
  end
251
259
  if jwe.nil?
252
- jwe = other_public_jwk.kty.block_encryptor(fields, plain_text)
260
+ jwe = other_public_jwk.block_encryptor
253
261
  end
254
262
  if jwe.is_a?(Hash)
255
263
  jwe = JOSE::Map.new(jwe)
@@ -318,6 +326,24 @@ module JOSE
318
326
  return JOSE::JWK.new(nil, *kty.generate_key(fields))
319
327
  end
320
328
 
329
+ def self.merge(left, right)
330
+ return from(left).merge(right)
331
+ end
332
+
333
+ def merge(object)
334
+ object = case object
335
+ when JOSE::Map, Hash
336
+ object
337
+ when String
338
+ JOSE.decode(object)
339
+ when JOSE::JWK
340
+ object.to_map
341
+ else
342
+ raise ArgumentError, "'object' must be a Hash, String, or JOSE::JWK"
343
+ end
344
+ return JOSE::JWK.from_map(self.to_map.merge(object))
345
+ end
346
+
321
347
  def self.shared_secret(your_jwk, my_jwk)
322
348
  return from(your_jwk).shared_secret(from(my_jwk))
323
349
  end
@@ -334,10 +360,18 @@ module JOSE
334
360
  end
335
361
 
336
362
  def sign(plain_text, jws = nil, header = nil)
337
- jws ||= kty.signer(fields, plain_text)
363
+ jws ||= signer
338
364
  return JOSE::JWS.sign(self, plain_text, jws, header)
339
365
  end
340
366
 
367
+ def self.signer(jwk)
368
+ return from(jwk).signer
369
+ end
370
+
371
+ def signer
372
+ return kty.signer(fields)
373
+ end
374
+
341
375
  def self.verify(signed, jwk)
342
376
  return from(jwk).verify(signed)
343
377
  end
@@ -82,11 +82,28 @@ class JOSE::JWK::KTY_EC < Struct.new(:key)
82
82
 
83
83
  # JOSE::JWK::KTY callbacks
84
84
 
85
- def block_encryptor(fields, plain_text)
86
- return JOSE::Map[
87
- 'alg' => 'ECDH-ES',
88
- 'enc' => 'A128GCM'
89
- ]
85
+ def block_encryptor(fields)
86
+ if fields and fields['use'] == 'enc' and not fields['alg'].nil? and not fields['enc'].nil?
87
+ jwe = JOSE::Map[
88
+ 'alg' => fields['alg'],
89
+ 'enc' => fields['enc']
90
+ ]
91
+ if not fields['apu'].nil?
92
+ jwe = jwe.put('apu', fields['apu'])
93
+ end
94
+ if not fields['apv'].nil?
95
+ jwe = jwe.put('apv', fields['apv'])
96
+ end
97
+ if not fields['epk'].nil?
98
+ jwe = jwe.put('epk', fields['epk'])
99
+ end
100
+ return jwe
101
+ else
102
+ return JOSE::Map[
103
+ 'alg' => 'ECDH-ES',
104
+ 'enc' => 'A128GCM'
105
+ ]
106
+ end
90
107
  end
91
108
 
92
109
  def derive_key(my_private_key)
@@ -104,6 +121,16 @@ class JOSE::JWK::KTY_EC < Struct.new(:key)
104
121
  if curve_name.is_a?(Array) and curve_name.length == 2 and curve_name[0] == :ec
105
122
  curve_name = curve_name[1]
106
123
  end
124
+ curve_name = case curve_name
125
+ when 'P-256'
126
+ 'prime256v1'
127
+ when 'P-384'
128
+ 'secp384r1'
129
+ when 'P-521'
130
+ 'secp521r1'
131
+ else
132
+ curve_name
133
+ end
107
134
  if curve_name.is_a?(String)
108
135
  return from_key(OpenSSL::PKey::EC.new(curve_name).generate_key)
109
136
  else
@@ -131,9 +158,21 @@ class JOSE::JWK::KTY_EC < Struct.new(:key)
131
158
  return rpad.concat(spad)
132
159
  end
133
160
 
134
- def signer(fields = nil, plain_text = nil)
135
- if key.private_key?
136
- return JOSE::Map['alg' => 'ES256']
161
+ def signer(fields = nil)
162
+ if key.private_key? and fields and fields['use'] == 'sig' and not fields['alg'].nil?
163
+ return JOSE::Map['alg' => fields['alg']]
164
+ elsif key.private_key?
165
+ alg = case key.group.curve_name
166
+ when 'prime256v1', 'secp256r1'
167
+ 'ES256'
168
+ when 'secp384r1'
169
+ 'ES384'
170
+ when 'secp521r1'
171
+ 'ES512'
172
+ else
173
+ raise ArgumentError, "unhandled EC curve name: #{key.group.curve_name.inspect}"
174
+ end
175
+ return JOSE::Map['alg' => alg]
137
176
  else
138
177
  raise ArgumentError, "signing not supported for public keys"
139
178
  end
@@ -28,25 +28,39 @@ class JOSE::JWK::KTY_oct < Struct.new(:oct)
28
28
 
29
29
  # JOSE::JWK::KTY callbacks
30
30
 
31
- def block_encryptor(fields, plain_text)
32
- enc = case (oct.bytesize * 8)
33
- when 128
34
- 'A128GCM'
35
- when 192
36
- 'A192GCM'
37
- when 256
38
- 'A256GCM'
39
- when 384
40
- 'A192CBC-HS384'
41
- when 512
42
- 'A256CBC-HS512'
31
+ def block_encryptor(fields)
32
+ if fields and fields['use'] == 'enc' and not fields['alg'].nil? and not fields['enc'].nil?
33
+ jwe = JOSE::Map[
34
+ 'alg' => fields['alg'],
35
+ 'enc' => fields['enc']
36
+ ]
37
+ if not fields['p2c'].nil?
38
+ jwe = jwe.put('p2c', fields['p2c'])
39
+ end
40
+ if not fields['p2s'].nil?
41
+ jwe = jwe.put('p2s', fields['p2s'])
42
+ end
43
+ return jwe
43
44
  else
44
- raise ArgumentError, "oct of size #{oct.bytesize * 8} has no default block encryptor"
45
+ enc = case (oct.bytesize * 8)
46
+ when 128
47
+ 'A128GCM'
48
+ when 192
49
+ 'A192GCM'
50
+ when 256
51
+ 'A256GCM'
52
+ when 384
53
+ 'A192CBC-HS384'
54
+ when 512
55
+ 'A256CBC-HS512'
56
+ else
57
+ raise ArgumentError, "oct of size #{oct.bytesize * 8} has no default block encryptor"
58
+ end
59
+ return JOSE::Map[
60
+ 'alg' => 'dir',
61
+ 'enc' => enc
62
+ ]
45
63
  end
46
- return JOSE::Map[
47
- 'alg' => 'dir',
48
- 'enc' => enc
49
- ]
50
64
  end
51
65
 
52
66
  def derive_key
@@ -78,8 +92,20 @@ class JOSE::JWK::KTY_oct < Struct.new(:oct)
78
92
  return OpenSSL::HMAC.digest(digest_type.new, oct, message)
79
93
  end
80
94
 
81
- def signer(fields = nil, plain_text = nil)
82
- return JOSE::Map['alg' => 'HS256']
95
+ def signer(fields = nil)
96
+ if fields and fields['use'] == 'sig' and not fields['alg'].nil?
97
+ return JOSE::Map['alg' => fields['alg']]
98
+ else
99
+ bitsize = (oct.bytesize * 8)
100
+ alg = if bitsize < 384
101
+ 'HS256'
102
+ elsif bitsize < 512
103
+ 'HS384'
104
+ else
105
+ 'HS512'
106
+ end
107
+ return JOSE::Map['alg' => alg]
108
+ end
83
109
  end
84
110
 
85
111
  def verify(message, digest_type, signature)
@@ -84,8 +84,14 @@ class JOSE::JWK::KTY_OKP_Ed25519 < Struct.new(:okp)
84
84
  return JOSE::JWA::Curve25519.ed25519_sign(message, okp)
85
85
  end
86
86
 
87
- def signer(fields = nil, plain_text = nil)
88
- return JOSE::Map['alg' => 'Ed25519']
87
+ def signer(fields = nil)
88
+ if okp.bytesize == SK_BYTES and fields and fields['use'] == 'sig' and not fields['alg'].nil?
89
+ return JOSE::Map['alg' => fields['alg']]
90
+ elsif okp.bytesize == SK_BYTES
91
+ return JOSE::Map['alg' => 'Ed25519']
92
+ else
93
+ raise ArgumentError, "signing not supported for public keys"
94
+ end
89
95
  end
90
96
 
91
97
  def verify(message, digest_type, signature)
@@ -84,8 +84,14 @@ class JOSE::JWK::KTY_OKP_Ed25519ph < Struct.new(:okp)
84
84
  return JOSE::JWA::Curve25519.ed25519ph_sign(message, okp)
85
85
  end
86
86
 
87
- def signer(fields = nil, plain_text = nil)
88
- return JOSE::Map['alg' => 'Ed25519ph']
87
+ def signer(fields = nil)
88
+ if okp.bytesize == SK_BYTES and fields and fields['use'] == 'sig' and not fields['alg'].nil?
89
+ return JOSE::Map['alg' => fields['alg']]
90
+ elsif okp.bytesize == SK_BYTES
91
+ return JOSE::Map['alg' => 'Ed25519ph']
92
+ else
93
+ raise ArgumentError, "signing not supported for public keys"
94
+ end
89
95
  end
90
96
 
91
97
  def verify(message, sign_type, signature)
@@ -93,8 +93,14 @@ class JOSE::JWK::KTY_OKP_Ed448 < Struct.new(:okp)
93
93
  return JOSE::JWA::Curve448.ed448_sign(message, okp)
94
94
  end
95
95
 
96
- def signer(fields = nil, plain_text = nil)
97
- return JOSE::Map['alg' => 'Ed448']
96
+ def signer(fields = nil)
97
+ if (okp.bytesize == SK_BYTES or okp.bytesize == LEGACY_SK_BYTES) and fields and fields['use'] == 'sig' and not fields['alg'].nil?
98
+ return JOSE::Map['alg' => fields['alg']]
99
+ elsif (okp.bytesize == SK_BYTES or okp.bytesize == LEGACY_SK_BYTES)
100
+ return JOSE::Map['alg' => 'Ed448']
101
+ else
102
+ raise ArgumentError, "signing not supported for public keys"
103
+ end
98
104
  end
99
105
 
100
106
  def verify(message, digest_type, signature)
@@ -93,8 +93,14 @@ class JOSE::JWK::KTY_OKP_Ed448ph < Struct.new(:okp)
93
93
  return JOSE::JWA::Curve448.ed448ph_sign(message, okp)
94
94
  end
95
95
 
96
- def signer(fields = nil, plain_text = nil)
97
- return JOSE::Map['alg' => 'Ed448ph']
96
+ def signer(fields = nil)
97
+ if (okp.bytesize == SK_BYTES or okp.bytesize == LEGACY_SK_BYTES) and fields and fields['use'] == 'sig' and not fields['alg'].nil?
98
+ return JOSE::Map['alg' => fields['alg']]
99
+ elsif (okp.bytesize == SK_BYTES or okp.bytesize == LEGACY_SK_BYTES)
100
+ return JOSE::Map['alg' => 'Ed448ph']
101
+ else
102
+ raise ArgumentError, "signing not supported for public keys"
103
+ end
98
104
  end
99
105
 
100
106
  def verify(message, digest_type, signature)
@@ -55,11 +55,28 @@ class JOSE::JWK::KTY_OKP_X25519 < Struct.new(:okp)
55
55
 
56
56
  # JOSE::JWK::KTY callbacks
57
57
 
58
- def block_encryptor(fields, plain_text)
59
- return JOSE::Map[
60
- 'alg' => 'ECDH-ES',
61
- 'enc' => 'A128GCM'
62
- ]
58
+ def block_encryptor(fields)
59
+ if fields and fields['use'] == 'enc' and not fields['alg'].nil? and not fields['enc'].nil?
60
+ jwe = JOSE::Map[
61
+ 'alg' => fields['alg'],
62
+ 'enc' => fields['enc']
63
+ ]
64
+ if not fields['apu'].nil?
65
+ jwe = jwe.put('apu', fields['apu'])
66
+ end
67
+ if not fields['apv'].nil?
68
+ jwe = jwe.put('apv', fields['apv'])
69
+ end
70
+ if not fields['epk'].nil?
71
+ jwe = jwe.put('epk', fields['epk'])
72
+ end
73
+ return jwe
74
+ else
75
+ return JOSE::Map[
76
+ 'alg' => 'ECDH-ES',
77
+ 'enc' => 'A128GCM'
78
+ ]
79
+ end
63
80
  end
64
81
 
65
82
  def derive_key(my_sk)
@@ -55,11 +55,28 @@ class JOSE::JWK::KTY_OKP_X448 < Struct.new(:okp)
55
55
 
56
56
  # JOSE::JWK::KTY callbacks
57
57
 
58
- def block_encryptor(fields, plain_text)
59
- return JOSE::Map[
60
- 'alg' => 'ECDH-ES',
61
- 'enc' => 'A128GCM'
62
- ]
58
+ def block_encryptor(fields)
59
+ if fields and fields['use'] == 'enc' and not fields['alg'].nil? and not fields['enc'].nil?
60
+ jwe = JOSE::Map[
61
+ 'alg' => fields['alg'],
62
+ 'enc' => fields['enc']
63
+ ]
64
+ if not fields['apu'].nil?
65
+ jwe = jwe.put('apu', fields['apu'])
66
+ end
67
+ if not fields['apv'].nil?
68
+ jwe = jwe.put('apv', fields['apv'])
69
+ end
70
+ if not fields['epk'].nil?
71
+ jwe = jwe.put('epk', fields['epk'])
72
+ end
73
+ return jwe
74
+ else
75
+ return JOSE::Map[
76
+ 'alg' => 'ECDH-ES',
77
+ 'enc' => 'A128GCM'
78
+ ]
79
+ end
63
80
  end
64
81
 
65
82
  def derive_key(my_sk)