json-jwt 0.5.6 → 0.6.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.
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
|