jose 1.1.3 → 1.2.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.
@@ -0,0 +1,35 @@
1
+ module JOSE::JWA::XChaCha20Poly1305_RbNaCl
2
+
3
+ extend self
4
+
5
+ def __ruby__?; false; end
6
+
7
+ def __supported__?
8
+ return @supported ||= begin
9
+ begin
10
+ require 'rbnacl/libsodium'
11
+ rescue LoadError
12
+ end
13
+ begin
14
+ require 'rbnacl'
15
+ rescue LoadError
16
+ end
17
+ !!(defined?(RbNaCl::AEAD::XChaCha20Poly1305IETF))
18
+ end
19
+ end
20
+
21
+ def xchacha20poly1305_aead_encrypt(key, nonce, aad, plaintext)
22
+ cipher = RbNaCl::AEAD::XChaCha20Poly1305IETF.new(key)
23
+ ciphertext_with_tag = cipher.encrypt(nonce, plaintext, aad)
24
+ return [ciphertext_with_tag[0..-17], ciphertext_with_tag[-16..-1]]
25
+ end
26
+
27
+ def xchacha20poly1305_aead_decrypt(key, nonce, aad, ciphertext, tag)
28
+ cipher = RbNaCl::AEAD::XChaCha20Poly1305IETF.new(key)
29
+ ciphertext_with_tag = [ciphertext, tag].join()
30
+ return cipher.decrypt(nonce, ciphertext_with_tag, aad)
31
+ end
32
+
33
+ end
34
+
35
+ JOSE::JWA::XChaCha20Poly1305.__register__(JOSE::JWA::XChaCha20Poly1305_RbNaCl)
@@ -0,0 +1,16 @@
1
+ module JOSE::JWA::XChaCha20Poly1305_Unsupported
2
+
3
+ extend self
4
+
5
+ def __ruby__?; true; end
6
+ def __supported__?; false; end
7
+
8
+ def xchacha20poly1305_aead_encrypt(key, nonce, aad, plaintext)
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def xchacha20poly1305_aead_decrypt(key, nonce, aad, ciphertext, tag)
13
+ raise NotImplementedError
14
+ end
15
+
16
+ end
data/lib/jose/jwa.rb CHANGED
@@ -127,7 +127,9 @@ module JOSE
127
127
  'A256GCM',
128
128
  'A128CBC-HS256',
129
129
  'A192CBC-HS384',
130
- 'A256CBC-HS512'
130
+ 'A256CBC-HS512',
131
+ 'C20P',
132
+ 'XC20P'
131
133
  ])
132
134
  jwe_alg = __jwe_alg_support_check__([
133
135
  ['A128GCMKW', :block],
@@ -136,6 +138,7 @@ module JOSE
136
138
  ['A128KW', :block],
137
139
  ['A192KW', :block],
138
140
  ['A256KW', :block],
141
+ ['C20PKW', :block],
139
142
  ['ECDH-ES', :box],
140
143
  ['ECDH-ES+A128KW', :box],
141
144
  ['ECDH-ES+A192KW', :box],
@@ -146,6 +149,7 @@ module JOSE
146
149
  ['RSA1_5', :rsa],
147
150
  ['RSA-OAEP', :rsa],
148
151
  ['RSA-OAEP-256', :rsa],
152
+ ['XC20PKW', :block],
149
153
  ['dir', :direct]
150
154
  ], jwe_enc)
