smaak 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|