fast_secure_compare 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +19 -0
- data/README.md +39 -0
- data/Rakefile +21 -0
- data/ext/Rakefile +3 -0
- data/ext/fast_secure_compare/secure_compare.c +15 -0
- data/fast_secure_compare.gemspec +27 -0
- data/lib/fast_secure_compare.rb +17 -0
- data/spec/fast_secure_compare_spec.rb +17 -0
- metadata +97 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1b49fc77195a730ff81966f32d327f2e4eafda4b
|
4
|
+
data.tar.gz: cc68be175b411a1d1f6867d8e9a7f0443269be40
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d1bd92fc4dcc15967c9e2dc614bf492c6722c10e898fc3e5a8cf2121739ec8da1dd12b7093e5daddcfaed20f08c2083ec4a984b8ba7620ae25b16186d193ad92
|
7
|
+
data.tar.gz: f473788cc8c4c789f02d9262593290f5e8e0eb4a12024d73f0099592ce622642215d367bb0ae17b4679e74bb48ac9da5c08e7377bd4245dfe8b4950a34f2592e
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2014 Daniel Axtens
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
This gem provides a simple, fast way to do string comparisons that resist timing attacks.
|
2
|
+
|
3
|
+
# What is a timing attack? #
|
4
|
+
A timing attack is an attack on a system that determines secret information based on how long an operation takes.
|
5
|
+
|
6
|
+
Timing attacks are particularly prevalent (and dangerous) in cryptographic operations, but they can also sneak into other types of operation.
|
7
|
+
|
8
|
+
In particular, any time you are **comparing user specified input with a secret**, you should consider whether or not you are exposing yourself to a timing attack.
|
9
|
+
|
10
|
+
The attack is probably best described by [Nate Lawson](http://rdist.root.org/2010/07/19/exploiting-remote-timing-attacks/):
|
11
|
+
|
12
|
+
> The attack is very simple. You repeatedly send guesses about a secret value to the server, which rejects them as incorrect. However, if your first byte of the guess is correct, it takes a very slightly longer time to return the error. With many measurements and some filtering, you can distinguish this difference.
|
13
|
+
|
14
|
+
Therefore, it's important that the amount of time these operations take depends *only* on the length of the user's input, and *not* on any characteristic of the secret data.
|
15
|
+
|
16
|
+
# How does this gem help? Why should I use it rather than rolling my own? #
|
17
|
+
|
18
|
+
This gem provides a secure comparison function that is:
|
19
|
+
|
20
|
+
- very simple: 1 class, 1 method
|
21
|
+
- fast: it uses a C back-end rather than a pure Ruby implementation.
|
22
|
+
- portable: the C code is platform independent
|
23
|
+
|
24
|
+
Furthermore, unlike some other secure comparison fuctions, the code does not require that the strings are the same length, and should not leak the length of the string if the string lengths do not match.
|
25
|
+
|
26
|
+
If you're interested in seeing how much faster you can make your code by using this gem, check out the demo folder.
|
27
|
+
|
28
|
+
# How do I use this gem in my code? #
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
|
32
|
+
import 'fast_secure_compare'
|
33
|
+
|
34
|
+
FastSecureCompare.compare(my_secret, user_input)
|
35
|
+
```
|
36
|
+
|
37
|
+
# Is there anything else I should know? #
|
38
|
+
|
39
|
+
The gem is not foolproof. In particular, it can't protect you against anything designed to exploit cache misses or any other more elaborate form of timing attack. However, none of the existing pure Ruby secure_compare functions do either.
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# shamelessly ripped off https://github.com/cotag/http-parser/blob/master/Rakefile
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
|
7
|
+
task :default => [:compile, :test]
|
8
|
+
|
9
|
+
task :compile do
|
10
|
+
protect = ['secure_compare.c']
|
11
|
+
Dir["ext/fast_secure_compare/**/*"].each do |file|
|
12
|
+
begin
|
13
|
+
next if protect.include? File.basename(file)
|
14
|
+
FileUtils.rm file
|
15
|
+
rescue
|
16
|
+
end
|
17
|
+
end
|
18
|
+
system 'cd ext && rake'
|
19
|
+
end
|
20
|
+
|
21
|
+
RSpec::Core::RakeTask.new(:test)
|
data/ext/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
int secure_compare_bytes(const unsigned char * secret, unsigned int secret_len,
|
2
|
+
const unsigned char * input, unsigned int input_len) {
|
3
|
+
|
4
|
+
int input_pos;
|
5
|
+
int secret_pos = 0;
|
6
|
+
int result = secret_len - input_len;
|
7
|
+
// make sure our time isn't dependent on secret_len, and only dependent
|
8
|
+
// on input_len
|
9
|
+
for (input_pos = 0; input_pos < input_len; input_pos++) {
|
10
|
+
result |= input[input_pos] ^ secret[secret_pos];
|
11
|
+
secret_pos = (secret_pos + 1) % secret_len;
|
12
|
+
}
|
13
|
+
|
14
|
+
return result;
|
15
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'fast_secure_compare'
|
3
|
+
s.version = '0.0.2'
|
4
|
+
s.date = '2014-08-17'
|
5
|
+
s.summary = "A fast, simple way to do constant time string comparisons."
|
6
|
+
s.description = "A secure_comparison function implemented in C for blazing speed."
|
7
|
+
s.authors = ["Daniel Axtens"]
|
8
|
+
s.email = 'daniel@axtens.net'
|
9
|
+
s.homepage =
|
10
|
+
'https://github.com/daxtens/fast_secure_compare'
|
11
|
+
s.license = 'MIT'
|
12
|
+
|
13
|
+
|
14
|
+
s.add_dependency 'ffi-compiler', '>= 0.0.2'
|
15
|
+
s.add_dependency 'rake'
|
16
|
+
|
17
|
+
s.add_development_dependency 'rspec'
|
18
|
+
|
19
|
+
s.files = Dir["{lib}/**/*"] + %w(Rakefile fast_secure_compare.gemspec README.md LICENSE)
|
20
|
+
s.files += ["ext/fast_secure_compare/secure_compare.c"]
|
21
|
+
s.test_files = Dir["spec/**/*"]
|
22
|
+
s.extra_rdoc_files = ["README.md"]
|
23
|
+
|
24
|
+
s.extensions << "ext/Rakefile"
|
25
|
+
s.require_paths = ["lib"]
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'ffi-compiler/loader'
|
3
|
+
|
4
|
+
module FastSecureCompare
|
5
|
+
extend FFI::Library
|
6
|
+
ffi_lib FFI::Compiler::Loader.find('fast_secure_compare')
|
7
|
+
|
8
|
+
attach_function :secure_compare_bytes, [:pointer, :uint, :pointer, :uint], :int
|
9
|
+
|
10
|
+
def self.compare(secret, input)
|
11
|
+
sBuf = FFI::MemoryPointer.new(:char, secret.size)
|
12
|
+
sBuf.put_bytes(0, secret)
|
13
|
+
iBuf = FFI::MemoryPointer.new(:char, input.size)
|
14
|
+
iBuf.put_bytes(0, input)
|
15
|
+
secure_compare_bytes(secret, secret.size, input, input.size) == 0
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'fast_secure_compare'
|
2
|
+
|
3
|
+
describe FastSecureCompare, "#compare" do
|
4
|
+
it "returns true on equal strings" do
|
5
|
+
expect(FastSecureCompare.compare("aaa","aaa")).to eq(true)
|
6
|
+
end
|
7
|
+
it "returns false on an empty string" do
|
8
|
+
expect(FastSecureCompare.compare("aaa","")).to eq(false)
|
9
|
+
end
|
10
|
+
it "returns false on different strings of different length" do
|
11
|
+
expect(FastSecureCompare.compare("aaa","a")).to eq(false)
|
12
|
+
expect(FastSecureCompare.compare("aaa","aaaaaa")).to eq(false)
|
13
|
+
end
|
14
|
+
it "returns false on different strings of equal length" do
|
15
|
+
expect(FastSecureCompare.compare("aaa","bbb")).to eq(false)
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fast_secure_compare
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Axtens
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi-compiler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.0.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.0.2
|
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: :runtime
|
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: rspec
|
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 secure_comparison function implemented in C for blazing speed.
|
56
|
+
email: daniel@axtens.net
|
57
|
+
executables: []
|
58
|
+
extensions:
|
59
|
+
- ext/Rakefile
|
60
|
+
extra_rdoc_files:
|
61
|
+
- README.md
|
62
|
+
files:
|
63
|
+
- lib/fast_secure_compare.rb
|
64
|
+
- Rakefile
|
65
|
+
- fast_secure_compare.gemspec
|
66
|
+
- README.md
|
67
|
+
- LICENSE
|
68
|
+
- ext/fast_secure_compare/secure_compare.c
|
69
|
+
- spec/fast_secure_compare_spec.rb
|
70
|
+
- ext/Rakefile
|
71
|
+
homepage: https://github.com/daxtens/fast_secure_compare
|
72
|
+
licenses:
|
73
|
+
- MIT
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.0.6
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: A fast, simple way to do constant time string comparisons.
|
95
|
+
test_files:
|
96
|
+
- spec/fast_secure_compare_spec.rb
|
97
|
+
has_rdoc:
|