json-jwt 0.5.6 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of json-jwt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.rdoc +1 -1
- data/VERSION +1 -1
- data/lib/json/jwe.rb +49 -79
- data/lib/json/jwt.rb +1 -1
- data/spec/json/jwe_spec.rb +14 -14
- data/spec/json/jwt_spec.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ed6b68461d916fd8be52e755b8bb2c77253149d
|
4
|
+
data.tar.gz: 8f0b99b938171b21ab88d259471ec72622c979bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07c51fe7a0b6b66ce4e4504f36baf1698c76537fa8f38513d2cc3fc67dd33208c88b64b8fbe8d0c6feafbf457d10e1ccdf2f3f2adc148035577ed3d5c37cedfb
|
7
|
+
data.tar.gz: 44ae1afcca4d398d46fedacfa69e3403d484f77011af870b7e77f38496a4b1177d3b8fad54a014b49a980dc0f871135b3eed27354cc3035e3cba80b1d36d7d22
|
data/README.rdoc
CHANGED
@@ -33,7 +33,7 @@ JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON
|
|
33
33
|
jws.to_s # => header.payload.signature
|
34
34
|
|
35
35
|
# With signature & encryption
|
36
|
-
jwe = jws.encrypt(key, algorithm, encryption_method) # algorithm & encryption_method are optional. default RSA1_5 & A128CBC
|
36
|
+
jwe = jws.encrypt(key, algorithm, encryption_method) # algorithm & encryption_method are optional. default RSA1_5 & A128CBC-HS256
|
37
37
|
jws.to_s # => header.master_key.iv.cipher_text.integrity_value
|
38
38
|
|
39
39
|
For details about <code>key</code> and <code>algorithm</code>, see
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0
|
data/lib/json/jwe.rb
CHANGED
@@ -9,8 +9,8 @@ module JSON
|
|
9
9
|
|
10
10
|
attr_accessor(
|
11
11
|
:public_key_or_secret, :private_key_or_secret, :mode,
|
12
|
-
:input, :plain_text, :cipher_text, :
|
13
|
-
:
|
12
|
+
:input, :plain_text, :cipher_text, :authentication_tag, :iv,
|
13
|
+
:content_encryption_key, :jwe_encrypted_key, :encryption_key, :mac_key
|
14
14
|
)
|
15
15
|
|
16
16
|
register_header_keys :enc, :epk, :zip, :apu, :apv
|
@@ -49,10 +49,10 @@ module JSON
|
|
49
49
|
if mode == :encyption
|
50
50
|
[
|
51
51
|
header.to_json,
|
52
|
-
|
52
|
+
jwe_encrypted_key,
|
53
53
|
iv,
|
54
54
|
cipher_text,
|
55
|
-
|
55
|
+
authentication_tag
|
56
56
|
].collect do |segment|
|
57
57
|
UrlSafeBase64.encode64 segment.to_s
|
58
58
|
end.join('.')
|
@@ -74,7 +74,7 @@ module JSON
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def cbc?
|
77
|
-
[:'A128CBC
|
77
|
+
[:'A128CBC-HS256', :'A256CBC-HS512'].collect(&:to_s).include? encryption_method.to_s
|
78
78
|
end
|
79
79
|
|
80
80
|
def dir?
|
@@ -95,9 +95,9 @@ module JSON
|
|
95
95
|
'aes-128-gcm'
|
96
96
|
when :A256GCM.to_s
|
97
97
|
'aes-256-gcm'
|
98
|
-
when :'A128CBC
|
98
|
+
when :'A128CBC-HS256'.to_s
|
99
99
|
'aes-128-cbc'
|
100
|
-
when :'A256CBC
|
100
|
+
when :'A256CBC-HS512'.to_s
|
101
101
|
'aes-256-cbc'
|
102
102
|
else
|
103
103
|
raise UnexpectedAlgorithm.new('Unknown Encryption Algorithm')
|
@@ -106,9 +106,9 @@ module JSON
|
|
106
106
|
|
107
107
|
def sha_size
|
108
108
|
case encryption_method.to_s
|
109
|
-
when :'A128CBC
|
109
|
+
when :'A128CBC-HS256'.to_s
|
110
110
|
256
|
111
|
-
when :'A256CBC
|
111
|
+
when :'A256CBC-HS512'.to_s
|
112
112
|
512
|
113
113
|
else
|
114
114
|
raise UnexpectedAlgorithm.new('Unknown Hash Size')
|
@@ -119,50 +119,14 @@ module JSON
|
|
119
119
|
OpenSSL::Digest::Digest.new "SHA#{sha_size}"
|
120
120
|
end
|
121
121
|
|
122
|
-
def derive_cbc_encryption_and_integirity_keys!
|
123
|
-
encryption_key_size = sha_size / 2
|
124
|
-
integrity_key_size = sha_size
|
125
|
-
encryption_segments = [
|
126
|
-
1,
|
127
|
-
master_key,
|
128
|
-
encryption_key_size,
|
129
|
-
encryption_method,
|
130
|
-
0,
|
131
|
-
0,
|
132
|
-
'Encryption'
|
133
|
-
]
|
134
|
-
integrity_segments = [
|
135
|
-
1,
|
136
|
-
master_key,
|
137
|
-
integrity_key_size,
|
138
|
-
encryption_method,
|
139
|
-
0,
|
140
|
-
0,
|
141
|
-
'Integrity'
|
142
|
-
]
|
143
|
-
encryption_hash_input, integrity_hash_input = [encryption_segments, integrity_segments].collect do |segments|
|
144
|
-
segments.collect do |segment|
|
145
|
-
case segment
|
146
|
-
when Integer
|
147
|
-
BinData::Int32be.new(segment).to_binary_s
|
148
|
-
else
|
149
|
-
segment.to_s
|
150
|
-
end
|
151
|
-
end.join
|
152
|
-
end
|
153
|
-
self.encryption_key = sha_digest.digest(encryption_hash_input)[0, encryption_key_size / 8]
|
154
|
-
self.integrity_key = sha_digest.digest integrity_hash_input
|
155
|
-
self
|
156
|
-
end
|
157
|
-
|
158
122
|
# encyption
|
159
123
|
|
160
|
-
def
|
161
|
-
@
|
124
|
+
def jwe_encrypted_key
|
125
|
+
@jwe_encrypted_key ||= case algorithm.to_s
|
162
126
|
when :RSA1_5.to_s
|
163
|
-
public_key_or_secret.public_encrypt
|
127
|
+
public_key_or_secret.public_encrypt content_encryption_key
|
164
128
|
when :'RSA-OAEP'.to_s
|
165
|
-
public_key_or_secret.public_encrypt
|
129
|
+
public_key_or_secret.public_encrypt content_encryption_key, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
|
166
130
|
when :A128KW.to_s
|
167
131
|
raise NotImplementedError.new('A128KW not supported yet')
|
168
132
|
when :A256KW.to_s
|
@@ -190,65 +154,64 @@ module JSON
|
|
190
154
|
cipher.key = encryption_key
|
191
155
|
self.iv = cipher.random_iv
|
192
156
|
if gcm?
|
193
|
-
cipher.auth_data =
|
194
|
-
UrlSafeBase64.encode64 segment.to_s
|
195
|
-
end.join('.')
|
157
|
+
cipher.auth_data = UrlSafeBase64.encode64 header.to_json
|
196
158
|
end
|
197
159
|
self
|
198
160
|
end
|
199
161
|
|
200
162
|
def generate_gcm_keys!
|
201
|
-
self.
|
163
|
+
self.content_encryption_key ||= if dir?
|
202
164
|
public_key_or_secret
|
203
165
|
else
|
204
166
|
cipher.random_key
|
205
167
|
end
|
206
|
-
self.encryption_key =
|
207
|
-
self.integrity_key = :wont_be_used
|
168
|
+
self.encryption_key = content_encryption_key
|
208
169
|
self
|
209
170
|
end
|
210
171
|
|
211
172
|
def generate_cbc_keys!
|
212
|
-
self.
|
173
|
+
self.content_encryption_key ||= if dir?
|
213
174
|
public_key_or_secret
|
214
175
|
else
|
215
176
|
SecureRandom.random_bytes sha_size / 8
|
216
177
|
end
|
217
|
-
|
178
|
+
self.mac_key, self.encryption_key = content_encryption_key.unpack("a#{content_encryption_key.length / 2}" * 2)
|
179
|
+
self
|
218
180
|
end
|
219
181
|
|
220
|
-
def
|
221
|
-
@
|
182
|
+
def authentication_tag
|
183
|
+
@authentication_tag ||= case
|
222
184
|
when gcm?
|
223
185
|
cipher.auth_tag
|
224
186
|
when cbc?
|
187
|
+
auth_data = UrlSafeBase64.encode64 header.to_json
|
225
188
|
secured_input = [
|
226
|
-
|
227
|
-
encrypted_master_key,
|
189
|
+
auth_data,
|
228
190
|
iv,
|
229
|
-
cipher_text
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
191
|
+
cipher_text,
|
192
|
+
BinData::Uint64be.new(auth_data.length * 8).to_binary_s
|
193
|
+
].join
|
194
|
+
OpenSSL::HMAC.digest(
|
195
|
+
sha_digest, mac_key, secured_input
|
196
|
+
)[0, sha_size / 2 / 8]
|
234
197
|
end
|
235
198
|
end
|
236
199
|
|
237
200
|
# decryption
|
238
201
|
|
239
202
|
def decode_segments!
|
240
|
-
_header_json_, self.
|
203
|
+
_header_json_, self.jwe_encrypted_key, self.iv, self.cipher_text, self.authentication_tag = input.split('.').collect do |segment|
|
241
204
|
UrlSafeBase64.decode64 segment
|
242
205
|
end
|
243
206
|
self
|
244
207
|
end
|
245
208
|
|
246
|
-
def
|
209
|
+
def decrypt_content_encryption_key
|
247
210
|
case algorithm.to_s
|
248
211
|
when :RSA1_5.to_s
|
249
|
-
private_key_or_secret.private_decrypt
|
212
|
+
private_key_or_secret.private_decrypt jwe_encrypted_key
|
250
213
|
when :'RSA-OAEP'.to_s
|
251
|
-
private_key_or_secret.private_decrypt
|
214
|
+
private_key_or_secret.private_decrypt jwe_encrypted_key, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
|
252
215
|
when :A128KW.to_s
|
253
216
|
raise NotImplementedError.new('A128KW not supported yet')
|
254
217
|
when :A256KW.to_s
|
@@ -267,26 +230,33 @@ module JSON
|
|
267
230
|
end
|
268
231
|
|
269
232
|
def restore_cipher_keys!
|
270
|
-
self.
|
233
|
+
self.content_encryption_key = decrypt_content_encryption_key
|
271
234
|
case
|
272
235
|
when gcm?
|
273
|
-
self.encryption_key =
|
274
|
-
self.integrity_key = :wont_be_used
|
236
|
+
self.encryption_key = content_encryption_key
|
275
237
|
when cbc?
|
276
|
-
|
238
|
+
self.mac_key, self.encryption_key = content_encryption_key.unpack("a#{content_encryption_key.length / 2}" * 2)
|
277
239
|
end
|
278
240
|
cipher.key = encryption_key
|
279
241
|
cipher.iv = iv # NOTE: 'iv' has to be set after 'key' for GCM
|
280
242
|
if gcm?
|
281
|
-
cipher.auth_tag =
|
282
|
-
cipher.auth_data = input.split('.')
|
243
|
+
cipher.auth_tag = authentication_tag
|
244
|
+
cipher.auth_data = input.split('.').first
|
283
245
|
end
|
284
246
|
end
|
285
247
|
|
286
248
|
def verify_cbc_integirity_value!
|
287
|
-
|
288
|
-
|
289
|
-
|
249
|
+
auth_data = input.split('.').first
|
250
|
+
secured_input = [
|
251
|
+
auth_data,
|
252
|
+
iv,
|
253
|
+
cipher_text,
|
254
|
+
BinData::Uint64be.new(auth_data.length * 8).to_binary_s
|
255
|
+
].join
|
256
|
+
expected_authentication_tag = OpenSSL::HMAC.digest(
|
257
|
+
sha_digest, mac_key, secured_input
|
258
|
+
)[0, sha_size / 2 / 8]
|
259
|
+
unless authentication_tag == expected_authentication_tag
|
290
260
|
raise DecryptionFailed.new('Invalid integrity value')
|
291
261
|
end
|
292
262
|
end
|
data/lib/json/jwt.rb
CHANGED
@@ -59,7 +59,7 @@ module JSON
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
def encrypt(public_key_or_secret, algorithm = :RSA1_5, encryption_method = :'A128CBC
|
62
|
+
def encrypt(public_key_or_secret, algorithm = :RSA1_5, encryption_method = :'A128CBC-HS256')
|
63
63
|
jwe = JWE.new(self)
|
64
64
|
jwe.alg = algorithm
|
65
65
|
jwe.enc = encryption_method
|
data/spec/json/jwe_spec.rb
CHANGED
@@ -59,8 +59,8 @@ describe JSON::JWE do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
shared_examples_for :cbc_encryption do
|
62
|
-
context 'when enc=A128CBC
|
63
|
-
before { jwe.enc = :'A128CBC
|
62
|
+
context 'when enc=A128CBC-HS256' do
|
63
|
+
before { jwe.enc = :'A128CBC-HS256' }
|
64
64
|
|
65
65
|
it 'should decryptable by Nimbus JOSE JWT' do
|
66
66
|
jwe.encrypt! key
|
@@ -68,8 +68,8 @@ describe JSON::JWE do
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
context 'when enc=A256CBC
|
72
|
-
before { jwe.enc = :'A256CBC
|
71
|
+
context 'when enc=A256CBC-HS512' do
|
72
|
+
before { jwe.enc = :'A256CBC-HS512' }
|
73
73
|
|
74
74
|
it 'should decryptable by Nimbus JOSE JWT' do
|
75
75
|
jwe.encrypt! key
|
@@ -137,7 +137,7 @@ describe JSON::JWE do
|
|
137
137
|
context 'when unknonw/unsupported algorithm given' do
|
138
138
|
let(:key) { public_key }
|
139
139
|
let(:alg) { :RSA1_5 }
|
140
|
-
let(:enc) { :'A128CBC
|
140
|
+
let(:enc) { :'A128CBC-HS256' }
|
141
141
|
before { jwe.alg, jwe.enc = alg, enc }
|
142
142
|
|
143
143
|
context 'when alg=unknown' do
|
@@ -280,13 +280,13 @@ describe JSON::JWE do
|
|
280
280
|
end
|
281
281
|
end
|
282
282
|
|
283
|
-
context 'when enc=A128CBC
|
284
|
-
let(:enc) { :'A128CBC
|
283
|
+
context 'when enc=A128CBC-HS256' do
|
284
|
+
let(:enc) { :'A128CBC-HS256' }
|
285
285
|
it_behaves_like :decryptable
|
286
286
|
end
|
287
287
|
|
288
|
-
context 'when enc=A256CBC
|
289
|
-
let(:enc) { :'A256CBC
|
288
|
+
context 'when enc=A256CBC-HS512' do
|
289
|
+
let(:enc) { :'A256CBC-HS512' }
|
290
290
|
it_behaves_like :decryptable
|
291
291
|
end
|
292
292
|
end
|
@@ -313,14 +313,14 @@ describe JSON::JWE do
|
|
313
313
|
end
|
314
314
|
end
|
315
315
|
|
316
|
-
context 'when enc=A128CBC
|
317
|
-
let(:enc) { :'A128CBC
|
316
|
+
context 'when enc=A128CBC-HS256' do
|
317
|
+
let(:enc) { :'A128CBC-HS256' }
|
318
318
|
it_behaves_like :decryptable
|
319
319
|
it_behaves_like :verify_cbc_integrity_value
|
320
320
|
end
|
321
321
|
|
322
|
-
context 'when enc=A256CBC
|
323
|
-
let(:enc) { :'A256CBC
|
322
|
+
context 'when enc=A256CBC-HS512' do
|
323
|
+
let(:enc) { :'A256CBC-HS512' }
|
324
324
|
it_behaves_like :decryptable
|
325
325
|
it_behaves_like :verify_cbc_integrity_value
|
326
326
|
end
|
@@ -336,7 +336,7 @@ describe JSON::JWE do
|
|
336
336
|
let(:input) { 'whatever' }
|
337
337
|
let(:key) { public_key }
|
338
338
|
let(:alg) { :RSA1_5 }
|
339
|
-
let(:enc) { :'A128CBC
|
339
|
+
let(:enc) { :'A128CBC-HS256' }
|
340
340
|
|
341
341
|
context 'when alg=unknown' do
|
342
342
|
let(:alg) { :unknown }
|
data/spec/json/jwt_spec.rb
CHANGED
@@ -115,7 +115,7 @@ describe JSON::JWT do
|
|
115
115
|
end
|
116
116
|
|
117
117
|
it 'should accept optional algorithm and encryption method' do
|
118
|
-
jwt.encrypt(
|
118
|
+
jwt.encrypt(SecureRandom.hex(32), :dir, :'A256CBC-HS512').should be_a JSON::JWE
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
@@ -167,7 +167,7 @@ describe JSON::JWT do
|
|
167
167
|
it 'should skip verification' do
|
168
168
|
expect do
|
169
169
|
jwe = JSON::JWT.decode input, :skip_decryption
|
170
|
-
jwe.header.should == {'alg' => 'RSA1_5', 'enc' => 'A128CBC
|
170
|
+
jwe.header.should == {'alg' => 'RSA1_5', 'enc' => 'A128CBC-HS256'}
|
171
171
|
end.not_to raise_error
|
172
172
|
end
|
173
173
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json-jwt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- nov matake
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: multi_json
|