sandal 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/CHANGELOG.md +14 -0
- data/README.md +1 -1
- data/lib/sandal.rb +77 -76
- data/lib/sandal/claims.rb +13 -13
- data/lib/sandal/enc.rb +15 -49
- data/lib/sandal/enc/acbc_hs.rb +97 -52
- data/lib/sandal/enc/agcm.rb +64 -26
- data/lib/sandal/enc/alg.rb +2 -3
- data/lib/sandal/enc/alg/direct.rb +27 -25
- data/lib/sandal/enc/alg/rsa.rb +82 -0
- data/lib/sandal/sig.rb +12 -12
- data/lib/sandal/sig/es.rb +43 -25
- data/lib/sandal/sig/hs.rb +21 -8
- data/lib/sandal/sig/rs.rb +34 -23
- data/lib/sandal/util.rb +7 -7
- data/lib/sandal/version.rb +1 -1
- data/spec/helper.rb +1 -0
- data/spec/sample_keys.rb +28 -0
- data/spec/sandal/claims_spec.rb +4 -4
- data/spec/sandal/enc/a128cbc_hs256_spec.rb +15 -39
- data/spec/sandal/enc/a128gcm_spec.rb +13 -6
- data/spec/sandal/enc/a256cbc_hs512_spec.rb +13 -4
- data/spec/sandal/enc/a256gcm_spec.rb +15 -37
- data/spec/sandal/enc/alg/direct_spec.rb +27 -33
- data/spec/sandal/enc/alg/rsa_spec.rb +100 -0
- data/spec/sandal/enc/shared_examples.rb +93 -21
- data/spec/sandal/sig/es_spec.rb +145 -188
- data/spec/sandal/sig/hs_spec.rb +73 -18
- data/spec/sandal/sig/rs_spec.rb +81 -78
- metadata +7 -6
- data/lib/sandal/enc/alg/rsa1_5.rb +0 -47
- data/lib/sandal/enc/alg/rsa_oaep.rb +0 -48
- data/spec/sandal/enc/alg/rsa1_5_spec.rb +0 -40
data/spec/sandal/claims_spec.rb
CHANGED
@@ -130,14 +130,14 @@ describe Sandal::Claims do
|
|
130
130
|
claims.validate_exp(120)
|
131
131
|
end
|
132
132
|
|
133
|
-
it 'raises
|
133
|
+
it 'raises an ExpiredTokenError when the expiry time is in the past with no clock skew' do
|
134
134
|
claims = { 'exp' => (Time.now - 300).to_i }.extend(Sandal::Claims)
|
135
|
-
expect { claims.validate_exp }.to raise_error Sandal::
|
135
|
+
expect { claims.validate_exp }.to raise_error Sandal::ExpiredTokenError
|
136
136
|
end
|
137
137
|
|
138
|
-
it 'raises
|
138
|
+
it 'raises an ExpiredTokenError when the expiry time is in the past and outside the max clock skew' do
|
139
139
|
claims = { 'exp' => (Time.now - 300).to_i }.extend(Sandal::Claims)
|
140
|
-
expect { claims.validate_exp(120) }.to raise_error Sandal::
|
140
|
+
expect { claims.validate_exp(120) }.to raise_error Sandal::ExpiredTokenError
|
141
141
|
end
|
142
142
|
|
143
143
|
end
|
@@ -1,48 +1,24 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require_relative
|
4
|
-
|
5
|
-
# TODO: These tests are really for the Sandal module rather than just the algorithm -- move them!
|
1
|
+
require "helper"
|
2
|
+
require "openssl"
|
3
|
+
require_relative "shared_examples"
|
6
4
|
|
7
5
|
describe Sandal::Enc::A128CBC_HS256 do
|
8
|
-
include_examples
|
9
|
-
|
10
|
-
# these tests don't run with jruby as it errors when you try and set rsa.d parameter directly
|
11
|
-
context 'using the example RSA key from JWE section A.2', :jruby_incompatible do
|
12
|
-
|
13
|
-
before :all do
|
14
|
-
@rsa = OpenSSL::PKey::RSA.new(2048)
|
15
|
-
@rsa.n = make_bn([177, 119, 33, 13, 164, 30, 108, 121, 207, 136, 107, 242, 12, 224, 19, 226, 198, 134, 17, 71, 173, 75, 42, 61, 48, 162, 206, 161, 97, 108, 185, 234, 226, 219, 118, 206, 118, 5, 169, 224, 60, 181, 90, 85, 51, 123, 6, 224, 4, 122, 29, 230, 151, 12, 244, 127, 121, 25, 4, 85, 220, 144, 215, 110, 130, 17, 68, 228, 129, 138, 7, 130, 231, 40, 212, 214, 17, 179, 28, 124, 151, 178, 207, 20, 14, 154, 222, 113, 176, 24, 198, 73, 211, 113, 9, 33, 178, 80, 13, 25, 21, 25, 153, 212, 206, 67, 154, 147, 70, 194, 192, 183, 160, 83, 98, 236, 175, 85, 23, 97, 75, 199, 177, 73, 145, 50, 253, 206, 32, 179, 254, 236, 190, 82, 73, 67, 129, 253, 252, 220, 108, 136, 138, 11, 192, 1, 36, 239, 228, 55, 81, 113, 17, 25, 140, 63, 239, 146, 3, 172, 96, 60, 227, 233, 64, 255, 224, 173, 225, 228, 229, 92, 112, 72, 99, 97, 26, 87, 187, 123, 46, 50, 90, 202, 117, 73, 10, 153, 47, 224, 178, 163, 77, 48, 46, 154, 33, 148, 34, 228, 33, 172, 216, 89, 46, 225, 127, 68, 146, 234, 30, 147, 54, 146, 5, 133, 45, 78, 254, 85, 55, 75, 213, 86, 194, 218, 215, 163, 189, 194, 54, 6, 83, 36, 18, 153, 53, 7, 48, 89, 35, 66, 144, 7, 65, 154, 13, 97, 75, 55, 230, 132, 3, 13, 239, 71])
|
16
|
-
@rsa.e = make_bn([1, 0, 1])
|
17
|
-
@rsa.d = make_bn([84, 80, 150, 58, 165, 235, 242, 123, 217, 55, 38, 154, 36, 181, 221, 156, 211, 215, 100, 164, 90, 88, 40, 228, 83, 148, 54, 122, 4, 16, 165, 48, 76, 194, 26, 107, 51, 53, 179, 165, 31, 18, 198, 173, 78, 61, 56, 97, 252, 158, 140, 80, 63, 25, 223, 156, 36, 203, 214, 252, 120, 67, 180, 167, 3, 82, 243, 25, 97, 214, 83, 133, 69, 16, 104, 54, 160, 200, 41, 83, 164, 187, 70, 153, 111, 234, 242, 158, 175, 28, 198, 48, 211, 45, 148, 58, 23, 62, 227, 74, 52, 117, 42, 90, 41, 249, 130, 154, 80, 119, 61, 26, 193, 40, 125, 10, 152, 174, 227, 225, 205, 32, 62, 66, 6, 163, 100, 99, 219, 19, 253, 25, 105, 80, 201, 29, 252, 157, 237, 69, 1, 80, 171, 167, 20, 196, 156, 109, 249, 88, 0, 3, 152, 38, 165, 72, 87, 6, 152, 71, 156, 214, 16, 71, 30, 82, 51, 103, 76, 218, 63, 9, 84, 163, 249, 91, 215, 44, 238, 85, 101, 240, 148, 1, 82, 224, 91, 135, 105, 127, 84, 171, 181, 152, 210, 183, 126, 24, 46, 196, 90, 173, 38, 245, 219, 186, 222, 27, 240, 212, 194, 15, 66, 135, 226, 178, 190, 52, 245, 74, 65, 224, 81, 100, 85, 25, 204, 165, 203, 187, 175, 84, 100, 82, 15, 11, 23, 202, 151, 107, 54, 41, 207, 3, 136, 229, 134, 131, 93, 139, 50, 182, 204, 93, 130, 89])
|
18
|
-
end
|
6
|
+
include_examples "algorithm compatibility", Sandal::Enc::A128CBC_HS256
|
7
|
+
include_examples "invalid tokens", Sandal::Enc::A128CBC_HS256
|
19
8
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
Sandal::Enc::A128CBC_HS256.new(alg)
|
25
|
-
end
|
26
|
-
payload.should == 'No matter where you go, there you are.'
|
9
|
+
context "#name" do
|
10
|
+
it "is 'A128CBC-HS256'" do
|
11
|
+
enc = Sandal::Enc::A128CBC_HS256.new(Sandal::Enc::Alg::Direct.new("a cmk"))
|
12
|
+
enc.name.should == "A128CBC-HS256"
|
27
13
|
end
|
28
|
-
|
29
|
-
it 'raises a token error when the integrity value is changed' do
|
30
|
-
token = 'eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDK0hTMjU2In0.ZmnlqWgjXyqwjr7cXHys8F79anIUI6J2UWdAyRQEcGBU-KPHsePM910_RoTDGu1IW40Dn0dvcdVEjpJcPPNIbzWcMxDi131Ejeg-b8ViW5YX5oRdYdiR4gMSDDB3mbkInMNUFT-PK5CuZRnHB2rUK5fhPuF6XFqLLZCG5Q_rJm6Evex-XLcNQAJNa1-6CIU12Wj3mPExxw9vbnsQDU7B4BfmhdyiflLA7Ae5ZGoVRl3A__yLPXxRjHFhpOeDp_adx8NyejF5cz9yDKULugNsDMdlHeJQOMGVLYaSZt3KP6aWNSqFA1PHDg-10ceuTEtq_vPE4-Gtev4N4K4Eudlj4Q.AxY8DCtDaGlsbGljb3RoZQ.Rxsjg6PIExcmGSF7LnSEkDqWIKfAw1wZz2XpabV5PwQsolKwEauWYZNE9Q1hZJEZ.7V5ZDko0v_mf2PAc4JMiUg'
|
31
|
-
expect { Sandal.decode_token(token) do |header|
|
32
|
-
alg = Sandal::Enc::Alg::RSA1_5.new(@rsa)
|
33
|
-
Sandal::Enc::A128CBC_HS256.new(alg)
|
34
|
-
end }.to raise_error Sandal::TokenError, 'Invalid integrity value.'
|
35
|
-
end
|
36
|
-
|
37
14
|
end
|
38
15
|
|
39
|
-
|
40
|
-
token
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end }.to raise_error Sandal::TokenError, 'Cannot decrypt content master key.'
|
16
|
+
context "#decrypt" do
|
17
|
+
it "can decrypt the example token from JWE draft-11 appendix 2", :jruby_incompatible do
|
18
|
+
token="eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A.AxY8DCtDaGlsbGljb3RoZQ.KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.9hH0vgRfYgPnAHOd8stkvw"
|
19
|
+
enc = Sandal::Enc::A128CBC_HS256.new(Sandal::Enc::Alg::RSA1_5.new(SampleKeys.jwe_draft11_appendix2_rsa))
|
20
|
+
enc.decrypt(token).should == "Live long and prosper."
|
21
|
+
end
|
46
22
|
end
|
47
23
|
|
48
24
|
end
|
@@ -1,13 +1,20 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require_relative
|
4
|
-
|
5
|
-
# TODO: These tests are really for the Sandal module rather than just the algorithm -- move them!
|
1
|
+
require "helper"
|
2
|
+
require "openssl"
|
3
|
+
require_relative "shared_examples"
|
6
4
|
|
7
5
|
if defined? Sandal::Enc::A128GCM
|
8
6
|
|
9
7
|
describe Sandal::Enc::A128GCM do
|
10
|
-
include_examples
|
8
|
+
include_examples "algorithm compatibility", Sandal::Enc::A128GCM
|
9
|
+
include_examples "invalid tokens", Sandal::Enc::A128GCM
|
10
|
+
|
11
|
+
context "#name" do
|
12
|
+
it "is 'A128GCM'" do
|
13
|
+
enc = Sandal::Enc::A128GCM.new(Sandal::Enc::Alg::Direct.new("a cmk"))
|
14
|
+
enc.name.should == "A128GCM"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
11
18
|
end
|
12
19
|
|
13
20
|
end
|
@@ -1,10 +1,19 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require_relative
|
1
|
+
require "helper"
|
2
|
+
require "openssl"
|
3
|
+
require_relative "shared_examples"
|
4
4
|
|
5
5
|
# TODO: These tests are really for the Sandal module rather than just the algorithm -- move them!
|
6
6
|
|
7
7
|
describe Sandal::Enc::A256CBC_HS512 do
|
8
|
-
include_examples
|
8
|
+
include_examples "algorithm compatibility", Sandal::Enc::A256CBC_HS512
|
9
|
+
include_examples "invalid tokens", Sandal::Enc::A256CBC_HS512
|
10
|
+
|
11
|
+
context "#name" do
|
12
|
+
it "is 'A256CBC-HS512'" do
|
13
|
+
enc = Sandal::Enc::A256CBC_HS512.new(Sandal::Enc::Alg::Direct.new("a cmk"))
|
14
|
+
enc.name.should == "A256CBC-HS512"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
9
18
|
end
|
10
19
|
|
@@ -1,50 +1,28 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require_relative
|
4
|
-
|
5
|
-
# TODO: These tests are really for the Sandal module rather than just the algorithm -- move them!
|
1
|
+
require "helper"
|
2
|
+
require "openssl"
|
3
|
+
require_relative "shared_examples"
|
6
4
|
|
7
5
|
if defined? Sandal::Enc::A256GCM
|
8
6
|
|
9
7
|
describe Sandal::Enc::A256GCM do
|
10
|
-
include_examples
|
11
|
-
|
12
|
-
# these tests don't run with jruby as it errors when you try and set rsa.d parameter directly
|
13
|
-
context 'using the example RSA key from JWE section A.1', :jruby_incompatible do
|
14
|
-
|
15
|
-
before :all do
|
16
|
-
@rsa = OpenSSL::PKey::RSA.new(2048)
|
17
|
-
@rsa.n = make_bn([161, 168, 84, 34, 133, 176, 208, 173, 46, 176, 163, 110, 57, 30, 135, 227, 9, 31, 226, 128, 84, 92, 116, 241, 70, 248, 27, 227, 193, 62, 5, 91, 241, 145, 224, 205, 141, 176, 184, 133, 239, 43, 81, 103, 9, 161, 153, 157, 179, 104, 123, 51, 189, 34, 152, 69, 97, 69, 78, 93, 140, 131, 87, 182, 169, 101, 92, 142, 3, 22, 167, 8, 212, 56, 35, 79, 210, 222, 192, 208, 252, 49, 109, 138, 173, 253, 210, 166, 201, 63, 102, 74, 5, 158, 41, 90, 144, 108, 160, 79, 10, 89, 222, 231, 172, 31, 227, 197, 0, 19, 72, 81, 138, 78, 136, 221, 121, 118, 196, 17, 146, 10, 244, 188, 72, 113, 55, 221, 162, 217, 171, 27, 57, 233, 210, 101, 236, 154, 199, 56, 138, 239, 101, 48, 198, 186, 202, 160, 76, 111, 234, 71, 57, 183, 5, 211, 171, 136, 126, 64, 40, 75, 58, 89, 244, 254, 107, 84, 103, 7, 236, 69, 163, 18, 180, 251, 58, 153, 46, 151, 174, 12, 103, 197, 181, 161, 162, 55, 250, 235, 123, 110, 17, 11, 158, 24, 47, 133, 8, 199, 235, 107, 126, 130, 246, 73, 195, 20, 108, 202, 176, 214, 187, 45, 146, 182, 118, 54, 32, 200, 61, 201, 71, 243, 1, 255, 131, 84, 37, 111, 211, 168, 228, 45, 192, 118, 27, 197, 235, 232, 36, 10, 230, 248, 190, 82, 182, 140, 35, 204, 108, 190, 253, 186, 186, 27])
|
18
|
-
@rsa.e = make_bn([1, 0, 1])
|
19
|
-
@rsa.d = make_bn([144, 183, 109, 34, 62, 134, 108, 57, 44, 252, 10, 66, 73, 54, 16, 181, 233, 92, 54, 219, 101, 42, 35, 178, 63, 51, 43, 92, 119, 136, 251, 41, 53, 23, 191, 164, 164, 60, 88, 227, 229, 152, 228, 213, 149, 228, 169, 237, 104, 71, 151, 75, 88, 252, 216, 77, 251, 231, 28, 97, 88, 193, 215, 202, 248, 216, 121, 195, 211, 245, 250, 112, 71, 243, 61, 129, 95, 39, 244, 122, 225, 217, 169, 211, 165, 48, 253, 220, 59, 122, 219, 42, 86, 223, 32, 236, 39, 48, 103, 78, 122, 216, 187, 88, 176, 89, 24, 1, 42, 177, 24, 99, 142, 170, 1, 146, 43, 3, 108, 64, 194, 121, 182, 95, 187, 134, 71, 88, 96, 134, 74, 131, 167, 69, 106, 143, 121, 27, 72, 44, 245, 95, 39, 194, 179, 175, 203, 122, 16, 112, 183, 17, 200, 202, 31, 17, 138, 156, 184, 210, 157, 184, 154, 131, 128, 110, 12, 85, 195, 122, 241, 79, 251, 229, 183, 117, 21, 123, 133, 142, 220, 153, 9, 59, 57, 105, 81, 255, 138, 77, 82, 54, 62, 216, 38, 249, 208, 17, 197, 49, 45, 19, 232, 157, 251, 131, 137, 175, 72, 126, 43, 229, 69, 179, 117, 82, 157, 213, 83, 35, 57, 210, 197, 252, 171, 143, 194, 11, 47, 163, 6, 253, 75, 252, 96, 11, 187, 84, 130, 210, 7, 121, 78, 91, 79, 57, 251, 138, 132, 220, 60, 224, 173, 56, 224, 201])
|
20
|
-
end
|
8
|
+
include_examples "algorithm compatibility", Sandal::Enc::A256GCM
|
9
|
+
include_examples "invalid tokens", Sandal::Enc::A256GCM
|
21
10
|
|
22
|
-
|
23
|
-
token = 'eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.M2XxpbORKezKSzzQL_95-GjiudRBTqn_omS8z9xgoRb7L0Jw5UsEbxmtyHn2T71mrZLkjg4Mp8gbhYoltPkEOHvAopz25-vZ8C2e1cOaAo5WPcbSIuFcB4DjBOM3t0UAO6JHkWLuAEYoe58lcxIQneyKdaYSLbV9cKqoUoFQpvKWYRHZbfszIyfsa18rmgTjzrtLDTPnc09DSJE24aQ8w3i8RXEDthW9T1J6LsTH_vwHdwUgkI-tC2PNeGrnM-dNSfzF3Y7-lwcGy0FsdXkPXytvDV7y4pZeeUiQ-0VdibIN2AjjfW60nfrPuOjepMFG6BBBbR37pHcyzext9epOAQ.48V1_ALb6US04U3b._e21tGGhac_peEFkLXr2dMPUZiUkrw.7V5ZDko0v_mf2PAc4JMiUg'
|
24
|
-
payload = Sandal.decode_token(token) do |header|
|
25
|
-
alg = Sandal::Enc::Alg::RSA_OAEP.new(@rsa)
|
26
|
-
Sandal::Enc::A256GCM.new(alg)
|
27
|
-
end
|
28
|
-
payload.should == 'Live long and prosper.'
|
29
|
-
end
|
11
|
+
context "#name" do
|
30
12
|
|
31
|
-
it
|
32
|
-
|
33
|
-
|
34
|
-
alg = Sandal::Enc::Alg::RSA_OAEP.new(@rsa)
|
35
|
-
Sandal::Enc::A256GCM.new(alg)
|
36
|
-
end }.to raise_error Sandal::TokenError, 'Invalid token.'
|
13
|
+
it "is 'A256GCM'" do
|
14
|
+
enc = Sandal::Enc::A256GCM.new(Sandal::Enc::Alg::Direct.new("a cmk"))
|
15
|
+
enc.name.should == "A256GCM"
|
37
16
|
end
|
38
17
|
|
39
18
|
end
|
40
19
|
|
41
|
-
|
42
|
-
token
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end }.to raise_error Sandal::TokenError, 'Cannot decrypt content master key.'
|
20
|
+
context "#decrypt" do
|
21
|
+
it "can decrypt the example token from JWE draft-11 appendix 1", :jruby_incompatible do
|
22
|
+
token = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ"
|
23
|
+
enc = Sandal::Enc::A256GCM.new(Sandal::Enc::Alg::RSA_OAEP.new(SampleKeys.jwe_draft11_appendix1_rsa))
|
24
|
+
enc.decrypt(token).should == "The true sign of intelligence is not knowledge but imagination."
|
25
|
+
end
|
48
26
|
end
|
49
27
|
|
50
28
|
end
|
@@ -1,53 +1,47 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "helper"
|
2
|
+
require "openssl"
|
3
3
|
|
4
4
|
describe Sandal::Enc::Alg::Direct do
|
5
5
|
|
6
|
-
context
|
7
|
-
|
8
|
-
|
9
|
-
alg
|
10
|
-
alg.name.should == 'dir'
|
6
|
+
context "#name" do
|
7
|
+
it "is 'dir'" do
|
8
|
+
alg = Sandal::Enc::Alg::Direct.new("some key")
|
9
|
+
alg.name.should == "dir"
|
11
10
|
end
|
12
|
-
|
13
11
|
end
|
14
12
|
|
15
|
-
context
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
alg
|
20
|
-
alg.cmk.should == cmk
|
13
|
+
context "#preshared_key" do
|
14
|
+
it "returns the pre-shared key" do
|
15
|
+
key = "the pre-shared key"
|
16
|
+
alg = Sandal::Enc::Alg::Direct.new(key)
|
17
|
+
alg.preshared_key.should == key
|
21
18
|
end
|
22
|
-
|
23
19
|
end
|
24
20
|
|
25
|
-
context
|
26
|
-
|
27
|
-
|
28
|
-
alg
|
29
|
-
alg.encrypt_cmk('any value').should == ''
|
21
|
+
context "#encrypt_key" do
|
22
|
+
it "returns an empty string" do
|
23
|
+
alg = Sandal::Enc::Alg::Direct.new("the real key")
|
24
|
+
alg.encrypt_key("any value").should == ""
|
30
25
|
end
|
31
|
-
|
32
26
|
end
|
33
27
|
|
34
|
-
context
|
28
|
+
context "#decrypt_key" do
|
35
29
|
|
36
|
-
it
|
37
|
-
|
38
|
-
alg = Sandal::Enc::Alg::Direct.new(
|
39
|
-
alg.
|
30
|
+
it "returns the pre-shared content key when the value to decrypt is nil" do
|
31
|
+
key = "a pre-shared key"
|
32
|
+
alg = Sandal::Enc::Alg::Direct.new(key)
|
33
|
+
alg.decrypt_key(nil).should == key
|
40
34
|
end
|
41
35
|
|
42
|
-
it
|
43
|
-
|
44
|
-
alg = Sandal::Enc::Alg::Direct.new(
|
45
|
-
alg.
|
36
|
+
it "returns the pre-shared content key when the value to decrypt is empty" do
|
37
|
+
key = "my pre-shared key"
|
38
|
+
alg = Sandal::Enc::Alg::Direct.new(key)
|
39
|
+
alg.decrypt_key("").should == key
|
46
40
|
end
|
47
41
|
|
48
|
-
it
|
49
|
-
alg = Sandal::Enc::Alg::Direct.new(
|
50
|
-
expect { alg.
|
42
|
+
it "raises an InvalidTokenError if the value to decrypt is not nil or empty" do
|
43
|
+
alg = Sandal::Enc::Alg::Direct.new("the pre-shared key")
|
44
|
+
expect { alg.decrypt_key("a value") }.to raise_error Sandal::InvalidTokenError
|
51
45
|
end
|
52
46
|
|
53
47
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require "helper"
|
2
|
+
require "openssl"
|
3
|
+
|
4
|
+
include Sandal::Util
|
5
|
+
|
6
|
+
shared_examples "encryption and decryption" do |enc_class|
|
7
|
+
|
8
|
+
it "can encrypt and decrypt a content master key" do
|
9
|
+
key = OpenSSL::PKey::RSA.new(2048)
|
10
|
+
encrypter = enc_class.new(key.public_key)
|
11
|
+
decrypter = enc_class.new(key)
|
12
|
+
key = "an encryption key"
|
13
|
+
decrypter.decrypt_key(encrypter.encrypt_key(key)).should == key
|
14
|
+
end
|
15
|
+
|
16
|
+
it "can use DER-encoded keys to encrypt and decrypt a content master key" do
|
17
|
+
key = OpenSSL::PKey::RSA.new(2048)
|
18
|
+
encrypter = enc_class.new(key.public_key.to_der)
|
19
|
+
decrypter = enc_class.new(key.to_der)
|
20
|
+
key = "an encryption key"
|
21
|
+
decrypter.decrypt_key(encrypter.encrypt_key(key)).should == key
|
22
|
+
end
|
23
|
+
|
24
|
+
it "can use PEM-encoded keys to encrypt and decrypt a content master key" do
|
25
|
+
key = OpenSSL::PKey::RSA.new(2048)
|
26
|
+
encrypter = enc_class.new(key.public_key.to_pem)
|
27
|
+
decrypter = enc_class.new(key.to_pem)
|
28
|
+
key = "an encryption key"
|
29
|
+
decrypter.decrypt_key(encrypter.encrypt_key(key)).should == key
|
30
|
+
end
|
31
|
+
|
32
|
+
context "#decrypt_key" do
|
33
|
+
|
34
|
+
it "raises an InvalidTokenError when the wrong key is used for decryption" do
|
35
|
+
encrypter = enc_class.new(OpenSSL::PKey::RSA.new(2048).public_key)
|
36
|
+
decrypter = enc_class.new(OpenSSL::PKey::RSA.new(2048))
|
37
|
+
encrypted_key = encrypter.encrypt_key("an encryption key")
|
38
|
+
expect { decrypter.decrypt_key(encrypted_key) }.to raise_error Sandal::InvalidTokenError
|
39
|
+
end
|
40
|
+
|
41
|
+
it "raises an InvalidTokenError when the key to decrypt is nil" do
|
42
|
+
decrypter = enc_class.new(OpenSSL::PKey::RSA.new(2048))
|
43
|
+
expect { decrypter.decrypt_key(nil) }.to raise_error Sandal::InvalidTokenError
|
44
|
+
end
|
45
|
+
|
46
|
+
it "raises an InvalidTokenError when the key to decrypt is empty" do
|
47
|
+
decrypter = enc_class.new(OpenSSL::PKey::RSA.new(2048))
|
48
|
+
expect { decrypter.decrypt_key("") }.to raise_error Sandal::InvalidTokenError
|
49
|
+
end
|
50
|
+
|
51
|
+
it "raises an InvalidTokenError when the key to decrypt is invalid" do
|
52
|
+
decrypter = enc_class.new(OpenSSL::PKey::RSA.new(2048))
|
53
|
+
expect { decrypter.decrypt_key("not a real encrypted key") }.to raise_error Sandal::InvalidTokenError
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
describe Sandal::Enc::Alg::RSA1_5 do
|
61
|
+
include_examples "encryption and decryption", Sandal::Enc::Alg::RSA1_5
|
62
|
+
|
63
|
+
context "#name" do
|
64
|
+
it "is 'RSA1_5'" do
|
65
|
+
alg = Sandal::Enc::Alg::RSA1_5.new(OpenSSL::PKey::RSA.new(2048))
|
66
|
+
alg.name.should == "RSA1_5"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "#decrypt_key" do
|
71
|
+
it "can decrypt the encypted content master key from JWE draft-11 appendix 2", :jruby_incompatible do
|
72
|
+
key = [4, 211, 31, 197, 84, 157, 252, 254, 11, 100, 157, 250, 63, 170, 106, 206, 107, 124, 212, 45, 111, 107, 9, 219, 200, 177, 0, 240, 143, 156, 44, 207].pack("C*")
|
73
|
+
encrypted_key = [80, 104, 72, 58, 11, 130, 236, 139, 132, 189, 255, 205, 61, 86, 151, 176, 99, 40, 44, 233, 176, 189, 205, 70, 202, 169, 72, 40, 226, 181, 156, 223, 120, 156, 115, 232, 150, 209, 145, 133, 104, 112, 237, 156, 116, 250, 65, 102, 212, 210, 103, 240, 177, 61, 93, 40, 71, 231, 223, 226, 240, 157, 15, 31, 150, 89, 200, 215, 198, 203, 108, 70, 117, 66, 212, 238, 193, 205, 23, 161, 169, 218, 243, 203, 128, 214, 127, 253, 215, 139, 43, 17, 135, 103, 179, 220, 28, 2, 212, 206, 131, 158, 128, 66, 62, 240, 78, 186, 141, 125, 132, 227, 60, 137, 43, 31, 152, 199, 54, 72, 34, 212, 115, 11, 152, 101, 70, 42, 219, 233, 142, 66, 151, 250, 126, 146, 141, 216, 190, 73, 50, 177, 146, 5, 52, 247, 28, 197, 21, 59, 170, 247, 181, 89, 131, 241, 169, 182, 246, 99, 15, 36, 102, 166, 182, 172, 197, 136, 230, 120, 60, 58, 219, 243, 149, 94, 222, 150, 154, 194, 110, 227, 225, 112, 39, 89, 233, 112, 207, 211, 241, 124, 174, 69, 221, 179, 107, 196, 225, 127, 167, 112, 226, 12, 242, 16, 24, 28, 120, 182, 244, 213, 244, 153, 194, 162, 69, 160, 244, 248, 63, 165, 141, 4, 207, 249, 193, 79, 131, 0, 169, 233, 127, 167, 101, 151, 125, 56, 112, 111, 248, 29, 232, 90, 29, 147, 110, 169, 146, 114, 165, 204, 71, 136, 41, 252].pack("C*")
|
74
|
+
alg = Sandal::Enc::Alg::RSA1_5.new(SampleKeys.jwe_draft11_appendix2_rsa)
|
75
|
+
alg.decrypt_key(encrypted_key).should == key
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
describe Sandal::Enc::Alg::RSA_OAEP do
|
82
|
+
include_examples "encryption and decryption", Sandal::Enc::Alg::RSA_OAEP
|
83
|
+
|
84
|
+
context "#name" do
|
85
|
+
it "is 'RSA-OAEP'" do
|
86
|
+
alg = Sandal::Enc::Alg::RSA_OAEP.new(OpenSSL::PKey::RSA.new(2048))
|
87
|
+
alg.name.should == "RSA-OAEP"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "#decrypt_key" do
|
92
|
+
it "can decrypt the encypted content master key from JWE draft-11 appendix 1", :jruby_incompatible do
|
93
|
+
key = [177, 161, 244, 128, 84, 143, 225, 115, 63, 180, 3, 255, 107, 154, 212, 246, 138, 7, 110, 91, 112, 46, 34, 105, 47, 130, 203, 46, 122, 234, 64, 252].pack("C*")
|
94
|
+
encrypted_key = [56, 163, 154, 192, 58, 53, 222, 4, 105, 218, 136, 218, 29, 94, 203, 22, 150, 92, 129, 94, 211, 232, 53, 89, 41, 60, 138, 56, 196, 216, 82, 98, 168, 76, 37, 73, 70, 7, 36, 8, 191, 100, 136, 196, 244, 220, 145, 158, 138, 155, 4, 117, 141, 230, 199, 247, 173, 45, 182, 214, 74, 177, 107, 211, 153, 11, 205, 196, 171, 226, 162, 128, 171, 182, 13, 237, 239, 99, 193, 4, 91, 219, 121, 223, 107, 167, 61, 119, 228, 173, 156, 137, 134, 200, 80, 219, 74, 253, 56, 185, 91, 177, 34, 158, 89, 154, 205, 96, 55, 18, 138, 43, 96, 218, 215, 128, 124, 75, 138, 243, 85, 25, 109, 117, 140, 26, 155, 249, 67, 167, 149, 231, 100, 6, 41, 65, 214, 251, 232, 87, 72, 40, 182, 149, 154, 168, 31, 193, 126, 215, 89, 28, 111, 219, 125, 182, 139, 235, 195, 197, 23, 234, 55, 58, 63, 180, 68, 202, 206, 149, 75, 205, 248, 176, 67, 39, 178, 60, 98, 193, 32, 238, 122, 96, 158, 222, 57, 183, 111, 210, 55, 188, 215, 206, 180, 166, 150, 166, 106, 250, 55, 229, 72, 40, 69, 214, 216, 104, 23, 40, 135, 212, 28, 127, 41, 80, 175, 174, 168, 115, 171, 197, 89, 116, 92, 103, 246, 83, 216, 182, 176, 84, 37, 147, 35, 45, 219, 172, 99, 226, 233, 73, 37, 124, 42, 72, 49, 242, 35, 127, 184, 134, 117, 114, 135, 206].pack("C*")
|
95
|
+
alg = Sandal::Enc::Alg::RSA_OAEP.new(SampleKeys.jwe_draft11_appendix1_rsa)
|
96
|
+
alg.decrypt_key(encrypted_key).should == key
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
@@ -1,37 +1,109 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "helper"
|
2
|
+
require "securerandom"
|
3
3
|
|
4
|
-
shared_examples
|
4
|
+
shared_examples "algorithm compatibility" do |enc_class|
|
5
5
|
|
6
|
-
it
|
7
|
-
payload =
|
8
|
-
|
9
|
-
|
10
|
-
token =
|
11
|
-
output =
|
6
|
+
it "can encrypt and decrypt tokens with the dir algorithm" do
|
7
|
+
payload = "Some text to encrypt"
|
8
|
+
content_encryption_key = SecureRandom.random_bytes(enc_class::KEY_SIZE / 8)
|
9
|
+
enc = enc_class.new(Sandal::Enc::Alg::Direct.new(content_encryption_key))
|
10
|
+
token = enc.encrypt("", payload)
|
11
|
+
output = enc.decrypt(token)
|
12
12
|
output.should == payload
|
13
13
|
end
|
14
14
|
|
15
|
-
it
|
16
|
-
payload =
|
15
|
+
it "can encrypt and decrypt tokens with the RSA1_5 algorithm" do
|
16
|
+
payload = "Some other text to encrypt"
|
17
17
|
rsa = OpenSSL::PKey::RSA.new(2048)
|
18
18
|
encrypter = enc_class.new(Sandal::Enc::Alg::RSA1_5.new(rsa.public_key))
|
19
|
-
token =
|
20
|
-
|
21
|
-
|
22
|
-
end
|
19
|
+
token = encrypter.encrypt("", payload)
|
20
|
+
decrypter = enc_class.new(Sandal::Enc::Alg::RSA1_5.new(rsa))
|
21
|
+
output = decrypter.decrypt(token)
|
23
22
|
output.should == payload
|
24
23
|
end
|
25
24
|
|
26
|
-
it
|
27
|
-
payload =
|
25
|
+
it "can encrypt and decrypt tokens with the RSA-OAEP algorithm" do
|
26
|
+
payload = "Some more text to encrypt"
|
28
27
|
rsa = OpenSSL::PKey::RSA.new(2048)
|
29
28
|
encrypter = enc_class.new(Sandal::Enc::Alg::RSA_OAEP.new(rsa.public_key))
|
30
|
-
token =
|
31
|
-
|
32
|
-
|
33
|
-
end
|
29
|
+
token = encrypter.encrypt("", payload)
|
30
|
+
decrypter = enc_class.new(Sandal::Enc::Alg::RSA_OAEP.new(rsa))
|
31
|
+
output = decrypter.decrypt(token)
|
34
32
|
output.should == payload
|
35
33
|
end
|
36
34
|
|
35
|
+
end
|
36
|
+
|
37
|
+
shared_examples "invalid tokens" do |enc_class|
|
38
|
+
|
39
|
+
context "#decrypt" do
|
40
|
+
|
41
|
+
def test_decrypt_mangled_token(enc_class)
|
42
|
+
content_encryption_key = SecureRandom.random_bytes(enc_class::KEY_SIZE / 8)
|
43
|
+
enc = enc_class.new(Sandal::Enc::Alg::Direct.new(content_encryption_key))
|
44
|
+
token = enc.encrypt("", "any old payload")
|
45
|
+
token_parts = token.split(".")
|
46
|
+
yield token_parts
|
47
|
+
token = token_parts.join(".")
|
48
|
+
expect { enc.decrypt(token) }.to raise_error Sandal::InvalidTokenError
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_decrypt_token_with_missing_part(enc_class, part_index)
|
52
|
+
test_decrypt_mangled_token(enc_class) do |token_parts|
|
53
|
+
token_parts.delete_at(part_index)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "raises an InvalidTokenError when the header is missing" do
|
58
|
+
test_decrypt_token_with_missing_part(enc_class, 0)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "raises an InvalidTokenError when the encrypted key is missing" do
|
62
|
+
test_decrypt_token_with_missing_part(enc_class, 1)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "raises an InvalidTokenError when the IV is missing" do
|
66
|
+
test_decrypt_token_with_missing_part(enc_class, 2)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "raises an InvalidTokenError when the encrypted data is missing" do
|
70
|
+
test_decrypt_token_with_missing_part(enc_class, 3)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "raises an InvalidTokenError when the integrity value is missing" do
|
74
|
+
test_decrypt_token_with_missing_part(enc_class, 4)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "raises an InvalidTokenError when the header value is invalid" do
|
78
|
+
test_decrypt_mangled_token(enc_class) do |token_parts|
|
79
|
+
token_parts[0] = token_parts[4]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it "raises an InvalidTokenError when the encrypted key is invalid" do
|
84
|
+
test_decrypt_mangled_token(enc_class) do |token_parts|
|
85
|
+
token_parts[1] = token_parts[4]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it "raises an InvalidTokenError when the IV is invalid" do
|
90
|
+
test_decrypt_mangled_token(enc_class) do |token_parts|
|
91
|
+
token_parts[2] = token_parts[4]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it "raises an InvalidTokenError when the encrypted data is invalid" do
|
96
|
+
test_decrypt_mangled_token(enc_class) do |token_parts|
|
97
|
+
token_parts[3] = token_parts[4]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "raises an InvalidTokenError when the integrity value is invalid" do
|
102
|
+
test_decrypt_mangled_token(enc_class) do |token_parts|
|
103
|
+
token_parts[4] = token_parts[0]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
37
109
|
end
|