151
155
  jwe_zip = __jwe_zip_support_check__([
@@ -231,7 +235,7 @@ module JOSE
231
235
  cipher_text = recv_jwk.box_encrypt(plain_text, send_jwk).compact
232
236
  next recv_jwk.box_decrypt(cipher_text).first == plain_text
233
237
  elsif strategy == :rsa
234
- rsa ||= JOSE::JWK.generate_key([:rsa, 1024])
238
+ rsa ||= JOSE::JWK.generate_key([:rsa, 2048])
235
239
  cipher_text = rsa.block_encrypt(plain_text, { 'alg' => alg, 'enc' => enc }).compact
236
240
  next rsa.block_decrypt(cipher_text).first == plain_text
237
241
  elsif strategy == :direct
@@ -290,7 +294,7 @@ module JOSE
290
294
  kty.push(key_type) if not kty_OKP_crv.empty?
291
295
  when 'RSA'
292
296
  begin
293
- JOSE::JWK.generate_key([:rsa, 256])
297
+ JOSE::JWK.generate_key([:rsa, 1024])
294
298
  kty.push(key_type)
295
299
  rescue StandardError, NotImplementedError
296
300
  # do nothing
@@ -314,7 +318,7 @@ module JOSE
314
318
  begin
315
319
  jwk = nil
316
320
  jwk ||= JOSE::JWK.generate_key([:oct, 0]).merge({ 'alg' => alg, 'use' => 'sig' }) if alg == 'none'
317
- jwk ||= (rsa ||= JOSE::JWK.generate_key([:rsa, 1024])).merge({ 'alg' => alg, 'use' => 'sig' }) if alg.start_with?('RS') or alg.start_with?('PS')
321
+ jwk ||= (rsa ||= JOSE::JWK.generate_key([:rsa, 2048])).merge({ 'alg' => alg, 'use' => 'sig' }) if alg.start_with?('RS') or alg.start_with?('PS')
318
322
  jwk ||= JOSE::JWS.generate_key({ 'alg' => alg })
319
323
  signed_text = jwk.sign(plain_text).compact
320
324
  next jwk.verify_strict(signed_text, [alg]).first
@@ -337,3 +341,4 @@ require 'jose/jwa/curve25519'
337
341
  require 'jose/jwa/curve448'
338
342
  require 'jose/jwa/pkcs1'
339
343
  require 'jose/jwa/pkcs7'
344
+ require 'jose/jwa/xchacha20poly1305'
data/lib/jose/jwe/alg.rb CHANGED
@@ -19,7 +19,9 @@ end
19
19
 
20
20
  require 'jose/jwe/alg_aes_gcm_kw'
21
21
  require 'jose/jwe/alg_aes_kw'
22
+ require 'jose/jwe/alg_c20p_kw'
22
23
  require 'jose/jwe/alg_dir'
23
24
  require 'jose/jwe/alg_ecdh_es'
24
25
  require 'jose/jwe/alg_pbes2'
25
26
  require 'jose/jwe/alg_rsa'
27
+ require 'jose/jwe/alg_xc20p_kw'
@@ -103,7 +103,7 @@ class JOSE::JWE::ALG_AES_GCM_KW < Struct.new(:cipher_name, :bits, :iv, :tag)
103
103
  when 256
104
104
  'A256GCMKW'
105
105
  else
106
- raise ArgumentError, "unhandled JOSE::JWE::ALG_AES_KW bits: #{bits.inspect}"
106
+ raise ArgumentError, "unhandled JOSE::JWE::ALG_AES_GCM_KW bits: #{bits.inspect}"
107
107
  end
108
108
  end
109
109
 
@@ -0,0 +1,100 @@
1
+ class JOSE::JWE::ALG_C20P_KW < Struct.new(:cipher_name, :bits, :iv, :tag)
2
+
3
+ # JOSE::JWE callbacks
4
+
5
+ def self.from_map(fields)
6
+ bits = nil
7
+ cipher_name = nil
8
+ case fields['alg']
9
+ when 'C20PKW'
10
+ bits = 256
11
+ cipher_name = 'chacha20-poly1305'
12
+ else
13
+ raise ArgumentError, "invalid 'alg' for JWE: #{fields['alg'].inspect}"
14
+ end
15
+ iv = nil
16
+ if fields.has_key?('iv')
17
+ iv = JOSE.urlsafe_decode64(fields['iv'])
18
+ end
19
+ tag = nil
20
+ if fields.has_key?('tag')
21
+ tag = JOSE.urlsafe_decode64(fields['tag'])
22
+ end
23
+ return new(cipher_name, bits, iv, tag), fields.except('alg', 'iv', 'tag')
24
+ end
25
+
26
+ def to_map(fields)
27
+ alg = algorithm
28
+ fields = fields.put('alg', alg)
29
+ if iv
30
+ fields = fields.put('iv', JOSE.urlsafe_encode64(iv))
31
+ end
32
+ if tag
33
+ fields = fields.put('tag', JOSE.urlsafe_encode64(tag))
34
+ end
35
+ return fields
36
+ end
37
+
38
+ # JOSE::JWE::ALG callbacks
39
+
40
+ def generate_key(fields, enc)
41
+ return JOSE::JWE::ALG.generate_key([:oct, bits.div(8)], algorithm, enc.algorithm)
42
+ end
43
+
44
+ def key_decrypt(key, enc, encrypted_key)
45
+ if iv.nil? or tag.nil?
46
+ raise ArgumentError, "missing required fields for decryption: 'iv' and 'tag'"
47
+ end
48
+ if key.is_a?(JOSE::JWK)
49
+ key = key.kty.derive_key
50
+ end
51
+ derived_key = key
52
+ aad = ''
53
+ cipher_text = encrypted_key
54
+ cipher_tag = tag
55
+ cipher = OpenSSL::Cipher.new(cipher_name)
56
+ cipher.decrypt
57
+ cipher.key = derived_key
58
+ cipher.iv = iv
59
+ cipher.padding = 0
60
+ cipher.auth_data = aad
61
+ cipher.auth_tag = cipher_tag
62
+ plain_text = cipher.update(cipher_text) + cipher.final
63
+ return plain_text
64
+ end
65
+
66
+ def key_encrypt(key, enc, decrypted_key)
67
+ if key.is_a?(JOSE::JWK)
68
+ key = key.kty.derive_key
69
+ end
70
+ new_alg = JOSE::JWE::ALG_C20P_KW.new(cipher_name, bits, iv || SecureRandom.random_bytes(12))
71
+ derived_key = key
72
+ aad = ''
73
+ plain_text = decrypted_key
74
+ cipher = OpenSSL::Cipher.new(new_alg.cipher_name)
75
+ cipher.encrypt
76
+ cipher.key = derived_key
77
+ cipher.iv = new_alg.iv
78
+ cipher.padding = 0
79
+ cipher.auth_data = aad
80
+ cipher_text = cipher.update(plain_text) + cipher.final
81
+ new_alg.tag = cipher.auth_tag
82
+ return cipher_text, new_alg
83
+ end
84
+
85
+ def next_cek(key, enc)
86
+ return enc.next_cek, self
87
+ end
88
+
89
+ # API functions
90
+
91
+ def algorithm
92
+ case bits
93
+ when 256
94
+ 'C20PKW'
95
+ else
96
+ raise ArgumentError, "unhandled JOSE::JWE::ALG_C20P_KW bits: #{bits.inspect}"
97
+ end
98
+ end
99
+
100
+ end
@@ -0,0 +1,86 @@
1
+ class JOSE::JWE::ALG_XC20P_KW < Struct.new(:cipher_name, :bits, :iv, :tag)
2
+
3
+ # JOSE::JWE callbacks
4
+
5
+ def self.from_map(fields)
6
+ bits = nil
7
+ cipher_name = nil
8
+ case fields['alg']
9
+ when 'XC20PKW'
10
+ bits = 256
11
+ cipher_name = 'xchacha20-poly1305'
12
+ else
13
+ raise ArgumentError, "invalid 'alg' for JWE: #{fields['alg'].inspect}"
14
+ end
15
+ iv = nil
16
+ if fields.has_key?('iv')
17
+ iv = JOSE.urlsafe_decode64(fields['iv'])
18
+ end
19
+ tag = nil
20
+ if fields.has_key?('tag')
21
+ tag = JOSE.urlsafe_decode64(fields['tag'])
22
+ end
23
+ return new(cipher_name, bits, iv, tag), fields.except('alg', 'iv', 'tag')
24
+ end
25
+
26
+ def to_map(fields)
27
+ alg = algorithm
28
+ fields = fields.put('alg', alg)
29
+ if iv
30
+ fields = fields.put('iv', JOSE.urlsafe_encode64(iv))
31
+ end
32
+ if tag
33
+ fields = fields.put('tag', JOSE.urlsafe_encode64(tag))
34
+ end
35
+ return fields
36
+ end
37
+
38
+ # JOSE::JWE::ALG callbacks
39
+
40
+ def generate_key(fields, enc)
41
+ return JOSE::JWE::ALG.generate_key([:oct, bits.div(8)], algorithm, enc.algorithm)
42
+ end
43
+
44
+ def key_decrypt(key, enc, encrypted_key)
45
+ if iv.nil? or tag.nil?
46
+ raise ArgumentError, "missing required fields for decryption: 'iv' and 'tag'"
47
+ end
48
+ if key.is_a?(JOSE::JWK)
49
+ key = key.kty.derive_key
50
+ end
51
+ derived_key = key
52
+ aad = ''
53
+ cipher_text = encrypted_key
54
+ cipher_tag = tag
55
+ plain_text = JOSE.xchacha20poly1305_module().xchacha20poly1305_aead_decrypt(derived_key, iv, aad, cipher_text, cipher_tag)
56
+ return plain_text
57
+ end
58
+
59
+ def key_encrypt(key, enc, decrypted_key)
60
+ if key.is_a?(JOSE::JWK)
61
+ key = key.kty.derive_key
62
+ end
63
+ new_alg = JOSE::JWE::ALG_XC20P_KW.new(cipher_name, bits, iv || SecureRandom.random_bytes(24))
64
+ derived_key = key
65
+ aad = ''
66
+ plain_text = decrypted_key
67
+ cipher_text, new_alg.tag = JOSE.xchacha20poly1305_module().xchacha20poly1305_aead_encrypt(key, new_alg.iv, aad, plain_text)
68
+ return cipher_text, new_alg
69
+ end
70
+
71
+ def next_cek(key, enc)
72
+ return enc.next_cek, self
73
+ end
74
+
75
+ # API functions
76
+
77
+ def algorithm
78
+ case bits
79
+ when 256
80
+ 'XC20PKW'
81
+ else
82
+ raise ArgumentError, "unhandled JOSE::JWE::ALG_XC20P_KW bits: #{bits.inspect}"
83
+ end
84
+ end
85
+
86
+ end
data/lib/jose/jwe/enc.rb CHANGED
@@ -6,3 +6,5 @@ end
6
6
 
7
7
  require 'jose/jwe/enc_aes_cbc_hmac'
8
8
  require 'jose/jwe/enc_aes_gcm'
9
+ require 'jose/jwe/enc_c20p'
10
+ require 'jose/jwe/enc_xc20p'
@@ -0,0 +1,62 @@
1
+ class JOSE::JWE::ENC_C20P < Struct.new(:cipher_name, :bits, :cek_len, :iv_len)
2
+
3
+ # JOSE::JWE callbacks
4
+
5
+ def self.from_map(fields)
6
+ case fields['enc']
7
+ when 'C20P'
8
+ return new('chacha20-poly1305', 256, 32, 12), fields.delete('enc')
9
+ else
10
+ raise ArgumentError, "invalid 'enc' for JWE: #{fields['enc'].inspect}"
11
+ end
12
+ end
13
+
14
+ def to_map(fields)
15
+ return fields.put('enc', algorithm)
16
+ end
17
+
18
+ # JOSE::JWE::ENC callbacks
19
+
20
+ def algorithm
21
+ case cipher_name
22
+ when 'chacha20-poly1305'
23
+ return 'C20P'
24
+ else
25
+ raise ArgumentError, "unhandled JOSE::JWE::ENC_C20P cipher name: #{cipher_name.inspect}"
26
+ end
27
+ end
28
+
29
+ def block_decrypt(aad_cipher_text_cipher_tag, cek, iv)
30
+ aad, cipher_text, cipher_tag = aad_cipher_text_cipher_tag
31
+ cipher = OpenSSL::Cipher.new(cipher_name)
32
+ cipher.decrypt
33
+ cipher.key = cek
34
+ cipher.iv = iv
35
+ cipher.padding = 0
36
+ cipher.auth_data = aad
37
+ cipher.auth_tag = cipher_tag
38
+ plain_text = cipher.update(cipher_text) + cipher.final
39
+ return plain_text
40
+ end
41
+
42
+ def block_encrypt(aad_plain_text, cek, iv)
43
+ aad, plain_text = aad_plain_text
44
+ cipher = OpenSSL::Cipher.new(cipher_name)
45
+ cipher.encrypt
46
+ cipher.key = cek
47
+ cipher.iv = iv
48
+ cipher.padding = 0
49
+ cipher.auth_data = aad
50
+ cipher_text = cipher.update(plain_text) + cipher.final
51
+ return cipher_text, cipher.auth_tag
52
+ end
53
+
54
+ def next_cek
55
+ return SecureRandom.random_bytes(cek_len)
56
+ end
57
+
58
+ def next_iv
59
+ return SecureRandom.random_bytes(iv_len)
60
+ end
61
+
62
+ end
@@ -0,0 +1,49 @@
1
+ class JOSE::JWE::ENC_XC20P < Struct.new(:cipher_name, :bits, :cek_len, :iv_len)
2
+
3
+ # JOSE::JWE callbacks
4
+
5
+ def self.from_map(fields)
6
+ case fields['enc']
7
+ when 'XC20P'
8
+ return new('xchacha20-poly1305', 256, 32, 24), fields.delete('enc')
9
+ else
10
+ raise ArgumentError, "invalid 'enc' for JWE: #{fields['enc'].inspect}"
11
+ end
12
+ end
13
+
14
+ def to_map(fields)
15
+ return fields.put('enc', algorithm)
16
+ end
17
+
18
+ # JOSE::JWE::ENC callbacks
19
+
20
+ def algorithm
21
+ case cipher_name
22
+ when 'xchacha20-poly1305'
23
+ return 'XC20P'
24
+ else
25
+ raise ArgumentError, "unhandled JOSE::JWE::ENC_XC20P cipher name: #{cipher_name.inspect}"
26
+ end
27
+ end
28
+
29
+ def block_decrypt(aad_cipher_text_cipher_tag, cek, iv)
30
+ aad, cipher_text, cipher_tag = aad_cipher_text_cipher_tag
31
+ plain_text = JOSE.xchacha20poly1305_module().xchacha20poly1305_aead_decrypt(cek, iv, aad, cipher_text, cipher_tag)
32
+ return plain_text
33
+ end
34
+
35
+ def block_encrypt(aad_plain_text, cek, iv)
36
+ aad, plain_text = aad_plain_text
37
+ cipher_text, cipher_tag = JOSE.xchacha20poly1305_module().xchacha20poly1305_aead_encrypt(cek, iv, aad, plain_text)
38
+ return cipher_text, cipher_tag
39
+ end
40
+
41
+ def next_cek
42
+ return SecureRandom.random_bytes(cek_len)
43
+ end
44
+
45
+ def next_iv
46
+ return SecureRandom.random_bytes(iv_len)
47
+ end
48
+
49
+ end
data/lib/jose/jwe.rb CHANGED
@@ -1076,6 +1076,8 @@ module JOSE
1076
1076
  JOSE::JWE::ALG_AES_KW
1077
1077
  when 'A128GCMKW', 'A192GCMKW', 'A256GCMKW'
1078
1078
  JOSE::JWE::ALG_AES_GCM_KW
1079
+ when 'C20PKW'
1080
+ JOSE::JWE::ALG_C20P_KW
1079
1081
  when 'dir'
1080
1082
  JOSE::JWE::ALG_dir
1081
1083
  when 'ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW'
@@ -1084,6 +1086,8 @@ module JOSE
1084
1086
  JOSE::JWE::ALG_PBES2
1085
1087
  when 'RSA1_5', 'RSA-OAEP', 'RSA-OAEP-256'
1086
1088
  JOSE::JWE::ALG_RSA
1089
+ when 'XC20PKW'
1090
+ JOSE::JWE::ALG_XC20P_KW
1087
1091
  else
1088
1092
  raise ArgumentError, "unknown 'alg': #{jwe.fields['alg'].inspect}"
1089
1093
  end
@@ -1095,6 +1099,10 @@ module JOSE
1095
1099
  JOSE::JWE::ENC_AES_CBC_HMAC
1096
1100
  when 'A128GCM', 'A192GCM', 'A256GCM'
1097
1101
  JOSE::JWE::ENC_AES_GCM
1102
+ when 'C20P'
1103
+ JOSE::JWE::ENC_C20P
1104
+ when 'XC20P'
1105
+ JOSE::JWE::ENC_XC20P
1098
1106
  else
1099
1107
  raise ArgumentError, "unknown 'enc': #{jwe.fields['enc'].inspect}"
1100
1108
  end
@@ -14,16 +14,31 @@ class JOSE::JWK::KTY_EC < Struct.new(:key)
14
14
  else
15
15
  raise ArgumentError, "invalid 'EC' JWK"
16
16
  end
17
- ec = OpenSSL::PKey::EC.new(crv)
17
+
18
18
  x = JOSE.urlsafe_decode64(fields['x'])
19
19
  y = JOSE.urlsafe_decode64(fields['y'])
20
- ec.public_key = OpenSSL::PKey::EC::Point.new(
20
+ point = OpenSSL::PKey::EC::Point.new(
21
21
  OpenSSL::PKey::EC::Group.new(crv),
22
22
  OpenSSL::BN.new([0x04, x, y].pack('Ca*a*'), 2)
23
23
  )
24
- if fields['d'].is_a?(String)
25
- ec.private_key = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2)
24
+
25
+ sequence = if fields['d'].is_a?(String)
26
+ OpenSSL::ASN1::Sequence([
27
+ OpenSSL::ASN1::Integer(1),
28
+ OpenSSL::ASN1::OctetString(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2).to_s(2)),
29
+ OpenSSL::ASN1::ObjectId(crv, 0, :EXPLICIT),
30
+ OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed), 1, :EXPLICIT)
31
+ ])
32
+ else
33
+ OpenSSL::ASN1::Sequence([
34
+ OpenSSL::ASN1::Sequence([
35
+ OpenSSL::ASN1::ObjectId("id-ecPublicKey"),
36
+ OpenSSL::ASN1::ObjectId(crv)
37
+ ]),
38
+ OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed))
39
+ ])
26
40
  end
