json-jwt 0.5.0 → 0.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7fc22bebad1c3924998f637b07f91089ba1d365f
4
- data.tar.gz: 8f969eba9420ffccaeb0053096e039c02fbcfb89
3
+ metadata.gz: 86380eefda874cbe7e7939e70fdfcffe379395e4
4
+ data.tar.gz: d2f3fc1ba0a60787927dac2d0b21d8a151488218
5
5
  SHA512:
6
- metadata.gz: a32887bed2783fb91c98776c70e6a471a6640f59b336b56d4a5576019ab79cdbdbb25bcf149bf26d4710006f03a0699c4dae0137ab61d3895ded29dbd38cdfa2
7
- data.tar.gz: 44ee98be92413ef444c90d93529566802a0725a182e55517d5ecea8e8b7b66b5d3386e3dccf7d3b67e728c038ca336f42a2bcf3837ffd2c5c20a2f73b5f0bcfc
6
+ metadata.gz: 2257bab98f399a6b5da81de323eead584846a68064024655bd58cc06c29305be08ee173b32816fb2d848b47f633c9382d6d1929bf83b2171c159f07a04ad4854
7
+ data.tar.gz: f4721c5653fd40b4895b9086ca4291e78317a135c9ec22005d9fda471cb9c07a06f278fc9d787b295345ce88f9fa09e569b1430003795e95e394d0bb3a9b33e6
data/.gitignore CHANGED
@@ -17,6 +17,7 @@ tmtags
17
17
  coverage*
18
18
  rdoc
19
19
  pkg
20
+ Gemfile.lock
20
21
 
21
22
  ## PROJECT::SPECIFIC
22
23
  .class
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.5.1
data/lib/json/jwe.rb CHANGED
@@ -7,16 +7,22 @@ module JSON
7
7
  class DecryptionFailed < JWT::VerificationFailed; end
8
8
  class UnexpectedAlgorithm < JWT::UnexpectedAlgorithm; end
9
9
 
10
- attr_accessor :public_key_or_secret, :plain_text, :master_key, :encrypted_master_key, :encryption_key, :integrity_key, :integrity_value, :iv, :cipher_text
10
+ attr_accessor(
11
+ :public_key_or_secret, :private_key_or_secret, :mode,
12
+ :input, :plain_text, :cipher_text, :integrity_value, :iv,
13
+ :master_key, :encrypted_master_key, :encryption_key, :integrity_key
14
+ )
11
15
 
12
16
  register_header_keys :enc, :epk, :zip, :jku, :jwk, :x5u, :x5t, :x5c, :kid, :typ, :cty, :apu, :apv, :epu, :epv
13
17
  alias_method :encryption_method, :enc
14
18
 
15
- def initialize(jwt_or_plain_text)
16
- self.plain_text = jwt_or_plain_text.to_s
19
+ def initialize(input)
20
+ self.input = input.to_s
17
21
  end
18
22
 
19
23
  def encrypt!(public_key_or_secret)
24
+ self.mode = :encyption
25
+ self.plain_text = input
20
26
  self.public_key_or_secret = public_key_or_secret
21
27
  cipher.encrypt
22
28
  generate_cipher_keys!
@@ -24,24 +30,37 @@ module JSON
24
30
  self
25
31
  end
26
32
 
27
- def decrypt!
28
- raise NotImplementedError.new('JWE decryption not supported yet')
33
+ def decrypt!(private_key_or_secret)
34
+ self.mode = :decryption
35
+ self.private_key_or_secret = private_key_or_secret
36
+ decode_segments!
37
+ cipher.decrypt
38
+ restore_cipher_keys!
39
+ self.plain_text = cipher.update(cipher_text) + cipher.final
40
+ verify_cbc_integirity_value! if cbc?
41
+ self
29
42
  end
30
43
 
31
44
  def to_s
32
- [
33
- header.to_json,
34
- encrypted_master_key,
35
- iv,
36
- cipher_text,
37
- integrity_value
38
- ].collect do |segment|
39
- UrlSafeBase64.encode64 segment.to_s
40
- end.join('.')
45
+ if mode == :encyption
46
+ [
47
+ header.to_json,
48
+ encrypted_master_key,
49
+ iv,
50
+ cipher_text,
51
+ integrity_value
52
+ ].collect do |segment|
53
+ UrlSafeBase64.encode64 segment.to_s
54
+ end.join('.')
55
+ else
56
+ plain_text
57
+ end
41
58
  end
