jwe 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +13 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +3 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE.md +24 -0
- data/Rakefile +7 -0
- data/jwe.gemspec +21 -0
- data/lib/jwe.rb +64 -0
- data/lib/jwe/alg.rb +16 -0
- data/lib/jwe/alg/dir.rb +19 -0
- data/lib/jwe/alg/rsa15.rb +19 -0
- data/lib/jwe/alg/rsa_oaep.rb +19 -0
- data/lib/jwe/base64.rb +16 -0
- data/lib/jwe/enc.rb +19 -0
- data/lib/jwe/enc/a128cbc_hs256.rb +21 -0
- data/lib/jwe/enc/a128gcm.rb +17 -0
- data/lib/jwe/enc/a192cbc_hs384.rb +21 -0
- data/lib/jwe/enc/a192gcm.rb +17 -0
- data/lib/jwe/enc/a256cbc_hs512.rb +21 -0
- data/lib/jwe/enc/a256gcm.rb +17 -0
- data/lib/jwe/enc/aes_cbc_hs.rb +89 -0
- data/lib/jwe/enc/aes_gcm.rb +73 -0
- data/lib/jwe/serialization/compact.rb +18 -0
- data/lib/jwe/version.rb +4 -0
- data/lib/jwe/zip.rb +14 -0
- data/lib/jwe/zip/def.rb +15 -0
- data/spec/jwe/alg_spec.rb +66 -0
- data/spec/jwe/base64_spec.rb +27 -0
- data/spec/jwe/enc_spec.rb +211 -0
- data/spec/jwe/serialization_spec.rb +18 -0
- data/spec/jwe/zip_spec.rb +21 -0
- data/spec/jwe_spec.rb +60 -0
- data/spec/keys/rsa.pem +27 -0
- data/spec/spec_helper.rb +9 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cb166f2f458cf97d14cdee1860f05aeaa53c5cfd
|
4
|
+
data.tar.gz: bd0dbea752a5d38424cd4b45b1f03e2fe85ae550
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 775afd82c19c9501a6534c313cdd50bfda73397b8720d79d924efc3632d86de893b344d37e383d0755f5f5499f33166ae074f41803cc11008e924b8d592708df
|
7
|
+
data.tar.gz: ffb94097e58257985a0d6334628a2bfa42217e36020a060ea621c49313364067505241d2b163f76027311c5f4071152b11696d5a095de8a083e90cdcbbb14184
|
data/.codeclimate.yml
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
=====================
|
3
|
+
|
4
|
+
* Copyright © 2016 Francesco Boffa
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
20
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
21
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
22
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
23
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
|
data/Rakefile
ADDED
data/jwe.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
lib = File.expand_path('../lib/', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'jwe/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'jwe'
|
7
|
+
s.version = JWE::VERSION
|
8
|
+
s.summary = 'JSON Web Encryption implementation in Ruby'
|
9
|
+
s.description = 'A Ruby implementation of the RFC 7516 JSON Web Encryption (JWE) standard'
|
10
|
+
s.authors = [ 'Francesco Boffa' ]
|
11
|
+
s.email = 'fra.boffa@gmail.com'
|
12
|
+
s.homepage = 'http://github.com/aomega08/jwe'
|
13
|
+
s.license = 'MIT'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.require_paths = %w(lib)
|
17
|
+
|
18
|
+
s.add_development_dependency 'rspec'
|
19
|
+
s.add_development_dependency 'rake'
|
20
|
+
s.add_development_dependency 'codeclimate-test-reporter'
|
21
|
+
end
|
data/lib/jwe.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'json'
|
3
|
+
require 'openssl'
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
require 'jwe/base64'
|
7
|
+
require 'jwe/serialization/compact'
|
8
|
+
require 'jwe/alg'
|
9
|
+
require 'jwe/enc'
|
10
|
+
require 'jwe/zip'
|
11
|
+
|
12
|
+
module JWE
|
13
|
+
class DecodeError < Exception; end
|
14
|
+
class NotImplementedError < Exception; end
|
15
|
+
class BadCEK < Exception; end
|
16
|
+
class InvalidData < Exception; end
|
17
|
+
|
18
|
+
VALID_ALG = [ 'RSA1_5', 'RSA-OAEP', 'RSA-OAEP-256', 'A128KW' 'A192KW', 'A256KW', 'dir', 'ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW', 'A128GCMKW', 'A192GCMKW', 'A256GCMKW', 'PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW' ]
|
19
|
+
VALID_ENC = [ 'A128CBC-HS256', 'A192CBC-HS384', 'A256CBC-HS512', 'A128GCM', 'A192GCM', 'A256GCM' ]
|
20
|
+
VALID_ZIP = [ 'DEF' ]
|
21
|
+
|
22
|
+
def self.encrypt(payload, key, alg: 'RSA-OAEP', enc: 'A128GCM', zip: nil)
|
23
|
+
raise ArgumentError.new("\"#{alg}\" is not a valid alg method") unless VALID_ALG.include?(alg)
|
24
|
+
raise ArgumentError.new("\"#{enc}\" is not a valid enc method") unless VALID_ENC.include?(enc)
|
25
|
+
raise ArgumentError.new("\"#{zip}\" is not a valid zip method") unless zip.nil? || zip == '' || VALID_ZIP.include?(zip)
|
26
|
+
|
27
|
+
header = { alg: alg, enc: enc }
|
28
|
+
header[:zip] = zip if zip and zip != ''
|
29
|
+
|
30
|
+
cipher = Enc.for(enc).new
|
31
|
+
cipher.cek = key if alg == 'dir'
|
32
|
+
|
33
|
+
if zip and zip != ''
|
34
|
+
payload = Zip.for(zip).new.compress(payload)
|
35
|
+
end
|
36
|
+
|
37
|
+
ciphertext = cipher.encrypt(payload, Base64::jwe_encode(header.to_json))
|
38
|
+
encrypted_cek = Alg.for(alg).new(key).encrypt(cipher.cek)
|
39
|
+
|
40
|
+
Serialization::Compact.encode(header.to_json, encrypted_cek, cipher.iv, ciphertext, cipher.tag)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.decrypt(payload, key)
|
44
|
+
header, enc_key, iv, ciphertext, tag = Serialization::Compact.decode(payload)
|
45
|
+
header = JSON.parse(header)
|
46
|
+
base64header = payload.split('.').first
|
47
|
+
|
48
|
+
raise ArgumentError.new("\"#{header['alg']}\" is not a valid alg method") unless VALID_ALG.include?(header['alg'])
|
49
|
+
raise ArgumentError.new("\"#{header['enc']}\" is not a valid enc method") unless VALID_ENC.include?(header['enc'])
|
50
|
+
raise ArgumentError.new("\"#{header['zip']}\" is not a valid zip method") unless header['zip'].nil? || VALID_ZIP.include?(header['zip'])
|
51
|
+
|
52
|
+
cek = Alg.for(header['alg']).new(key).decrypt(enc_key)
|
53
|
+
cipher = Enc.for(header['enc']).new(cek, iv)
|
54
|
+
cipher.tag = tag
|
55
|
+
|
56
|
+
plaintext = cipher.decrypt(ciphertext, base64header)
|
57
|
+
|
58
|
+
if header['zip']
|
59
|
+
Zip.for(header['zip']).new.decompress(plaintext)
|
60
|
+
else
|
61
|
+
plaintext
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/jwe/alg.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'jwe/alg/dir'
|
2
|
+
require 'jwe/alg/rsa_oaep'
|
3
|
+
require 'jwe/alg/rsa15'
|
4
|
+
|
5
|
+
module JWE
|
6
|
+
module Alg
|
7
|
+
def self.for(alg)
|
8
|
+
klass = alg.gsub(/[-\+]/, '_').downcase.sub(/^[a-z\d]*/) { $&.capitalize }
|
9
|
+
klass.gsub!(/_([a-z\d]*)/i) { $1.capitalize }
|
10
|
+
const_get(klass)
|
11
|
+
|
12
|
+
rescue NameError
|
13
|
+
raise NotImplementedError.new("Unsupported alg type: #{alg}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/jwe/alg/dir.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module JWE
|
2
|
+
module Alg
|
3
|
+
class Rsa15
|
4
|
+
attr_accessor :key
|
5
|
+
|
6
|
+
def initialize(key)
|
7
|
+
self.key = key
|
8
|
+
end
|
9
|
+
|
10
|
+
def encrypt(cek)
|
11
|
+
key.public_encrypt(cek)
|
12
|
+
end
|
13
|
+
|
14
|
+
def decrypt(encrypted_cek)
|
15
|
+
key.private_decrypt(encrypted_cek)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module JWE
|
2
|
+
module Alg
|
3
|
+
class RsaOaep
|
4
|
+
attr_accessor :key
|
5
|
+
|
6
|
+
def initialize(key)
|
7
|
+
self.key = key
|
8
|
+
end
|
9
|
+
|
10
|
+
def encrypt(cek)
|
11
|
+
key.public_encrypt(cek, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
|
12
|
+
end
|
13
|
+
|
14
|
+
def decrypt(encrypted_cek)
|
15
|
+
key.private_decrypt(encrypted_cek, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/jwe/base64.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module JWE
|
2
|
+
module Base64
|
3
|
+
def self.jwe_encode(payload)
|
4
|
+
::Base64.urlsafe_encode64(payload).gsub('=', '')
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.jwe_decode(payload)
|
8
|
+
padlen = 4 - (payload.length % 4)
|
9
|
+
if padlen < 4
|
10
|
+
pad = "=" * padlen
|
11
|
+
payload += pad
|
12
|
+
end
|
13
|
+
::Base64.urlsafe_decode64(payload)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/jwe/enc.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'jwe/enc/a128cbc_hs256'
|
2
|
+
require 'jwe/enc/a192cbc_hs384'
|
3
|
+
require 'jwe/enc/a256cbc_hs512'
|
4
|
+
require 'jwe/enc/a128gcm'
|
5
|
+
require 'jwe/enc/a192gcm'
|
6
|
+
require 'jwe/enc/a256gcm'
|
7
|
+
|
8
|
+
module JWE
|
9
|
+
module Enc
|
10
|
+
def self.for(enc)
|
11
|
+
klass = enc.gsub(/[-\+]/, '_').downcase.sub(/^[a-z\d]*/) { $&.capitalize }
|
12
|
+
klass.gsub!(/_([a-z\d]*)/i) { $1.capitalize }
|
13
|
+
const_get(klass)
|
14
|
+
|
15
|
+
rescue NameError
|
16
|
+
raise NotImplementedError.new("Unsupported enc type: #{enc}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module JWE
|
2
|
+
module Enc
|
3
|
+
module AesCbcHs
|
4
|
+
attr_accessor :cek
|
5
|
+
attr_accessor :iv
|
6
|
+
attr_accessor :tag
|
7
|
+
|
8
|
+
def initialize(cek = nil, iv = nil)
|
9
|
+
self.iv = iv
|
10
|
+
self.cek = cek
|
11
|
+
end
|
12
|
+
|
13
|
+
def encrypt(cleartext, authenticated_data)
|
14
|
+
raise JWE::BadCEK.new("The supplied key is invalid. Required length: #{key_length}") if cek.length != key_length
|
15
|
+
|
16
|
+
cipher.encrypt
|
17
|
+
cipher.key = enc_key
|
18
|
+
cipher.iv = iv
|
19
|
+
|
20
|
+
ciphertext = cipher.update(cleartext) + cipher.final
|
21
|
+
length = [ciphertext.length * 8].pack('Q>') # 64bit big endian
|
22
|
+
|
23
|
+
to_sign = authenticated_data + iv + ciphertext + length
|
24
|
+
signature = OpenSSL::HMAC.digest(OpenSSL::Digest.new(hash_name), mac_key, to_sign)
|
25
|
+
self.tag = signature[0 ... mac_key.length]
|
26
|
+
|
27
|
+
ciphertext
|
28
|
+
end
|
29
|
+
|
30
|
+
def decrypt(ciphertext, authenticated_data)
|
31
|
+
raise JWE::BadCEK.new("The supplied key is invalid. Required length: #{key_length}") if cek.length != key_length
|
32
|
+
|
33
|
+
length = [ciphertext.length * 8].pack('Q>') # 64bit big endian
|
34
|
+
to_sign = authenticated_data + iv + ciphertext + length
|
35
|
+
signature = OpenSSL::HMAC.digest(OpenSSL::Digest.new(hash_name), mac_key, to_sign)
|
36
|
+
if signature[0 ... mac_key.length] != tag
|
37
|
+
raise JWE::InvalidData.new("Authentication tag verification failed")
|
38
|
+
end
|
39
|
+
|
40
|
+
cipher.decrypt
|
41
|
+
cipher.key = enc_key
|
42
|
+
cipher.iv = iv
|
43
|
+
|
44
|
+
cipher.update(ciphertext) + cipher.final
|
45
|
+
rescue OpenSSL::Cipher::CipherError
|
46
|
+
raise JWE::InvalidData.new("Invalid ciphertext or authentication tag")
|
47
|
+
end
|
48
|
+
|
49
|
+
def iv
|
50
|
+
@iv ||= SecureRandom.random_bytes(16)
|
51
|
+
end
|
52
|
+
|
53
|
+
def cek
|
54
|
+
@cek ||= SecureRandom.random_bytes(key_length)
|
55
|
+
end
|
56
|
+
|
57
|
+
def mac_key
|
58
|
+
cek[0 ... key_length / 2]
|
59
|
+
end
|
60
|
+
|
61
|
+
def enc_key
|
62
|
+
cek[key_length / 2 .. -1 ]
|
63
|
+
end
|
64
|
+
|
65
|
+
def cipher
|
66
|
+
@cipher ||= OpenSSL::Cipher.new(cipher_name)
|
67
|
+
rescue RuntimeError
|
68
|
+
raise JWE::NotImplementedError.new("The version of OpenSSL linked to your Ruby does not support the cipher #{cipher_name}.")
|
69
|
+
end
|
70
|
+
|
71
|
+
def tag
|
72
|
+
@tag || ""
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.included(base)
|
76
|
+
base.extend(ClassMethods)
|
77
|
+
end
|
78
|
+
|
79
|
+
module ClassMethods
|
80
|
+
def available?
|
81
|
+
new.cipher
|
82
|
+
true
|
83
|
+
rescue JWE::NotImplementedError
|
84
|
+
false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module JWE
|
2
|
+
module Enc
|
3
|
+
module AesGcm
|
4
|
+
attr_accessor :cek
|
5
|
+
attr_accessor :iv
|
6
|
+
attr_accessor :tag
|
7
|
+
|
8
|
+
def initialize(cek = nil, iv = nil)
|
9
|
+
self.iv = iv
|
10
|
+
self.cek = cek
|
11
|
+
end
|
12
|
+
|
13
|
+
def encrypt(cleartext, authenticated_data)
|
14
|
+
raise JWE::BadCEK.new("The supplied key is too short. Required length: #{key_length}") if cek.length < key_length
|
15
|
+
|
16
|
+
cipher.encrypt
|
17
|
+
cipher.key = cek
|
18
|
+
cipher.iv = iv
|
19
|
+
cipher.auth_data = authenticated_data
|
20
|
+
|
21
|
+
ciphertext = cipher.update(cleartext) + cipher.final
|
22
|
+
self.tag = cipher.auth_tag
|
23
|
+
|
24
|
+
ciphertext
|
25
|
+
end
|
26
|
+
|
27
|
+
def decrypt(ciphertext, authenticated_data)
|
28
|
+
raise JWE::BadCEK.new("The supplied key is too short. Required length: #{key_length}") if cek.length < key_length
|
29
|
+
|
30
|
+
cipher.decrypt
|
31
|
+
cipher.key = cek
|
32
|
+
cipher.iv = iv
|
33
|
+
cipher.auth_tag = tag
|
34
|
+
cipher.auth_data = authenticated_data
|
35
|
+
|
36
|
+
cipher.update(ciphertext) + cipher.final
|
37
|
+
rescue OpenSSL::Cipher::CipherError
|
38
|
+
raise JWE::InvalidData.new("Invalid ciphertext or authentication tag")
|
39
|
+
end
|
40
|
+
|
41
|
+
def iv
|
42
|
+
@iv ||= SecureRandom.random_bytes(12)
|
43
|
+
end
|
44
|
+
|
45
|
+
def cek
|
46
|
+
@cek ||= SecureRandom.random_bytes(key_length)
|
47
|
+
end
|
48
|
+
|
49
|
+
def cipher
|
50
|
+
@cipher ||= OpenSSL::Cipher.new(cipher_name)
|
51
|
+
rescue RuntimeError
|
52
|
+
raise JWE::NotImplementedError.new("The version of OpenSSL linked to your Ruby does not support the cipher #{cipher_name}.")
|
53
|
+
end
|
54
|
+
|
55
|
+
def tag
|
56
|
+
@tag || ""
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.included(base)
|
60
|
+
base.extend(ClassMethods)
|
61
|
+
end
|
62
|
+
|
63
|
+
module ClassMethods
|
64
|
+
def available?
|
65
|
+
new.cipher
|
66
|
+
true
|
67
|
+
rescue JWE::NotImplementedError
|
68
|
+
false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module JWE
|
2
|
+
module Serialization
|
3
|
+
class Compact
|
4
|
+
def self.encode(header, encrypted_cek, iv, ciphertext, tag)
|
5
|
+
[ header, encrypted_cek, iv, ciphertext, tag ].map { |piece| JWE::Base64::jwe_encode(piece) }.join '.'
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.decode(payload)
|
9
|
+
parts = payload.split('.')
|
10
|
+
raise JWE::DecodeError.new('Not enaugh or too many segments') unless parts.length == 5
|
11
|
+
|
12
|
+
parts.map do |part|
|
13
|
+
JWE::Base64.jwe_decode(part)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/jwe/version.rb
ADDED
data/lib/jwe/zip.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'jwe/zip/def'
|
2
|
+
|
3
|
+
module JWE
|
4
|
+
module Zip
|
5
|
+
def self.for(zip)
|
6
|
+
klass = zip.gsub(/[-\+]/, '_').downcase.sub(/^[a-z\d]*/) { $&.capitalize }
|
7
|
+
klass.gsub!(/_([a-z\d]*)/i) { $1.capitalize }
|
8
|
+
const_get(klass)
|
9
|
+
|
10
|
+
rescue NameError
|
11
|
+
raise NotImplementedError.new("Unsupported zip type: #{zip}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/jwe/zip/def.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'jwe/alg/dir'
|
2
|
+
require 'jwe/alg/rsa_oaep'
|
3
|
+
require 'jwe/alg/rsa15'
|
4
|
+
require 'openssl'
|
5
|
+
|
6
|
+
describe JWE::Alg do
|
7
|
+
describe '.for' do
|
8
|
+
it 'returns a class for the specified alg' do
|
9
|
+
expect(JWE::Alg.for('RSA-OAEP')).to eq JWE::Alg::RsaOaep
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'raises an error for a not-implemented alg' do
|
13
|
+
expect { JWE::Alg.for('ERSA-4096-MAGIC') }.to raise_error(JWE::NotImplementedError)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe JWE::Alg::Dir do
|
19
|
+
# The direct encryption method does not Encrypt the CEK.
|
20
|
+
# When building the final JWE object, the "Encrypted CEK" part is left blank
|
21
|
+
|
22
|
+
describe '#encrypt' do
|
23
|
+
it 'returns an empty string' do
|
24
|
+
expect(JWE::Alg::Dir.new('whatever').encrypt('any')).to eq ''
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#decrypt' do
|
29
|
+
it 'returns the original key' do
|
30
|
+
expect(JWE::Alg::Dir.new('whatever').decrypt('any')).to eq 'whatever'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
key_path = File.dirname(__FILE__) + '/../keys/rsa.pem'
|
36
|
+
key = OpenSSL::PKey::RSA.new File.read(key_path)
|
37
|
+
|
38
|
+
describe JWE::Alg::RsaOaep do
|
39
|
+
let(:alg) { JWE::Alg::RsaOaep.new(key) }
|
40
|
+
|
41
|
+
describe '#encrypt' do
|
42
|
+
it 'returns an encrypted string' do
|
43
|
+
expect(alg.encrypt('random key')).to_not eq 'random key'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'decrypts the encrypted key to the original key' do
|
48
|
+
ciphertext = alg.encrypt('random key')
|
49
|
+
expect(alg.decrypt(ciphertext)).to eq 'random key'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe JWE::Alg::Rsa15 do
|
54
|
+
let(:alg) { JWE::Alg::Rsa15.new(key) }
|
55
|
+
|
56
|
+
describe '#encrypt' do
|
57
|
+
it 'returns an encrypted string' do
|
58
|
+
expect(alg.encrypt('random key')).to_not eq 'random key'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'decrypts the encrypted key to the original key' do
|
63
|
+
ciphertext = alg.encrypt('random key')
|
64
|
+
expect(alg.decrypt(ciphertext)).to eq 'random key'
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'jwe/base64'
|
2
|
+
|
3
|
+
module JWE
|
4
|
+
describe Base64 do
|
5
|
+
describe '.jwe_encode' do
|
6
|
+
it 'encodes the payload using the urlsafe encoding' do
|
7
|
+
# "me?" encodes to "bWU/" in standard encoding
|
8
|
+
expect(Base64.jwe_encode("me?")).to_not include '/'
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'strips the standard padding' do
|
12
|
+
expect(Base64.jwe_encode("a")).to_not end_with '='
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.jwe_decode' do
|
17
|
+
it 'decodes the payload using the urlsafe encoding' do
|
18
|
+
# "me?" encodes to "bWU/" in standard encoding
|
19
|
+
expect(Base64.jwe_decode("bWU_")).to eq "me?"
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'fixes the padding' do
|
23
|
+
expect(Base64.jwe_decode("YQ")).to eq "a"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'jwe/enc/a128cbc_hs256'
|
2
|
+
require 'jwe/enc/a192cbc_hs384'
|
3
|
+
require 'jwe/enc/a256cbc_hs512'
|
4
|
+
require 'jwe/enc/a128gcm'
|
5
|
+
require 'jwe/enc/a192gcm'
|
6
|
+
require 'jwe/enc/a256gcm'
|
7
|
+
|
8
|
+
describe JWE::Enc do
|
9
|
+
describe '.for' do
|
10
|
+
it 'returns a class for the specified enc' do
|
11
|
+
expect(JWE::Enc.for('A128GCM')).to eq JWE::Enc::A128gcm
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'raises an error for a not-implemented enc' do
|
15
|
+
expect { JWE::Enc.for('ERSA-4096-MAGIC') }.to raise_error(JWE::NotImplementedError)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
gcm = [
|
21
|
+
{
|
22
|
+
class: JWE::Enc::A128gcm,
|
23
|
+
keylen: 16,
|
24
|
+
helloworld: "\"\xC6\xE4h\x8AI\x83\x90v\xAF\xE2\x11".force_encoding('BINARY'),
|
25
|
+
tag: "\x85|\xF7\xE1\x94\tVG\x84\xE1\xA8\x81\a\xF4\xC60".force_encoding('BINARY'),
|
26
|
+
ivlen: 12,
|
27
|
+
iv: "\x0" * 12
|
28
|
+
},
|
29
|
+
{
|
30
|
+
class: JWE::Enc::A192gcm,
|
31
|
+
keylen: 24,
|
32
|
+
helloworld: "\x9F\xA4\xEC\xCCa\x86\tRO\xD7\xE3\x8D".force_encoding('BINARY'),
|
33
|
+
tag: "\xF6\xC0\xB8\x91A\xB1\xF0}\xD4u\xD0_\xCD\xA7\x17'".force_encoding('BINARY'),
|
34
|
+
ivlen: 12,
|
35
|
+
iv: "\x0" * 12
|
36
|
+
},
|
37
|
+
{
|
38
|
+
class: JWE::Enc::A256gcm,
|
39
|
+
keylen: 32,
|
40
|
+
helloworld: "\xFDq\xDC\xDD\x87\x9DK\x97\x03G\x99\f".force_encoding('BINARY'),
|
41
|
+
tag: "\xC6\xF1\r\xDD\x14\x7Fqf,6\x0EK\x7F\x9D\x1D\t".force_encoding('BINARY'),
|
42
|
+
ivlen: 12,
|
43
|
+
iv: "\x0" * 12
|
44
|
+
},
|
45
|
+
{
|
46
|
+
class: JWE::Enc::A128cbcHs256,
|
47
|
+
keylen: 32,
|
48
|
+
helloworld: "\a\x02F\xA4m%\xDFH\xB4\xA4.\xBF:\xBF$\xE2".force_encoding('BINARY'),
|
49
|
+
tag: "\xD2\xC2\xA5M\xF1e\x00\xDB}\xDB\x15\x9F\xFF\x8A\x7F\x94".force_encoding('BINARY'),
|
50
|
+
ivlen: 16,
|
51
|
+
iv: "\x0" * 16
|
52
|
+
},
|
53
|
+
{
|
54
|
+
class: JWE::Enc::A192cbcHs384,
|
55
|
+
keylen: 48,
|
56
|
+
helloworld: "p\xFES\xF0\xB4\xCC]8\x1D\xDE\x8Dt\xE7tMh".force_encoding('BINARY'),
|
57
|
+
tag: "\xEA\xF4\xD73M\xC6\x1D\x13\x0E\x9E\xAE%L\xD3\x04#\x80:\xA8}\xD7\x16E{".force_encoding('BINARY'),
|
58
|
+
ivlen: 16,
|
59
|
+
iv: "\x0" * 16
|
60
|
+
},
|
61
|
+
{
|
62
|
+
class: JWE::Enc::A256cbcHs512,
|
63
|
+
keylen: 64,
|
64
|
+
helloworld: "c\xFD\\\xB9Z\xB6\xE3\xB7\xEE\xA1\xD8\xDF\xB5\xB2\xF8\xEB".force_encoding('BINARY'),
|
65
|
+
tag: "\xD2W\xCAE\xBC\xE9\xC5\xCF\xD5\xE0\x88@j\xE4\xA1-\x16\xDA\x8F5(\x1D\x0E\x15.\xDC\x11\x12\x00`\xCER".force_encoding('BINARY'),
|
66
|
+
ivlen: 16,
|
67
|
+
iv: "\x0" * 16
|
68
|
+
}
|
69
|
+
]
|
70
|
+
|
71
|
+
gcm.each do |group|
|
72
|
+
describe group[:class] do
|
73
|
+
let(:klass) { group[:class] }
|
74
|
+
let(:key) { 'a' * group[:keylen] }
|
75
|
+
let(:plaintext) { 'hello world!' }
|
76
|
+
|
77
|
+
describe '#encrypt' do
|
78
|
+
context 'when an invalid key is used' do
|
79
|
+
it 'raises an error' do
|
80
|
+
enc = klass.new('small')
|
81
|
+
expect { enc.encrypt('plain', 'auth') }.to raise_error(JWE::BadCEK)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'with a valid key' do
|
86
|
+
it 'returns the encrypted payload' do
|
87
|
+
enc = klass.new(key, group[:iv])
|
88
|
+
expect(enc.encrypt(plaintext, '').force_encoding('BINARY')).to eq group[:helloworld]
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'sets an authentication tag' do
|
92
|
+
enc = klass.new(key, group[:iv])
|
93
|
+
enc.encrypt(plaintext, '')
|
94
|
+
expect(enc.tag).to eq group[:tag]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#decrypt' do
|
100
|
+
context 'when an invalid key is used' do
|
101
|
+
it 'raises an error' do
|
102
|
+
enc = klass.new('small')
|
103
|
+
expect { enc.decrypt('plain', 'auth') }.to raise_error(JWE::BadCEK)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'with a valid key' do
|
108
|
+
context 'when a valid tag is authenticated' do
|
109
|
+
it 'returns the plaintext' do
|
110
|
+
enc = klass.new(key, group[:iv])
|
111
|
+
enc.tag = group[:tag]
|
112
|
+
expect(enc.decrypt(group[:helloworld], '')).to eq plaintext
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'when the tag is not valid' do
|
117
|
+
it 'raises an error' do
|
118
|
+
enc = klass.new(key, group[:iv])
|
119
|
+
enc.tag = "random"
|
120
|
+
expect { enc.decrypt(group[:helloworld], '') }.to raise_error(JWE::InvalidData)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'when the tag is not set' do
|
125
|
+
it 'raises an error' do
|
126
|
+
enc = klass.new(key, group[:iv])
|
127
|
+
expect { enc.decrypt(group[:helloworld], '') }.to raise_error(JWE::InvalidData)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'when the ciphertext is not valid' do
|
132
|
+
it 'raises an error' do
|
133
|
+
enc = klass.new(key, group[:iv])
|
134
|
+
enc.tag = group[:tag]
|
135
|
+
expect { enc.decrypt("random", '') }.to raise_error(JWE::InvalidData)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#cipher' do
|
142
|
+
context 'when the cipher is not supported by the OpenSSL lib' do
|
143
|
+
it 'raises an error' do
|
144
|
+
enc = klass.new
|
145
|
+
allow(enc).to receive(:cipher_name) { 'bad-cipher-128' }
|
146
|
+
expect { enc.cipher }.to raise_error(JWE::NotImplementedError)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'when the cipher is supported' do
|
151
|
+
it 'returns the cipher object' do
|
152
|
+
enc = klass.new
|
153
|
+
allow(enc).to receive(:cipher_name) { OpenSSL::Cipher.ciphers.first }
|
154
|
+
expect(enc.cipher).to be_an OpenSSL::Cipher
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe '#cek' do
|
160
|
+
context 'when a key is not specified in initialization' do
|
161
|
+
it "returns a randomly generated #{group[:keylen]}-bytes key" do
|
162
|
+
expect(klass.new.cek.length).to eq group[:keylen]
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'when a cek is given' do
|
167
|
+
it 'returns the cek' do
|
168
|
+
expect(klass.new('cek').cek).to eq 'cek'
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe '#iv' do
|
174
|
+
context 'when an iv is not specified in initialization' do
|
175
|
+
it "returns a randomly generated #{group[:ivlen]}-bytes iv" do
|
176
|
+
expect(klass.new.iv.length).to eq group[:ivlen]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'when a iv is given' do
|
181
|
+
it 'returns the iv' do
|
182
|
+
expect(klass.new('cek', 'iv').iv).to eq 'iv'
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe '.available?' do
|
188
|
+
context 'when the cipher is not available' do
|
189
|
+
it 'is false' do
|
190
|
+
allow_any_instance_of(klass).to receive(:cipher) { raise JWE::NotImplementedError.new }
|
191
|
+
expect(klass.available?).to be_falsey
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context 'when the cipher is available' do
|
196
|
+
it 'is true' do
|
197
|
+
allow_any_instance_of(klass).to receive(:cipher)
|
198
|
+
expect(klass.available?).to be_truthy
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe 'full roundtrip' do
|
204
|
+
it 'decrypts the ciphertext to the original plaintext' do
|
205
|
+
enc = klass.new
|
206
|
+
ciphertext = enc.encrypt(plaintext, '')
|
207
|
+
expect(enc.decrypt(ciphertext, '')).to eq plaintext
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
describe JWE::Serialization::Compact do
|
2
|
+
describe '#encode' do
|
3
|
+
it 'returns components base64ed and joined with a dot' do
|
4
|
+
components = [ 'a', 'b', 'c', 'd', 'e' ]
|
5
|
+
expect(JWE::Serialization::Compact.encode(*components)).to eq 'YQ.Yg.Yw.ZA.ZQ'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#decode' do
|
10
|
+
it 'returns an array with the 5 components' do
|
11
|
+
expect(JWE::Serialization::Compact.decode('YQ.Yg.Yw.ZA.ZQ')).to eq [ 'a', 'b', 'c', 'd', 'e' ]
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'raises an error when passed a badly formatted payload' do
|
15
|
+
expect { JWE::Serialization::Compact.decode('YQ.YQ.Yg.Yw.ZA.ZQ') }.to raise_error(JWE::DecodeError)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'jwe/zip/def'
|
2
|
+
|
3
|
+
describe JWE::Zip do
|
4
|
+
describe '.for' do
|
5
|
+
it 'returns a class for the specified zip' do
|
6
|
+
expect(JWE::Zip.for('DEF')).to eq JWE::Zip::Def
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'raises an error for a not-implemented zip' do
|
10
|
+
expect { JWE::Zip.for('BZIP2+JPG') }.to raise_error(JWE::NotImplementedError)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe JWE::Zip::Def do
|
16
|
+
it 'deflates and inflates to original payload' do
|
17
|
+
deflate = JWE::Zip::Def.new
|
18
|
+
deflated = deflate.compress("hello world")
|
19
|
+
expect(deflate.decompress(deflated)).to eq "hello world"
|
20
|
+
end
|
21
|
+
end
|
data/spec/jwe_spec.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
describe JWE do
|
2
|
+
let(:plaintext) { "The true sign of intelligence is not knowledge but imagination." }
|
3
|
+
let(:rsa_key) { OpenSSL::PKey::RSA.new File.read(File.dirname(__FILE__) + '/keys/rsa.pem') }
|
4
|
+
let(:password) { SecureRandom.random_bytes(64) }
|
5
|
+
|
6
|
+
it 'roundtrips' do
|
7
|
+
encrypted = JWE.encrypt(plaintext, rsa_key)
|
8
|
+
result = JWE.decrypt(encrypted, rsa_key)
|
9
|
+
|
10
|
+
expect(result).to eq plaintext
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'when using DEF compression' do
|
14
|
+
it 'roundtrips' do
|
15
|
+
encrypted = JWE.encrypt(plaintext, rsa_key, zip: 'DEF')
|
16
|
+
result = JWE.decrypt(encrypted, rsa_key)
|
17
|
+
|
18
|
+
expect(result).to eq plaintext
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'when using dir alg method' do
|
23
|
+
it 'roundtrips' do
|
24
|
+
encrypted = JWE.encrypt(plaintext, password, alg: 'dir')
|
25
|
+
result = JWE.decrypt(encrypted, password)
|
26
|
+
|
27
|
+
expect(result).to eq plaintext
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'raises when passed a bad alg' do
|
32
|
+
expect { JWE.encrypt(plaintext, rsa_key, alg: 'TEST') }.to raise_error(ArgumentError)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'raises when passed a bad enc' do
|
36
|
+
expect { JWE.encrypt(plaintext, rsa_key, enc: 'TEST') }.to raise_error(ArgumentError)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'raises when passed a bad zip' do
|
40
|
+
expect { JWE.encrypt(plaintext, rsa_key, zip: 'TEST') }.to raise_error(ArgumentError)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'raises when decoding a bad alg' do
|
44
|
+
hdr = { alg: 'TEST', enc: 'A128GCM' }
|
45
|
+
payload = JWE::Base64.jwe_encode(hdr.to_json) + ".QY.QY.QY.QY"
|
46
|
+
expect { JWE.decrypt(payload, rsa_key) }.to raise_error(ArgumentError)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'raises when decoding a bad enc' do
|
50
|
+
hdr = { alg: 'A192CBC-HS384', enc: 'TEST' }
|
51
|
+
payload = JWE::Base64.jwe_encode(hdr.to_json) + ".QY.QY.QY.QY"
|
52
|
+
expect { JWE.decrypt(payload, rsa_key) }.to raise_error(ArgumentError)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'raises when decoding a bad zip' do
|
56
|
+
hdr = { alg: 'A192CBC-HS384', enc: 'A128GCM', zip: 'TEST' }
|
57
|
+
payload = JWE::Base64.jwe_encode(hdr.to_json) + ".QY.QY.QY.QY"
|
58
|
+
expect { JWE.decrypt(payload, rsa_key) }.to raise_error(ArgumentError)
|
59
|
+
end
|
60
|
+
end
|
data/spec/keys/rsa.pem
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIIEogIBAAKCAQEAsqm+NfpjE/i27FvgfOZmoQsC8WcokDRT7pJwK6fVL8nPs1KF
|
3
|
+
0YYHgtQMtsgh2KR1Z+y6cFiiXfzbksMP7XWn5h3G9uZVzaUAz3LM07TUqSA+9dkx
|
4
|
+
/QA9Q3VWP5iNBgo59E7LqkAKIE0wfx/rzH85VUCZLFBW5tjcaxzRWyCI9RcpPwmp
|
5
|
+
LtmNqoOxdhoy4O7r1mNTrcjlh+l/4I/yavS0+TXeImvOJkIbhIJhhbjE+GDiLEH4
|
6
|
+
GxE8j2SThs1nxJtboO1MMZr9hhoHL4Z5qRu6/t+ckO9ONYwUu8eDwQCOsluXsAoe
|
7
|
+
CdprYk92M/bvfhtV/C37AUZ6iZUFCS0/FE/VrQIDAQABAoIBAGL+jKdqAmX5hJm4
|
8
|
+
Ws25+Bm5eTr7Ns2YQP1K5J4703M0NkKdMgqjYhwKlLTedWqNzYP09mTzp5u+VIeg
|
9
|
+
T336mDp4O1toyxg0GhvX90hCxSak+F3Op9UQweFT7aM1SsaS+gO1eUHvU+0L+Bgo
|
10
|
+
PsZDpCfpsDWOmmg0twUepZ4BjAGIk8wBPA+cWi8Vmbvnwrwo1643LvtA3p76qUwJ
|
11
|
+
EPllQMmEnJ6gUNxQVgqQt/QM0UKPtZ5FyOK3zPcztY5xVO3SJCVvcKkciDo2M7wp
|
12
|
+
x9qkRrnBYmouNaQjZJZLHKngHr0DF16sw3ajk8qBZW3d2O72loiOxzAhMmnzm68f
|
13
|
+
dDHGNd0CgYEA2JueNMglqYWwOBQipboSMrDprSVR2We19Ji3VS1nXV+tvLsMyspq
|
14
|
+
YinH0SkW/xbLnpsOr9yC9jkW0KwFFqPK7TXnrXTVs3a4nAAaDyG8ciZQB2nKSRHt
|
15
|
+
H8DrM4IvIa1wU+mxj/Kdkp1L8dD6LLoLpmMsnxpjcvATImuZd5KqInsCgYEA0yeR
|
16
|
+
frrx8fOMo40WVVpinxxqycIHIBeI/jHeiwU8kGilQJcrWw3VxpoJriuLsNW2HWR+
|
17
|
+
nYz3Th6/FrJv6qhzwTFkgoqRS2Tw7qP+4gxk75hUR0M2a5d4Z0fjltQHaoP+P0kj
|
18
|
+
5iPgshDFDmRcMEPUFx+KtI+g59bTlo6U0gmJY/cCgYBiy/gJExE6lSOfMG/tL0WF
|
19
|
+
oXOz6cW/Z7JycgWM8DypNi7EWnynMlP7mhrtp9Q5XWhaW1cDl4yUSc3CN/PKM8Mn
|
20
|
+
FuMpFpUyWgAyB0nbhQOy/Q6bkwEU+vww84lT4RkmPzlwzLKUeZCtgtlU3oB9Tg5q
|
21
|
+
QenkV+DsV9wiYvmItHitaQKBgFNbe4ScKIdrrkmimP55ABXwEfg0MLvqjppK9Z/M
|
22
|
+
IWyg4xvskaEQhSQyC0BG0I6uz4Yq9hEcZUThvm4nYycv+QJ7jUI7kcBByRtsgmKa
|
23
|
+
of40FJFNZ15yHYYoSyBv872I/gXdyd5Aq6OgGyrjU8F6BXBbc1Z0nQDpPf5hqz5/
|
24
|
+
pU1hAoGAWLjOMTJCFoOOxtdZ39oJmSDN0hImu+KtYWAxa4BmBDimLxwa1Xn4qEsn
|
25
|
+
THDodsfMJc7HxYfeyzFZoqjf7vm2Et9eI+/PjT1CQx3DTYxsjk+8BaMqG6p/49Qr
|
26
|
+
//JbxdDS735BW/A5rU4TEiJfcV66lT7gI8lL8cFsV1rYPMJWkqc=
|
27
|
+
-----END RSA PRIVATE KEY-----
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jwe
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Francesco Boffa
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: codeclimate-test-reporter
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: A Ruby implementation of the RFC 7516 JSON Web Encryption (JWE) standard
|
56
|
+
email: fra.boffa@gmail.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- ".codeclimate.yml"
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".rubocop.yml"
|
65
|
+
- ".travis.yml"
|
66
|
+
- Gemfile
|
67
|
+
- LICENSE.md
|
68
|
+
- Rakefile
|
69
|
+
- jwe.gemspec
|
70
|
+
- lib/jwe.rb
|
71
|
+
- lib/jwe/alg.rb
|
72
|
+
- lib/jwe/alg/dir.rb
|
73
|
+
- lib/jwe/alg/rsa15.rb
|
74
|
+
- lib/jwe/alg/rsa_oaep.rb
|
75
|
+
- lib/jwe/base64.rb
|
76
|
+
- lib/jwe/enc.rb
|
77
|
+
- lib/jwe/enc/a128cbc_hs256.rb
|
78
|
+
- lib/jwe/enc/a128gcm.rb
|
79
|
+
- lib/jwe/enc/a192cbc_hs384.rb
|
80
|
+
- lib/jwe/enc/a192gcm.rb
|
81
|
+
- lib/jwe/enc/a256cbc_hs512.rb
|
82
|
+
- lib/jwe/enc/a256gcm.rb
|
83
|
+
- lib/jwe/enc/aes_cbc_hs.rb
|
84
|
+
- lib/jwe/enc/aes_gcm.rb
|
85
|
+
- lib/jwe/serialization/compact.rb
|
86
|
+
- lib/jwe/version.rb
|
87
|
+
- lib/jwe/zip.rb
|
88
|
+
- lib/jwe/zip/def.rb
|
89
|
+
- spec/jwe/alg_spec.rb
|
90
|
+
- spec/jwe/base64_spec.rb
|
91
|
+
- spec/jwe/enc_spec.rb
|
92
|
+
- spec/jwe/serialization_spec.rb
|
93
|
+
- spec/jwe/zip_spec.rb
|
94
|
+
- spec/jwe_spec.rb
|
95
|
+
- spec/keys/rsa.pem
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
homepage: http://github.com/aomega08/jwe
|
98
|
+
licenses:
|
99
|
+
- MIT
|
100
|
+
metadata: {}
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 2.4.5.1
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: JSON Web Encryption implementation in Ruby
|
121
|
+
test_files: []
|