41
+ ec = OpenSSL::PKey::EC.new(sequence.to_der)
27
42
  return JOSE::JWK::KTY_EC.new(JOSE::JWK::PKeyProxy.new(ec)), fields.except('kty', 'crv', 'd', 'x', 'y')
28
43
  else
29
44
  raise ArgumentError, "invalid 'EC' JWK"
@@ -132,7 +147,7 @@ class JOSE::JWK::KTY_EC < Struct.new(:key)
132
147
  curve_name
133
148
  end
134
149
  if curve_name.is_a?(String)
135
- return from_key(OpenSSL::PKey::EC.new(curve_name).generate_key)
150
+ return from_key(OpenSSL::PKey::EC.generate(curve_name))
136
151
  else
137
152
  raise ArgumentError, "'curve_name' must be a String"
138
153
  end
@@ -8,36 +8,32 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key)
8
8
  raise ArgumentError, "multi-prime RSA keys are not supported"
9
9
  elsif fields['d'].is_a?(String)
10
10
  if fields['dp'].is_a?(String) and fields['dq'].is_a?(String) and fields['p'].is_a?(String) and fields['q'].is_a?(String) and fields['qi'].is_a?(String)
11
- rsa = OpenSSL::PKey::RSA.new
12
- rsa.set_key(
13
- OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2),
14
- OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2),
15
- OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2)
16
- )
17
- rsa.set_factors(
18
- OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['p']), 2),
19
- OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['q']), 2)
20
- )
21
- rsa.set_crt_params(
22
- OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['dp']), 2),
23
- OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['dq']), 2),
24
- OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['qi']), 2)
25
- )
11
+ asn1_sequence = OpenSSL::ASN1::Sequence.new([
12
+ OpenSSL::ASN1::Integer.new(0),
13
+ OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2)),
14
+ OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2)),
15
+ OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2)),
16
+ OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['p']), 2)),
17
+ OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['q']), 2)),
18
+ OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['dp']), 2)),
19
+ OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['dq']), 2)),
20
+ OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['qi']), 2))
21
+ ])
22
+ rsa = OpenSSL::PKey::RSA.new(asn1_sequence.to_der)
26
23
  return JOSE::JWK::KTY_RSA.new(JOSE::JWK::PKeyProxy.new(rsa)), fields.except('kty', 'd', 'dp', 'dq', 'e', 'n', 'p', 'q', 'qi')
