smaak 0.2.1 → 0.2.2
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 +4 -0
- data/README.md +7 -2
- data/Rakefile +7 -1
- data/lib/smaak.rb +9 -9
- data/lib/smaak/adaptors/net_http_adaptor.rb +2 -2
- data/lib/smaak/adaptors/rack_adaptor.rb +18 -10
- data/lib/smaak/associate.rb +6 -6
- data/lib/smaak/auth_message.rb +35 -15
- data/lib/smaak/cavage_04.rb +23 -18
- data/lib/smaak/client.rb +25 -13
- data/lib/smaak/crypto.rb +2 -2
- data/lib/smaak/server.rb +83 -31
- data/lib/smaak/smaak_service.rb +1 -1
- data/lib/smaak/utils.rb +1 -1
- data/lib/smaak/version.rb +1 -1
- data/smaak.gemspec +3 -2
- data/spec/lib/smaak/adaptors/net_http_adaptor_spec.rb +3 -3
- data/spec/lib/smaak/auth_message_spec.rb +11 -11
- data/spec/lib/smaak/cavage_04_spec.rb +9 -9
- data/spec/lib/smaak/crypto_spec.rb +14 -14
- data/spec/lib/smaak/server_spec.rb +3 -4
- data/spec/lib/smaak/smaak_service_spec.rb +3 -3
- data/spec/lib/smaak_spec.rb +34 -34
- data/spec/spec_helper.rb +13 -8
- metadata +8 -23
- data/spec/mock/request.rb +0 -7
data/lib/smaak/crypto.rb
CHANGED
@@ -7,7 +7,7 @@ module Smaak
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.generate_nonce
|
10
|
-
SecureRandom
|
10
|
+
SecureRandom.random_number(10000000000)
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.encode64(data)
|
@@ -20,7 +20,7 @@ module Smaak
|
|
20
20
|
|
21
21
|
def self.sign_data(data, private_key)
|
22
22
|
digest = OpenSSL::Digest::SHA256.new
|
23
|
-
private_key.sign(digest, Smaak::Crypto
|
23
|
+
private_key.sign(digest, Smaak::Crypto.encode64(data))
|
24
24
|
end
|
25
25
|
|
26
26
|
def self.verify_signature(signature, data, public_key)
|
data/lib/smaak/server.rb
CHANGED
@@ -31,23 +31,87 @@ module Smaak
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def build_auth_message_from_request(adaptor)
|
34
|
-
puts "[smaak error]: x-smaak-* headers not all present. Is this a smaak request?"
|
35
|
-
recipient_public_key = Smaak::Crypto
|
34
|
+
puts "[smaak error]: x-smaak-* headers not all present. Is this a smaak request?" unless smaak_headers_all_present?(adaptor)
|
35
|
+
recipient_public_key = Smaak::Crypto.decode64(adaptor.header("x-smaak-recipient"))
|
36
36
|
psk = adaptor.header("x-smaak-psk")
|
37
37
|
expires = adaptor.header("x-smaak-expires")
|
38
38
|
identifier = adaptor.header("x-smaak-identifier")
|
39
39
|
route_info = adaptor.header("x-smaak-route-info")
|
40
40
|
nonce = adaptor.header("x-smaak-nonce")
|
41
41
|
encrypt = adaptor.header("x-smaak-encrypt")
|
42
|
-
|
42
|
+
Smaak::AuthMessage.build(recipient_public_key, psk, expires, identifier, route_info, nonce, encrypt)
|
43
43
|
end
|
44
44
|
|
45
45
|
def verify_auth_message(auth_message)
|
46
|
-
|
46
|
+
return false unless verify_message_characteristics?(auth_message)
|
47
|
+
identifier = auth_message.identifier
|
48
|
+
verify_association_characteristics?(auth_message, identifier)
|
49
|
+
end
|
50
|
+
|
51
|
+
def verify_signed_request(request)
|
52
|
+
adaptor = Smaak.create_adaptor(request)
|
53
|
+
auth_message = build_auth_message_from_request(adaptor)
|
54
|
+
unless verify_auth_message(auth_message)
|
55
|
+
puts "[smaak error]: could not verify auth_message"
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
pubkey = @association_store[auth_message.identifier]['public_key']
|
59
|
+
puts "[smaak warning]: pubkey not specified" if (pubkey.nil?) or (pubkey == "")
|
60
|
+
body = Smaak::Crypto.sink(adaptor.body)
|
61
|
+
body = Smaak::Crypto.decrypt(body, @private_key) if auth_message.encrypt
|
62
|
+
unless Smaak.verify_authorization_headers(adaptor, pubkey)
|
63
|
+
puts "[smaak error]: could not verify authorization headers"
|
64
|
+
return false, nil
|
65
|
+
end
|
66
|
+
return auth_message, body # TBD return ID from cert
|
67
|
+
end
|
68
|
+
|
69
|
+
def compile_response(auth_message, data)
|
70
|
+
return Smaak::Crypto.encrypt(data, @association_store[auth_message.identifier]['public_key']) if auth_message.encrypt
|
71
|
+
data
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def verify_message_characteristics?(auth_message)
|
77
|
+
verify_unique?(auth_message) and
|
78
|
+
verify_public_key? and
|
79
|
+
verify_intended_recipient?(auth_message)
|
80
|
+
end
|
81
|
+
|
82
|
+
def verify_association_characteristics?(auth_message, identifier)
|
83
|
+
verify_associate?(identifier) and
|
84
|
+
verify_expiry?(auth_message) and
|
85
|
+
verify_psk?(auth_message, identifier)
|
86
|
+
end
|
87
|
+
|
88
|
+
def smaak_headers_all_present?(adaptor)
|
89
|
+
not
|
90
|
+
(adaptor.header("x-smaak-recipient").nil? or
|
91
|
+
adaptor.header("x-smaak-psk").nil? or
|
92
|
+
adaptor.header("x-smaak-expires").nil? or
|
93
|
+
adaptor.header("x-smaak-identifier").nil? or
|
94
|
+
adaptor.header("x-smaak-nonce").nil? or
|
95
|
+
adaptor.header("x-smaak-encrypt").nil?)
|
96
|
+
end
|
97
|
+
|
98
|
+
def verify_unique?(auth_message)
|
99
|
+
unless auth_message_unique?(auth_message)
|
47
100
|
puts "[smaak error]: message not unique"
|
48
101
|
return false
|
49
102
|
end
|
50
|
-
|
103
|
+
true
|
104
|
+
end
|
105
|
+
|
106
|
+
def verify_public_key?
|
107
|
+
if @key.nil?
|
108
|
+
puts "[smaak error]: public key not set. Did you call set_public_key() ?"
|
109
|
+
return false
|
110
|
+
end
|
111
|
+
true
|
112
|
+
end
|
113
|
+
|
114
|
+
def verify_intended_recipient?(auth_message)
|
51
115
|
if (@verify_recipient) and (not auth_message.intended_for_recipient?(@key.export))
|
52
116
|
puts "[smaak error]: message not intended for this recipient"
|
53
117
|
return false
|
@@ -56,49 +120,37 @@ module Smaak
|
|
56
120
|
# if auth_message.router_info
|
57
121
|
# verified = auth_message.intended_for_recipient?(@association_store[auth_message.router_info])
|
58
122
|
# end
|
59
|
-
#
|
123
|
+
# unless verified
|
60
124
|
# puts "[smaak error]: message not intended for this recipient"
|
61
125
|
# return false
|
62
126
|
# end
|
63
127
|
end
|
64
|
-
|
128
|
+
true
|
129
|
+
end
|
130
|
+
|
131
|
+
def verify_associate?(identifier)
|
65
132
|
if @association_store[identifier].nil?
|
66
133
|
puts "[smaak error]: unknown associate #{identifier}"
|
67
134
|
return false
|
68
135
|
end
|
136
|
+
true
|
137
|
+
end
|
138
|
+
|
139
|
+
def verify_expiry?(auth_message)
|
69
140
|
if auth_message.expired?
|
70
141
|
puts "[smaak error]: message expired. Are the sender and receiver's clocks in sync?"
|
71
142
|
return false
|
72
143
|
end
|
73
|
-
psk = @association_store[identifier]['psk']
|
74
|
-
if not auth_message.verify(psk)
|
75
|
-
puts "[smaak error]: PSK mismatch"
|
76
|
-
return false
|
77
|
-
end
|
78
144
|
true
|
79
145
|
end
|
80
146
|
|
81
|
-
def
|
82
|
-
|
83
|
-
auth_message
|
84
|
-
|
85
|
-
puts "[smaak error]: could not verify auth_message"
|
147
|
+
def verify_psk?(auth_message, identifier)
|
148
|
+
psk = @association_store[identifier]['psk']
|
149
|
+
unless auth_message.verify(psk)
|
150
|
+
puts "[smaak error]: PSK mismatch"
|
86
151
|
return false
|
87
152
|
end
|
88
|
-
|
89
|
-
puts "[smaak warning]: pubkey not specified" if (pubkey.nil?) or (pubkey == "")
|
90
|
-
body = Smaak::Crypto::sink(adaptor.body)
|
91
|
-
body = Smaak::Crypto::decrypt(body, @private_key) if auth_message.encrypt
|
92
|
-
if not Smaak::verify_authorization_headers(adaptor, pubkey)
|
93
|
-
puts "[smaak error]: could not verify authorization headers"
|
94
|
-
return false, nil
|
95
|
-
end
|
96
|
-
return auth_message, body # TBD return ID from cert
|
97
|
-
end
|
98
|
-
|
99
|
-
def compile_response(auth_message, data)
|
100
|
-
return Smaak::Crypto::encrypt(data, @association_store[auth_message.identifier]['public_key']) if auth_message.encrypt
|
101
|
-
data
|
153
|
+
true
|
102
154
|
end
|
103
155
|
end
|
104
156
|
end
|
data/lib/smaak/smaak_service.rb
CHANGED
@@ -21,7 +21,7 @@ module Smaak
|
|
21
21
|
configure_services(configuration)
|
22
22
|
end
|
23
23
|
|
24
|
-
def configure_services(
|
24
|
+
def configure_services(_configuration = nil)
|
25
25
|
# @smaak_server.set_public_key(File.read('/service-provider-pub.pem'))
|
26
26
|
# @smaak_server.add_association('service-client-01', File.read('service-client-01-public.pem'), 'pre-shared-key')
|
27
27
|
end
|
data/lib/smaak/utils.rb
CHANGED
data/lib/smaak/version.rb
CHANGED
data/smaak.gemspec
CHANGED
@@ -23,8 +23,9 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.3"
|
24
24
|
spec.add_development_dependency "rake", "~> 10.5.0"
|
25
25
|
spec.add_development_dependency "byebug"
|
26
|
-
spec.add_development_dependency '
|
27
|
-
spec.add_development_dependency 'simplecov
|
26
|
+
spec.add_development_dependency 'coveralls'
|
27
|
+
# spec.add_development_dependency 'simplecov', "~> 0.11.1"
|
28
|
+
# spec.add_development_dependency 'simplecov-rcov', "~> 0.2.3"
|
28
29
|
spec.add_development_dependency 'rspec', "~> 3.4.0"
|
29
30
|
spec.add_development_dependency 'rack', "~> 1.6.4"
|
30
31
|
end
|
@@ -58,17 +58,17 @@ describe Smaak::NetHttpAdaptor do
|
|
58
58
|
one = true if header == "one" and value == "1"
|
59
59
|
two = true if header == "two" and value == "2"
|
60
60
|
end
|
61
|
-
expect(count).to eq(5) #some default headers come with a vanilla request
|
61
|
+
expect(count).to eq(5) # some default headers come with a vanilla request
|
62
62
|
expect(one).to eq(true)
|
63
63
|
expect(two).to eq(true)
|
64
64
|
end
|
65
65
|
|
66
66
|
it "should not iterate any headers if there are no headers set" do
|
67
67
|
count = 0
|
68
|
-
@iut.each_header do |
|
68
|
+
@iut.each_header do |_header, _value|
|
69
69
|
count = count + 1
|
70
70
|
end
|
71
|
-
expect(count).to eq(3) #some default headers come with a vanilla request
|
71
|
+
expect(count).to eq(3) # some default headers come with a vanilla request
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -17,7 +17,7 @@ describe Smaak::AuthMessage do
|
|
17
17
|
|
18
18
|
before :each do
|
19
19
|
@test_expires = Time.now.to_i + @test_token_life
|
20
|
-
@iut = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto
|
20
|
+
@iut = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto.obfuscate_psk(@test_psk), @test_recipient, @test_encrypt)
|
21
21
|
end
|
22
22
|
|
23
23
|
context "when initialized" do
|
@@ -76,7 +76,7 @@ describe Smaak::AuthMessage do
|
|
76
76
|
end
|
77
77
|
|
78
78
|
it "should remember the psk provided" do
|
79
|
-
expect(@iut.psk).to eq(Smaak::Crypto
|
79
|
+
expect(@iut.psk).to eq(Smaak::Crypto.obfuscate_psk(@test_psk))
|
80
80
|
end
|
81
81
|
|
82
82
|
it "should remember the recipient provided" do
|
@@ -88,23 +88,23 @@ describe Smaak::AuthMessage do
|
|
88
88
|
end
|
89
89
|
|
90
90
|
it "should translate the encrypt parameter from string to boolean" do
|
91
|
-
iut = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto
|
91
|
+
iut = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto.obfuscate_psk(@test_psk), @test_recipient, false)
|
92
92
|
expect(iut.encrypt).to eq(false)
|
93
93
|
|
94
|
-
iut = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto
|
94
|
+
iut = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto.obfuscate_psk(@test_psk), @test_recipient, true)
|
95
95
|
expect(iut.encrypt).to eq(true)
|
96
96
|
|
97
|
-
iut = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto
|
97
|
+
iut = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto.obfuscate_psk(@test_psk), @test_recipient, "false")
|
98
98
|
expect(iut.encrypt).to eq(false)
|
99
99
|
|
100
|
-
iut = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto
|
100
|
+
iut = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto.obfuscate_psk(@test_psk), @test_recipient, "true")
|
101
101
|
expect(iut.encrypt).to eq(true)
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
105
|
context "when asked if it has expired" do
|
106
106
|
it "should return true if the current timestamp exceeds that of the message expiry" do
|
107
|
-
iut = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, Time.now - 1, Smaak::Crypto
|
107
|
+
iut = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, Time.now - 1, Smaak::Crypto.obfuscate_psk(@test_psk), @test_recipient, false)
|
108
108
|
expect(iut.expired?).to eq(true)
|
109
109
|
end
|
110
110
|
|
@@ -141,7 +141,7 @@ describe Smaak::AuthMessage do
|
|
141
141
|
context "when asked to verify the message" do
|
142
142
|
it "should try and match the PSK and return false if it cannot" do
|
143
143
|
expect(@iut).to(receive(:psk_match?)).and_return(false)
|
144
|
-
expect(@iut.verify(Smaak::Crypto
|
144
|
+
expect(@iut.verify(Smaak::Crypto.obfuscate_psk(@test_psk))).to eq(false)
|
145
145
|
end
|
146
146
|
|
147
147
|
it "should return true if the message was successfully verified" do
|
@@ -152,15 +152,15 @@ describe Smaak::AuthMessage do
|
|
152
152
|
context "when asked to create an AuthMessage from scratch" do
|
153
153
|
it "should initialize with the recipient_public_key, psk, expires, identifier, nonce, encrypt provided, calculating expiry, generating a nonce, and obfuscating the PSK" do
|
154
154
|
allow(Smaak::Crypto).to receive(:generate_nonce).and_return(@test_nonce)
|
155
|
-
expect(Smaak::AuthMessage).to receive(:new).with(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto
|
155
|
+
expect(Smaak::AuthMessage).to receive(:new).with(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto.obfuscate_psk(@test_psk), @test_recipient, @test_encrypt)
|
156
156
|
Smaak::AuthMessage.create(@test_recipient, @test_psk, @test_token_life, @test_identifier, @test_route_info, @test_encrypt)
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
160
|
context "when asked to build an AuthMessage from existing data" do
|
161
161
|
it "should initialize with the recipient_public_key, psk, expires, identifier, nonce, encrypt provided" do
|
162
|
-
expect(Smaak::AuthMessage).to receive(:new).with(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto
|
163
|
-
Smaak::AuthMessage.build(@test_recipient, Smaak::Crypto
|
162
|
+
expect(Smaak::AuthMessage).to receive(:new).with(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto.obfuscate_psk(@test_psk), @test_recipient, @test_encrypt)
|
163
|
+
Smaak::AuthMessage.build(@test_recipient, Smaak::Crypto.obfuscate_psk(@test_psk), @test_expires, @test_identifier, @test_route_info, @test_nonce, @test_encrypt)
|
164
164
|
end
|
165
165
|
end
|
166
166
|
end
|
@@ -21,7 +21,7 @@ describe Smaak::Cavage04 do
|
|
21
21
|
@test_route_info = 'identifier'
|
22
22
|
@test_recipient = @test_server_public_key.export
|
23
23
|
@test_encrypt = true
|
24
|
-
@auth_message = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto
|
24
|
+
@auth_message = Smaak::AuthMessage.new(@test_identifier, @test_route_info, @test_nonce, @test_expires, Smaak::Crypto.obfuscate_psk(@test_psk), @test_recipient, @test_encrypt)
|
25
25
|
end
|
26
26
|
|
27
27
|
context "as a specification implementation" do
|
@@ -31,14 +31,14 @@ describe Smaak::Cavage04 do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
it "should provide a list of headers to be signed" do
|
34
|
-
expect(Smaak::Cavage04
|
35
|
-
expect(Smaak::Cavage04
|
36
|
-
expect(Smaak::Cavage04
|
37
|
-
expect(Smaak::Cavage04
|
34
|
+
expect(Smaak::Cavage04.headers_to_be_signed.include? "host").to eq(true)
|
35
|
+
expect(Smaak::Cavage04.headers_to_be_signed.include? "date").to eq(true)
|
36
|
+
expect(Smaak::Cavage04.headers_to_be_signed.include? "digest").to eq(true)
|
37
|
+
expect(Smaak::Cavage04.headers_to_be_signed.include? "content-length").to eq(true)
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should indicate that the specification specific header (request-target) is to be signed" do
|
41
|
-
expect(Smaak::Cavage04
|
41
|
+
expect(Smaak::Cavage04.headers_to_be_signed.include? "(request-target)").to eq(true)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -54,10 +54,10 @@ describe Smaak::Cavage04 do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
it "should set its headers to be signed to that of the specification and that of Smaak" do
|
57
|
-
Smaak::Cavage04
|
57
|
+
Smaak::Cavage04.headers_to_be_signed.each do |header|
|
58
58
|
expect(@iut.headers_to_be_signed.include? header).to eq(true)
|
59
59
|
end
|
60
|
-
Smaak
|
60
|
+
Smaak.headers_to_be_signed.each do |header|
|
61
61
|
expect(@iut.headers_to_be_signed.include? header).to eq(true)
|
62
62
|
end
|
63
63
|
end
|
@@ -217,7 +217,7 @@ describe Smaak::Cavage04 do
|
|
217
217
|
end
|
218
218
|
|
219
219
|
it "should return the signature headers in the order expressed in the signature, so that signature verification can succeed" do
|
220
|
-
#host date digest x-smaak-recipient x-smaak-identifier x-smaak-route-info x-smaak-psk x-smaak-expires x-smaak-nonce x-smaak-encrypt content-length
|
220
|
+
# host date digest x-smaak-recipient x-smaak-identifier x-smaak-route-info x-smaak-psk x-smaak-expires x-smaak-nonce x-smaak-encrypt content-length
|
221
221
|
expect(@iut.extract_signature_headers).to eq(\
|
222
222
|
"(request-target): post /secure-service\nhost: service-provider-internal\ndate: 2015-06-23 13:40:07 GMT\ndigest: SHA-256=748957b58cc24d2bb9eb8f9c468571712a14f6a89ce936c0fb2d3c5016e4dbdc\nx-smaak-recipient: LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUFxL2tiYjdBNWllQWV1WlBBVnI3MAo5cjl1TkFzc2dmYkdjeGMzZTc3RDNndkY4U2tzbURNQmQyTUt5TUh0ZjBrM1pqSVdZemJJVG5jQXM1Nnd4cmRSClhiVHpIZnhjMll1dDMwd0ljR2YvUVk4ZTJXNmdMWko4aVM3MXlYb0JQNFpEc2lLSXd4ajFsenYyVFlXWnNSL3EKd28xSzBxZ1NzOXJJVEVkWDVqampycHBYWTdobHNPMGVKQ2JBRG0weEtnU1hMcFQycnJzUnJ2OFllRXFvZTRMaQpDOFd6RjZZRlh1U3RHR1E4SXlxbjdPaTN5aVU2WFc3OTl2cFpIeHJlaERYaytDalZuU0ZXWkVPUHg3cENpam9SCnlXb0gyUmR6QVpQczdVdVJWOUdGWWFQeHRudmttNVdVZDVTdWVCNlMxT2E4dVZ3UnpyeXl6WkRjdG0xdWs1VjIKUE0zLzFqbFJMbFJzTWxSeHdZUDRzaFMzVlhjTkdGYjkvbzkvTjkzbitKZUFpSGd4YU5pQjN6YVV0a05XWWs0Vgozang2d0psTythOUNxdGJJeXg2ZzdyTHhOanVqRFpRZTZGcUdsMzVkVDR5MHA2UmVuUWQ4b1p5aWw3dlpqSkJaCjluTWRJblMyU05wWUZFclBsb25rdXNZKzZsam9TbFNLMXVSRmd2S3dzeGE3RmROMXZWSnRJQk9qdVJzSk9DaHYKOTB2K0ZEQWwxSnNZVUNPUnByUmtMWXB2TWI4Q1BZaUlzb3JmTUdKNnI3NktYUEIzRS9xejRmaWJ1UmZVeWJxMgp5eGxRTVJKb216d1BPemUrbWRQUU5Hd3VTTjU0VnByYXhoNGFpcWtaUVBsSWpRb1dFaFVKRWxMb0NtQXZ4TmtxCmRBcVZJMXZ3cS9FRXFBTEh3amJKRXIwQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=\nx-smaak-identifier: service-provider-public\nx-smaak-route-info: \nx-smaak-psk: 917e5f9bcf6d7c20a338d8a39bbf79ef\nx-smaak-expires: 1435066809\nx-smaak-nonce: 6457661831\nx-smaak-encrypt: false\ncontent-length: 25")
|
223
223
|
end
|
@@ -4,7 +4,7 @@ describe Smaak::Crypto do
|
|
4
4
|
before :all do
|
5
5
|
@private_key = OpenSSL::PKey::RSA.new(4096)
|
6
6
|
@data = {'a' => 'B'}.to_json
|
7
|
-
@bdata = Base64
|
7
|
+
@bdata = Base64.strict_encode64(@data)
|
8
8
|
@digest = OpenSSL::Digest::SHA256.new
|
9
9
|
@signature = @private_key.sign(@digest, @bdata)
|
10
10
|
@public_key = @private_key.public_key
|
@@ -12,22 +12,22 @@ describe Smaak::Crypto do
|
|
12
12
|
|
13
13
|
context "when asked to obfuscate a clear-text psk" do
|
14
14
|
it "should reverse the psk and apply an MD5 hexadecimal digest to the result" do
|
15
|
-
expect(Smaak::Crypto
|
15
|
+
expect(Smaak::Crypto.obfuscate_psk('sharedsecret')).to eq(Digest::MD5.hexdigest('sharedsecret'.reverse))
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
context "when asked to generate a nonce" do
|
20
20
|
it "should generate a random nonce with at most 1 in a ten billion probability of a consecutive clash" do
|
21
21
|
expect(SecureRandom).to receive(:random_number).with(10000000000)
|
22
|
-
Smaak::Crypto
|
22
|
+
Smaak::Crypto.generate_nonce
|
23
23
|
end
|
24
24
|
|
25
25
|
it "should generate a different nonce every time with high probability (less than 1 in 10000) given a history of 1000000 nonces" do
|
26
26
|
repeat = {}
|
27
27
|
failed = 0
|
28
28
|
threshold = 1000000
|
29
|
-
|
30
|
-
value = Smaak::Crypto
|
29
|
+
threshold.times do
|
30
|
+
value = Smaak::Crypto.generate_nonce
|
31
31
|
failed = failed + 1 if repeat[value] == 1
|
32
32
|
repeat[value] = 1
|
33
33
|
end
|
@@ -40,47 +40,47 @@ describe Smaak::Crypto do
|
|
40
40
|
context "when asked to encode data using base 64" do
|
41
41
|
it "should encode the data without newlines or line feeds using base 64 (strict)" do
|
42
42
|
data = "some data"
|
43
|
-
expect(Smaak::Crypto
|
43
|
+
expect(Smaak::Crypto.encode64(data)).to eq(Base64.strict_encode64(data))
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
context "when asked to decode data using base 64" do
|
48
48
|
it "should decode the data using base 64 (strict)" do
|
49
|
-
expect(Smaak::Crypto
|
49
|
+
expect(Smaak::Crypto.decode64(Base64.strict_encode64("some data"))).to eq("some data")
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
context "when asked to sign data given a private key" do
|
54
54
|
it "should sign a strict Base64 representation of the data with the key using a 256 bit SHA digest" do
|
55
|
-
expect(Smaak::Crypto
|
55
|
+
expect(Smaak::Crypto.sign_data(@data, @private_key)).to eq(@signature)
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
context "when asked to verify a signature given data and a public key" do
|
60
60
|
it "should verify using a 256 bit SHA digest" do
|
61
61
|
expect(OpenSSL::Digest::SHA256).to receive(:new).and_return(@digest)
|
62
|
-
Smaak::Crypto
|
62
|
+
Smaak::Crypto.verify_signature(@signature, @bdata, @public_key)
|
63
63
|
end
|
64
64
|
|
65
65
|
it "should return true when the signature is verified by the public key" do
|
66
|
-
expect(Smaak::Crypto
|
66
|
+
expect(Smaak::Crypto.verify_signature(@signature, @bdata, @public_key)).to eq(true)
|
67
67
|
end
|
68
68
|
|
69
69
|
it "should return false when the signature cannot be verified by the public key" do
|
70
70
|
other_key = OpenSSL::PKey::RSA.new(4096).public_key
|
71
|
-
expect(Smaak::Crypto
|
71
|
+
expect(Smaak::Crypto.verify_signature(@signature, @bdata, other_key)).to eq(false)
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
75
|
context "when asked to encrypt data given a public key" do
|
76
76
|
it "should return a base64 representation of the data encrypted with the public key" do
|
77
|
-
expect(@private_key.private_decrypt(Base64.strict_decode64(Smaak::Crypto
|
77
|
+
expect(@private_key.private_decrypt(Base64.strict_decode64(Smaak::Crypto.encrypt(@data, @public_key)))).to eq(@data)
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
81
|
context "when asked to decrypt encrypted data given a private key" do
|
82
82
|
it "should return a decryption using the private key of a base64 decode of the data" do
|
83
|
-
expect(Smaak::Crypto
|
83
|
+
expect(Smaak::Crypto.decrypt(Base64.strict_encode64(@public_key.public_encrypt(@data)), @private_key)).to eq(@data)
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
@@ -88,7 +88,7 @@ describe Smaak::Crypto do
|
|
88
88
|
it "should sink all data from the stream, collating when nil is read" do
|
89
89
|
mock_stream = double(Object)
|
90
90
|
allow(mock_stream).to receive(:gets).and_return("a", "b", nil)
|
91
|
-
expect(Smaak::Crypto
|
91
|
+
expect(Smaak::Crypto.sink(mock_stream)).to eq("ab")
|
92
92
|
end
|
93
93
|
end
|
94
94
|
end
|