jwe 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fa8fe82eeb7d259a610ce7e6a89374a8d5cd7ff2
4
- data.tar.gz: 0a1a8862400049ee407852f0e21cbb0cb6a8210b
3
+ metadata.gz: 05c87a9be4e5864d4f31495bd609ff3d4abf1a68
4
+ data.tar.gz: dc5edbbac44a91be23673da3f5d0b2beb91a8245
5
5
  SHA512:
6
- metadata.gz: 40e851c53020b8c790080090ba7ca53e9e4264a5bcb990dd78598d2b0109ca5fe83e77fe2a3ae40c2ee5fcf75265e6074985f1038ef5ebd4003df8fa23fc5b59
7
- data.tar.gz: f01772b4e6dc52ccded47081617c2890d21faf017b00ee285e525138e7d65765d9b2e38889b391159cf876e20328e81423afdf0123bcdd9497cc6581d4ad5478
6
+ metadata.gz: a26d929b4124949bbac9137855a32b42a9ab9165c0025e405e924937e99c9222e88096a1d5e40c93360f4e491df4f43ebe80a4f6d9fe0bba8bc34b9d10a94d99
7
+ data.tar.gz: b3e9575add99b0ad449c083a3981d419aaeaf17748591f00e293fcb61e556257b2b371af2c13c7ce8f294cfe72ec39d0f5cac7d6f2b46dd2c2864045410962dc
data/README.md CHANGED
@@ -84,9 +84,9 @@ Key management:
84
84
  * RSA1_5
85
85
  * RSA-OAEP (default)
86
86
  * ~~RSA-OAEP-256~~
87
- * ~~A128KW~~
88
- * ~~A192KW~~
89
- * ~~A256KW~~
87
+ * A128KW
88
+ * A192KW
89
+ * A256KW
90
90
  * dir
91
91
  * ~~ECDH-ES~~
92
92
  * ~~ECDH-ES+A128KW~~
@@ -1,3 +1,4 @@
1
+ require 'jwe/alg/a128_kw'
1
2
  require 'jwe/alg/dir'
2
3
  require 'jwe/alg/rsa_oaep'
3
4
  require 'jwe/alg/rsa15'
@@ -0,0 +1,13 @@
1
+ require 'jwe/alg/aes_kw'
2
+
3
+ module JWE
4
+ module Alg
5
+ class A128Kw
6
+ include AesKw
7
+
8
+ def cipher_name
9
+ 'AES-128-ECB'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'jwe/alg/aes_kw'
2
+
3
+ module JWE
4
+ module Alg
5
+ class A192Kw
6
+ include AesKw
7
+
8
+ def cipher_name
9
+ 'AES-192-ECB'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'jwe/alg/aes_kw'
2
+
3
+ module JWE
4
+ module Alg
5
+ class A256Kw
6
+ include AesKw
7
+
8
+ def cipher_name
9
+ 'AES-256-ECB'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,84 @@
1
+ module JWE
2
+ module Alg
3
+ module AesKw
4
+ attr_accessor :key
5
+ attr_accessor :iv
6
+
7
+ def initialize(key = nil, iv = "\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6")
8
+ self.iv = iv.force_encoding('ASCII-8BIT')
9
+ self.key = key.force_encoding('ASCII-8BIT')
10
+ end
11
+
12
+ def encrypt(cek)
13
+ a = iv
14
+ r = cek.scan(/.{8}/m)
15
+
16
+ 6.times do |j|
17
+ r.length.times do |i|
18
+ b = encrypt_round(a + r[i])
19
+
20
+ a = b.chars.first(8).join
21
+ r[i] = b.chars.last(8).join
22
+
23
+ t = (r.length * j) + i + 1
24
+ a = xor(a, t)
25
+ end
26
+ end
27
+
28
+ ([a] + r).join
29
+ end
30
+
31
+ def decrypt(encrypted_cek)
32
+ c = encrypted_cek.scan(/.{8}/m)
33
+ a = c[0]
34
+
35
+ r = c[1..c.length]
36
+
37
+ 5.downto(0) do |j|
38
+ r.length.downto(1) do |i|
39
+ t = (r.length * j) + i
40
+ a = xor(a, t)
41
+
42
+ b = decrypt_round(a + r[i - 1])
43
+
44
+ a = b.chars.first(8).join
45
+ r[i - 1] = b.chars.last(8).join
46
+ end
47
+ end
48
+
49
+ if a != iv
50
+ raise StandardError.new('The encrypted key has been tampered. Do not use this key.')
51
+ end
52
+
53
+ r.join
54
+ end
55
+
56
+ def cipher
57
+ @cipher ||= OpenSSL::Cipher.new(cipher_name)
58
+ rescue RuntimeError
59
+ raise JWE::NotImplementedError.new("The version of OpenSSL linked to your Ruby does not support the cipher #{cipher_name}.")
60
+ end
61
+
62
+ def encrypt_round(data)
63
+ cipher.encrypt
64
+ cipher.key = key
65
+ cipher.padding = 0
66
+ cipher.update(data) + cipher.final
67
+ end
68
+
69
+ def decrypt_round(data)
70
+ cipher.decrypt
71
+ cipher.key = key
72
+ cipher.padding = 0
73
+ cipher.update(data) + cipher.final
74
+ end
75
+
76
+ def xor(data, t)
77
+ t = ([0] * (data.length - 1)) + [t]
78
+ data = data.chars.map(&:ord)
79
+
80
+ data.zip(t).map { |a, b| (a ^ b).chr }.join
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,3 +1,3 @@
1
1
  module JWE
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '0.3.0'.freeze
3
3
  end