27
24
  else
28
- d = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2)
29
- e = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2)
30
- n = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2)
25
+ d = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2)
26
+ e = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2)
27
+ n = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2)
31
28
  rsa = convert_sfm_to_crt(d, e, n)
32
29
  return JOSE::JWK::KTY_RSA.new(JOSE::JWK::PKeyProxy.new(rsa)), fields.except('kty', 'd', 'dp', 'dq', 'e', 'n', 'p', 'q', 'qi')
33
30
  end
34
31
  else
35
- rsa = OpenSSL::PKey::RSA.new
36
- rsa.set_key(
37
- OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2),
38
- OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2),
39
- nil
40
- )
32
+ asn1_sequence = OpenSSL::ASN1::Sequence.new([
33
+ OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2)),
34
+ OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2))
35
+ ])
36
+ rsa = OpenSSL::PKey::RSA.new(OpenSSL::PKey::RSA.new(asn1_sequence.to_der))
41
37
  return JOSE::JWK::KTY_RSA.new(JOSE::JWK::PKeyProxy.new(rsa)), fields.except('kty', 'e', 'n')
42
38
  end
43
39
  else
@@ -140,7 +136,8 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key)
140
136
  end
141
137
  end
142
138
  if modulus_size.is_a?(Integer) and (exponent_size.nil? or exponent_size.is_a?(Integer))
