jose 1.1.3 → 1.2.0

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