@@ -4,11 +4,19 @@ module JWE
4
4
  module Zip
5
5
  class Def
6
6
  def compress(payload)
7
- Zlib::Deflate.deflate(payload)
7
+ zlib = Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION, -Zlib::MAX_WBITS)
8
+ zlib.deflate(payload)
9
+ zlib.finish
8
10
  end
9
11
 
12
+ # Was using RFC 1950 instead of 1951.
10
13
  def decompress(payload)
11
14
  Zlib::Inflate.inflate(payload)
15
+
16
+ # Keeping compatibility for old encoded tokens
17
+ rescue Zlib::DataError
18
+ inflate = Zlib::Inflate.new(-Zlib::MAX_WBITS)
19
+ inflate.inflate(payload)
12
20
  end
13
21
  end
14
22
  end
@@ -1,6 +1,9 @@
1
1
  require 'jwe/alg/dir'
2
2
  require 'jwe/alg/rsa_oaep'
3
3
  require 'jwe/alg/rsa15'
4
+ require 'jwe/alg/a128_kw'
5
+ require 'jwe/alg/a192_kw'
6
+ require 'jwe/alg/a256_kw'
4
7
  require 'openssl'
5
8
 
6
9
  describe JWE::Alg do
@@ -64,3 +67,34 @@ describe JWE::Alg::Rsa15 do
64
67
  expect(alg.decrypt(ciphertext)).to eq 'random key'
65
68
  end
66
69
  end
70
+
71
+ [
72
+ JWE::Alg::A128Kw,
73
+ JWE::Alg::A192Kw,
74
+ JWE::Alg::A256Kw
75
+ ].each_with_index do |klass, i|
76
+ describe klass do
77
+ let(:kek) { SecureRandom.random_bytes(16 + i * 8) }
78
+ let(:cek) { SecureRandom.random_bytes(32) }
79
+ let(:alg) { klass.new(kek) }
80
+
81
+ describe '#encrypt' do
82
+ it 'returns an encrypted string' do
83
+ expect(alg.encrypt(cek)).to_not eq cek
84
+ end
85
+ end
86
+
87
+ it 'decrypts the encrypted key to the original key' do
88
+ ciphertext = alg.encrypt(cek)
89
+ expect(alg.decrypt(ciphertext)).to eq cek
90
+ end
91
+
92
+ it 'raises when trying to decrypt tampered keys' do
93
+ alg = klass.new(kek, "\xA7\xA7\xA7\xA7\xA6\xA6\xA6\xA6")
94
+ ciphertext = alg.encrypt(cek)
95
+
96
+ bad_alg = klass.new(kek, "\xA7\xA7\xA7\xA7\xA7\xA7\xA7\xA7")
97
+ expect { bad_alg.decrypt(ciphertext) }.to raise_error(StandardError)
98
+ end
99
+ end
100
+ end
@@ -18,4 +18,10 @@ describe JWE::Zip::Def do
18
18
  deflated = deflate.compress('hello world')
19
19
  expect(deflate.decompress(deflated)).to eq 'hello world'
20
20
  end
21
+
22
+ it 'can deflate an RFC 1950 compressed message' do
23
+ deflated = Zlib::Deflate.deflate('hello world')
24
+ deflate = JWE::Zip::Def.new
25
+ expect(deflate.decompress(deflated)).to eq 'hello world'
26
+ end
21
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francesco Boffa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-02 00:00:00.000000000 Z
11
+ date: 2017-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -70,6 +70,10 @@ files:
70
70
  - jwe.gemspec
71
71
  - lib/jwe.rb
72
72
  - lib/jwe/alg.rb
73
+ - lib/jwe/alg/a128_kw.rb
74
+ - lib/jwe/alg/a192_kw.rb
75
+ - lib/jwe/alg/a256_kw.rb
76
+ - lib/jwe/alg/aes_kw.rb
73
77
  - lib/jwe/alg/dir.rb
74
78
  - lib/jwe/alg/rsa15.rb
75
79
  - lib/jwe/alg/rsa_oaep.rb