143
- return from_key(OpenSSL::PKey::RSA.generate(modulus_size, exponent_size))
139
+ return from_key(OpenSSL::PKey::RSA.generate(modulus_size)) if exponent_size.nil?
140
+ return from_key(OpenSSL::PKey::RSA.generate(modulus_size, exponent_size)) if exponent_size.is_a?(Integer)
144
141
  else
145
142
  raise ArgumentError, "'modulus_size' must be an Integer and 'exponent_size' must be nil or an Integer"
146
143
  end
@@ -160,7 +157,12 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key)
160
157
  when :rsa_pkcs1_padding
161
158
  return key.sign(digest_type.new, message)
162
159
  when :rsa_pkcs1_pss_padding
163
- return JOSE::JWA::PKCS1.rsassa_pss_sign(digest_type, message, key)
160
+ if key.respond_to?(:sign_pss)
161
+ digest_name = digest_type.new.name
162
+ return key.sign_pss(digest_name, message, salt_length: :digest, mgf1_hash: digest_name)
163
+ else
164
+ return JOSE::JWA::PKCS1.rsassa_pss_sign(digest_type, message, key)
165
+ end
164
166
  else
165
167
  raise ArgumentError, "unsupported RSA padding: #{padding.inspect}"
166
168
  end
@@ -189,7 +191,12 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key)
189
191
  when :rsa_pkcs1_padding