42
59
 
43
60
  private
44
61
 
62
+ # common
63
+
45
64
  def gcm_supported?
46
65
  RUBY_VERSION >= '2.0.0' && OpenSSL::OPENSSL_VERSION >= 'OpenSSL 1.0.1c'
47
66
  end
@@ -96,6 +115,44 @@ module JSON
96
115
  OpenSSL::Digest::Digest.new "SHA#{sha_size}"
97
116
  end
98
117
 
118
+ def derive_cbc_encryption_and_integirity_keys!
119
+ encryption_key_size = sha_size / 2
120
+ integrity_key_size = sha_size
121
+ encryption_segments = [
122
+ 1,
123
+ master_key,
124
+ encryption_key_size,
125
+ encryption_method,
126
+ epu || 0,
127
+ epv || 0,
128
+ 'Encryption'
129
+ ]
130
+ integrity_segments = [
131
+ 1,
132
+ master_key,
133
+ integrity_key_size,
134
+ encryption_method,
135
+ epu || 0,
136
+ epv || 0,
137
+ 'Integrity'
138
+ ]
139
+ encryption_hash_input, integrity_hash_input = [encryption_segments, integrity_segments].collect do |segments|
140
+ segments.collect do |segment|
141
+ case segment
142
+ when Integer
143
+ BinData::Int32be.new(segment).to_binary_s
144
+ else
145
+ segment.to_s
146
+ end
147
+ end.join
148
+ end
149
+ self.encryption_key = sha_digest.digest(encryption_hash_input)[0, encryption_key_size / 8]
150
+ self.integrity_key = sha_digest.digest integrity_hash_input
151
+ self
152
+ end
153
+
154
+ # encyption
155
+
99
156
  def encrypted_master_key
100
157
  @encrypted_master_key ||= case algorithm.to_s
101
158
  when :RSA1_5.to_s
@@ -126,8 +183,8 @@ module JSON
126
183
  when cbc?
127
184
  generate_cbc_keys!
128
185
  end
129
- @cipher.key = encryption_key
130
- self.iv = @cipher.random_iv
186
+ cipher.key = encryption_key
187
+ self.iv = cipher.random_iv
131
188
  if gcm?
132
189
  cipher.auth_data = [header.to_json, encrypted_master_key, iv].collect do |segment|
133
190
  UrlSafeBase64.encode64 segment.to_s
@@ -140,7 +197,7 @@ module JSON
140
197
  self.master_key ||= if dir?
141
198
  public_key_or_secret
142
199
  else
143
- @cipher.random_key
200
+ cipher.random_key
144
201
  end
145
202
  self.encryption_key = master_key
146
203
  self.integrity_key = :wont_be_used
@@ -148,50 +205,19 @@ module JSON
148
205
  end
149
206
 
150
207
  def generate_cbc_keys!
151
- encryption_key_size = sha_size / 2
152
- integrity_key_size = master_key_size = sha_size
153
208
  self.master_key ||= if dir?
154
209
  public_key_or_secret
155
210
  else
156
- SecureRandom.random_bytes master_key_size / 8
211
+ SecureRandom.random_bytes sha_size / 8
157
212
  end
158
- encryption_segments = [
159
- 1,
160
- master_key,
161
- encryption_key_size,
162
- encryption_method,
163
- epu || 0,
164
- epv || 0,
165
- 'Encryption'
166
- ]
167
- integrity_segments = [
168
- 1,
169
- master_key,
170
- integrity_key_size,
171
- encryption_method,
172
- epu || 0,
173
- epv || 0,
174
- 'Integrity'
175
- ]
176
- encryption_hash_input, integrity_hash_input = [encryption_segments, integrity_segments].collect do |segments|
177
- segments.collect do |segment|
178
- case segment
179
- when Integer
180
- BinData::Int32be.new(segment).to_binary_s
181
- else
182
- segment.to_s
183
- end
184
- end.join
185
- end
186
- self.encryption_key = sha_digest.digest(encryption_hash_input)[0, encryption_key_size / 8]
187
- self.integrity_key = sha_digest.digest integrity_hash_input
188
- self
213
+ derive_cbc_encryption_and_integirity_keys!
189
214
  end
190
215
 
191
216
  def integrity_value
