jose 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)