190
192
  return key.verify(digest_type.new, signature, message)
191
193
  when :rsa_pkcs1_pss_padding
192
- return JOSE::JWA::PKCS1.rsassa_pss_verify(digest_type, message, signature, key)
194
+ if key.respond_to?(:verify_pss)
195
+ digest_name = digest_type.new.name
196
+ return key.verify_pss(digest_name, signature, message, salt_length: :digest, mgf1_hash: digest_name)
197
+ else
198
+ return JOSE::JWA::PKCS1.rsassa_pss_verify(digest_type, message, signature, key)
199
+ end
193
200
  else
194
201
  raise ArgumentError, "unsupported RSA padding: #{padding.inspect}"
195
202
  end
@@ -230,11 +237,18 @@ private
230
237
  dq = d % (q - 1)
231
238
  qi = q.mod_inverse(p)
232
239
 
233
- rsa = OpenSSL::PKey::RSA.new
234
- rsa.set_key(n, e, d)
235
- rsa.set_factors(p, q)
236
- rsa.set_crt_params(dp, dq, qi)
237
-
240
+ asn1_sequence = OpenSSL::ASN1::Sequence.new([
241
+ OpenSSL::ASN1::Integer.new(0),
242
+ OpenSSL::ASN1::Integer.new(n),
243
+ OpenSSL::ASN1::Integer.new(e),
244
+ OpenSSL::ASN1::Integer.new(d),
245
+ OpenSSL::ASN1::Integer.new(p),
246
+ OpenSSL::ASN1::Integer.new(q),
247
+ OpenSSL::ASN1::Integer.new(dp),
248
+ OpenSSL::ASN1::Integer.new(dq),
249
+ OpenSSL::ASN1::Integer.new(qi)
250
+ ])
251
+ rsa = OpenSSL::PKey::RSA.new(asn1_sequence.to_der)
238
252
  return rsa