192
- @integrity_value ||= if gcm?
217
+ @integrity_value ||= case
218
+ when gcm?
193
219
  cipher.auth_tag
194
- else
220
+ when cbc?
195
221
  secured_input = [
196
222
  header.to_json,
197
223
  encrypted_master_key,
@@ -202,7 +228,59 @@ module JSON
202
228
  end.join('.')
203
229
  OpenSSL::HMAC.digest sha_digest, integrity_key, secured_input
204
230
  end
205
- @integrity_value
231
+ end
232
+
233
+ # decryption
234
+
235
+ def decode_segments!
236
+ _header_json_, self.encrypted_master_key, self.iv, self.cipher_text, self.integrity_value = input.split('.').collect do |segment|
237
+ UrlSafeBase64.decode64 segment
238
+ end
239
+ self
240
+ end
241
+
242
+ def decrypt_master_key
243
+ case algorithm.to_s
244
+ when :RSA1_5.to_s
245
+ private_key_or_secret.private_decrypt encrypted_master_key
246
+ when :'RSA-OAEP'.to_s
247
+ private_key_or_secret.private_decrypt encrypted_master_key, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
248
+ when :A128KW .to_s
249
+ raise NotImplementedError.new('A128KW not supported yet')
250
+ when :A256KW.to_s
251
+ raise NotImplementedError.new('A256KW not supported yet')
252
+ when :dir.to_s
253
+ private_key_or_secret
254
+ when :'ECDH-ES'.to_s
255
+ raise NotImplementedError.new('ECDH-ES not supported yet')
256
+ when :'ECDH-ES+A128KW'.to_s
257
+ raise NotImplementedError.new('ECDH-ES+A128KW not supported yet')
258
+ when :'ECDH-ES+A256KW'.to_s
259
+ raise NotImplementedError.new('ECDH-ES+A256KW not supported yet')
260
+ else
261
+ raise UnexpectedAlgorithm.new('Unknown Encryption Algorithm')
262
+ end
263
+ end
264
+
265
+ def restore_cipher_keys!
266
+ self.master_key = decrypt_master_key
267
+ case
268
+ when gcm?
269
+ self.encryption_key = master_key
270
+ self.integrity_key = :wont_be_used
271
+ when cbc?
272
+ derive_cbc_encryption_and_integirity_keys!
273
+ end
274
+ cipher.key = encryption_key
275
+ cipher.iv = iv # NOTE: 'iv' has to be set after 'key' for GCM
276
+ if gcm?
277
+ cipher.auth_tag = integrity_value
278
+ cipher.auth_data = input.split('.')[0, 3].join('.')
279
+ end
280
+ end
281
+
282
+ def verify_cbc_integirity_value!
283
+ # raise UnexpectedAlgorithm.new('TODO')
206
284
  end
207
285
  end
208
286
  end
@@ -154,4 +154,106 @@ describe JSON::JWE do
154
154
  end
155
155
  end
156
156
  end
157
+
158
+ describe 'decrypt!' do
159
+ let(:plain_text) { 'Hello World' }
160
+ let(:input) do
161
+ _jwe_ = JSON::JWE.new plain_text
162
+ _jwe_.alg, _jwe_.enc = alg, enc
163
+ _jwe_.encrypt! key
164
+ _jwe_.to_s
165
+ end
166
+ let(:jwe) do
167
+ _jwe_ = JSON::JWE.new input
168
+ _jwe_.alg, _jwe_.enc = alg, enc
169
+ _jwe_
170
+ end
171
+
172
+ shared_examples_for :decryptable do
173
+ it do
174
+ jwe.decrypt! key
175
+ jwe.to_s.should == plain_text
176
+ end
177
+ end
178
+
179
+ shared_examples_for :gcm_decryption_unsupported do
180
+ it do
181
+ expect do
182
+ jwe.decrypt! key
183
+ end.to raise_error JSON::JWE::UnexpectedAlgorithm
184
+ end
185
+ end
186
+
187
+ context 'when alg=RSA1_5' do
188
+ let(:alg) { :RSA1_5 }
189
+ let(:key) { private_key }
190
+
191
+ context 'when enc=A128GCM' do
192
+ let(:enc) { :A128GCM }
193
+ if gcm_supported?
194
+ it_behaves_like :decryptable
195
+ else
196
+ it_behaves_like :gcm_decryption_unsupported
197
+ end
198
+ end
199
+
200
+ context 'when enc=A256GCM' do
201
+ let(:enc) { :A256GCM }
202
+ if gcm_supported?
203
+ it_behaves_like :decryptable
204
+ else
205
+ it_behaves_like :gcm_decryption_unsupported
206
+ end
207
+ end
208
+
209
+ context 'when enc=A128CBC+HS256' do
210
+ let(:enc) { :'A128CBC+HS256' }
211
+ it_behaves_like :decryptable
212
+ end
213
+
214
+ context 'when enc=A256CBC+HS512' do
215
+ let(:enc) { :'A256CBC+HS512' }
216
+ it_behaves_like :decryptable
217
+ end
218
+ end
219
+
220
+ context 'when alg=RSA-OAEP' do
221
+ let(:alg) { :'RSA-OAEP' }
222
+ let(:key) { private_key }
223
+
224
+ context 'when enc=A128GCM' do
225
+ let(:enc) { :A128GCM }
226
+ if gcm_supported?
227
+ it_behaves_like :decryptable
228
+ else
229
+ it_behaves_like :gcm_decryption_unsupported
230
+ end
231
+ end
232
+
233
+ context 'when enc=A256GCM' do
234
+ let(:enc) { :A256GCM }
235
+ if gcm_supported?
236
+ it_behaves_like :decryptable
237
+ else
238
+ it_behaves_like :gcm_decryption_unsupported
239
+ end
240
+ end
241
+
242
+ context 'when enc=A128CBC+HS256' do
243
+ let(:enc) { :'A128CBC+HS256' }
244
+ it_behaves_like :decryptable
245
+ end
246
+
247
+ context 'when enc=A256CBC+HS512' do
248
+ let(:enc) { :'A256CBC+HS512' }
249
+ it_behaves_like :decryptable
250
+ end
251
+ end
252
+
253
+ context 'when alg=dir' do
254
+ let(:alg) { :dir }
255
+ let(:key) { 'todo' }
256
+ it :TODO
257
+ end
258
+ end
157
259
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json-jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - nov matake
@@ -135,7 +135,6 @@ files:
135
135
  - .rspec
136
136
  - .travis.yml
137
137
  - Gemfile
138
- - Gemfile.lock
139
138
  - LICENSE
140
139
  - README.rdoc
141
140
  - Rakefile
@@ -182,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
182
181
  version: '0'
183
182
  requirements: []
184
183
  rubyforge_project:
185
- rubygems_version: 2.0.0
184
+ rubygems_version: 2.0.3
186
185
  signing_key:
187
186
  specification_version: 4
188
187
  summary: JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and
@@ -205,4 +204,3 @@ test_files:
205
204
  - spec/json/jws_spec.rb
206
205
  - spec/json/jwt_spec.rb
207
206
  - spec/spec_helper.rb
208
- has_rdoc:
data/Gemfile.lock DELETED
@@ -1,44 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- json-jwt (0.4.3)
5
- activesupport (>= 2.3)
6
- i18n
7
- multi_json (>= 1.3)
8
- url_safe_base64
9
-
10
- GEM
11
- remote: http://rubygems.org/
12
- specs:
13
- activesupport (3.2.12)
14
- i18n (~> 0.6)
15
- multi_json (~> 1.0)
16
- configatron (2.10.0)
17
- yamler (>= 0.1.0)
18
- cover_me (1.2.0)
19
- configatron
20
- hashie
21
- diff-lcs (1.2.1)
22
- hashie (2.0.2)
23
- i18n (0.6.4)
24
- multi_json (1.6.1)
25
- rake (10.0.3)
26
- rspec (2.13.0)
27
- rspec-core (~> 2.13.0)
28
- rspec-expectations (~> 2.13.0)
29
- rspec-mocks (~> 2.13.0)
30
- rspec-core (2.13.0)
31
- rspec-expectations (2.13.0)
32
- diff-lcs (>= 1.1.3, < 2.0)
33
- rspec-mocks (2.13.0)
34
- url_safe_base64 (0.2.1)
35
- yamler (0.1.0)
36
-
37
- PLATFORMS
38
- ruby
39
-
40
- DEPENDENCIES
41
- cover_me (>= 1.2.0)
42
- json-jwt!
43
- rake (>= 0.8)
44
- rspec (>= 2)