239
253
  end
240
254
 
@@ -190,7 +190,6 @@ private
190
190
 
191
191
  def parse_publickeys(body, n, pks = [])
192
192
  return pks, body if n == 0
193
- pos = body.pos
194
193
  if pk_len = body.read(4) and pk_len.bytesize == 4
195
194
  pk_len, = pk_len.unpack('N')
196
195
  if pk = body.read(pk_len) and pk.bytesize == pk_len
data/lib/jose/jwk/set.rb CHANGED
@@ -1,7 +1,7 @@
1
- require 'hamster/vector'
1
+ require 'immutable/vector'
2
2
 
3
- # Immutable Set structure based on `Hamster::Vector`.
4
- class JOSE::JWK::Set < Hamster::Vector
3
+ # Immutable Set structure based on `Immutable::Vector`.
4
+ class JOSE::JWK::Set < Immutable::Vector
5
5
 
6
6
  def self.from_map(fields)
7
7
  if fields['keys'].is_a?(Array)
data/lib/jose/jwk.rb CHANGED
@@ -481,7 +481,7 @@ module JOSE
481
481
  # Converts a private {JOSE::JWK JOSE::JWK} into a public {JOSE::JWK JOSE::JWK}.
482
482
  #
483
483
  # !!!ruby
484
- # jwk_rsa = JOSE::JWK.generate_key([:rsa, 256]).to_map
484
+ # jwk_rsa = JOSE::JWK.generate_key([:rsa, 1024]).to_map
485
485
  # # => JOSE::Map[
486
486
  # # "dq" => "Iv_BghpjRyv8hk4AgsX_3w",
487
487
  # # "e" => "AQAB",
data/lib/jose/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module JOSE
2
- VERSION = "1.1.3"
2
+ VERSION = "1.2.0"
3
3
  end