dionysus 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/dionysus.gemspec +2 -2
- data/lib/dionysus/digest.rb +47 -17
- data/lib/dionysus/security/password_salt.rb +3 -11
- data/lib/dionysus/security/string.rb +22 -11
- data/lib/dionysus/string.rb +1 -0
- data/spec/digest_spec.rb +66 -8
- data/spec/password_salt_spec.rb +10 -0
- data/spec/string_security_spec.rb +22 -0
- metadata +3 -3
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.1
|
data/dionysus.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{dionysus}
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Travis D. Warlick, Jr."]
|
12
|
-
s.date = %q{2010-04-
|
12
|
+
s.date = %q{2010-04-04}
|
13
13
|
s.email = %q{warlickt@operissystems.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"LICENSE",
|
data/lib/dionysus/digest.rb
CHANGED
@@ -65,21 +65,15 @@ module Digest
|
|
65
65
|
##
|
66
66
|
# The lengths of the registered digests in the given encoding.
|
67
67
|
def self.digest_lengths( encoding = :binary )
|
68
|
-
if encoding
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
when :hex, :hexidecimal then 4
|
73
|
-
when :bit then 1
|
74
|
-
else raise ArgumentError, "Invalid encoding"
|
75
|
-
end
|
68
|
+
if encoding == :bit or encoding == 1
|
69
|
+
_digest_lengths(1)
|
70
|
+
elsif encoding.is_a?(Symbol) and String::ENCODING_BITS_PER_CHAR[encoding]
|
71
|
+
_digest_lengths(String::ENCODING_BITS_PER_CHAR[encoding])
|
76
72
|
elsif encoding.is_a?(Integer) and encoding > 0
|
77
|
-
|
73
|
+
_digest_lengths(encoding)
|
78
74
|
else
|
79
75
|
raise ArgumentError, "Invalid encoding"
|
80
76
|
end
|
81
|
-
|
82
|
-
Hash[ self.digests.collect { |dig, info| [dig, info[:bit_length] / bits_per_char] } ]
|
83
77
|
end
|
84
78
|
|
85
79
|
##
|
@@ -89,12 +83,48 @@ module Digest
|
|
89
83
|
#
|
90
84
|
# Digest.digest(:sha512, 'foobar') #=> binary digest
|
91
85
|
# Digest.digest(Digest::SHA512, 'foobar') #=> binary digest
|
92
|
-
def self.digest(
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
86
|
+
def self.digest( sym, str )
|
87
|
+
Digest.const_get(sym.to_s.upcase).digest(str)
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# Detect the digest of the string. Returns nil if the digest cannot be
|
92
|
+
# determined.
|
93
|
+
#
|
94
|
+
# Example:
|
95
|
+
# Digest.detect_digest("wxeCFXPVXePFcpwuFDjonyn1G/w=", :base64) #=> :sha1
|
96
|
+
# Digest.detect_digest("foobar", :hex) #=> nil
|
97
|
+
def self.detect_digest( string, encoding = :binary )
|
98
|
+
string = string.strip unless encoding == :binary
|
99
|
+
dig = self.digest_lengths(encoding).invert[string.length]
|
100
|
+
dig = :sha256 if dig == :sha2
|
101
|
+
dig
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Detect the digest of the string. Returns nil if the digest cannot be
|
106
|
+
# determined.
|
107
|
+
#
|
108
|
+
# Example:
|
109
|
+
# Digest.detect_digest!("wxeCFXPVXePFcpwuFDjonyn1G/w=", :base64) #=> :sha1
|
110
|
+
# Digest.detect_digest!("foobar", :hex) #=> RuntimeError
|
111
|
+
def self.detect_digest!( string, encoding = :binary )
|
112
|
+
self.detect_digest(string, encoding) or raise("Unknown digest")
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def self._digest_lengths( bits_per_char ) # :nodoc:
|
118
|
+
padding_factor = (bits_per_char.lcm(8) / bits_per_char)
|
119
|
+
|
120
|
+
returning result={} do
|
121
|
+
self.digests.each do |dig, info|
|
122
|
+
result[dig] = len = info[:bit_length] / bits_per_char
|
123
|
+
if (t_ = len % padding_factor) != 0
|
124
|
+
result[dig] = len + (padding_factor - t_)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
98
128
|
end
|
99
129
|
end
|
100
130
|
|
@@ -77,19 +77,11 @@ class PasswordSalt
|
|
77
77
|
# Default: 8
|
78
78
|
def initialize( *args )
|
79
79
|
options = args.extract_options!
|
80
|
-
if args[0].nil? or args[0] == :new or args[0].is_a?(String)
|
81
|
-
self.string = args[0] || :new
|
82
|
-
end
|
83
80
|
|
84
|
-
|
85
|
-
|
86
|
-
elsif args[1].is_a?(Symbol)
|
87
|
-
self.placement = args[1]
|
88
|
-
else
|
89
|
-
self.placement = DEFAULT_PLACEMENT
|
90
|
-
end
|
81
|
+
self.string = args.detect { |val| val.is_a?(String) or val == :new }
|
82
|
+
self.placement = args.detect { |val| PLACEMENTS.include?(val) } || DEFAULT_PLACEMENT
|
91
83
|
|
92
|
-
if self.string == :new
|
84
|
+
if self.string == :new or self.string.nil?
|
93
85
|
self.string = self.class.generate(options[:length] || DEFAULT_LENGTH)
|
94
86
|
end
|
95
87
|
end
|
@@ -53,22 +53,33 @@ class String
|
|
53
53
|
def method_missing( method, *args )
|
54
54
|
super if block_given?
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
if Digest.available_digests.include?(method)
|
57
|
+
self.digest(method, *args)
|
58
|
+
else
|
59
|
+
super
|
59
60
|
end
|
60
|
-
super
|
61
61
|
end
|
62
62
|
|
63
63
|
##
|
64
|
-
# Detect the digest of the string
|
64
|
+
# Detect the digest of the string. Returns nil if the digest cannot be
|
65
|
+
# determined.
|
66
|
+
#
|
67
|
+
# Example:
|
68
|
+
# "wxeCFXPVXePFcpwuFDjonyn1G/w=".detect_digest(:base64) #=> :sha1
|
69
|
+
# "foobar".detect_digest(:hex) #=> nil
|
65
70
|
def detect_digest( encoding )
|
66
|
-
self
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
71
|
+
Digest.detect_digest(self, encoding)
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Detect the digest of the string. Raises "Unknown digest" if the digest
|
76
|
+
# cannot be determined.
|
77
|
+
#
|
78
|
+
# Example:
|
79
|
+
# "wxeCFXPVXePFcpwuFDjonyn1G/w=".detect_digest!(:base64) #=> :sha1
|
80
|
+
# "foobar".detect_digest!(:hex) #=> RuntimeError
|
81
|
+
def detect_digest!( encoding )
|
82
|
+
Digest.detect_digest!(self, encoding)
|
72
83
|
end
|
73
84
|
|
74
85
|
private
|
data/lib/dionysus/string.rb
CHANGED
data/spec/digest_spec.rb
CHANGED
@@ -3,6 +3,8 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
3
3
|
require 'dionysus/digest'
|
4
4
|
|
5
5
|
describe Digest do
|
6
|
+
DIGESTS = { :md5 => 128, :sha1 => 160, :sha2 => 256,
|
7
|
+
:sha256 => 256, :sha384 => 384, :sha512 => 512 }
|
6
8
|
it 'should have the default available digests' do
|
7
9
|
Digest.available_digests.length.should == Digest::DEFAULT_DIGESTS.length
|
8
10
|
Digest::DEFAULT_DIGESTS.each do |dig|
|
@@ -87,8 +89,7 @@ describe Digest do
|
|
87
89
|
end
|
88
90
|
|
89
91
|
describe 'digest lengths' do
|
90
|
-
|
91
|
-
:sha256 => 256, :sha384 => 384, :sha512 => 512 }.each do |dig, bits|
|
92
|
+
DIGESTS.each do |dig, bits|
|
92
93
|
it "should have binary length for #{dig}" do
|
93
94
|
Digest.digest_lengths[dig].should == bits / 8
|
94
95
|
Digest.digest_lengths(:binary)[dig].should == bits / 8
|
@@ -102,8 +103,10 @@ describe Digest do
|
|
102
103
|
end
|
103
104
|
|
104
105
|
it "should have base64 length for #{dig}" do
|
105
|
-
|
106
|
-
|
106
|
+
len = bits / 6
|
107
|
+
expected = (len % 4 == 0 ? len : len + (4 - len % 4))
|
108
|
+
Digest.digest_lengths(:base64)[dig].should == expected
|
109
|
+
Digest.digest_lengths(6)[dig].should == expected
|
107
110
|
end
|
108
111
|
|
109
112
|
it "should have bit length for #{dig}" do
|
@@ -112,14 +115,69 @@ describe Digest do
|
|
112
115
|
end
|
113
116
|
|
114
117
|
it "should have arbitrary length for #{dig}" do
|
115
|
-
|
118
|
+
len = bits / 7
|
119
|
+
Digest.digest_lengths(7)[dig].should == len + (8 - len % 8)
|
116
120
|
end
|
117
121
|
end
|
118
122
|
|
119
123
|
it 'should reject bit length requests for < 0' do
|
120
|
-
lambda { Digest.digest_lengths(0).should raise_error(ArgumentError, 'Invalid encoding')
|
121
|
-
lambda { Digest.digest_lengths(-1).should raise_error(ArgumentError, 'Invalid encoding')
|
122
|
-
lambda { Digest.digest_lengths(-100).should raise_error(ArgumentError, 'Invalid encoding')
|
124
|
+
lambda { Digest.digest_lengths(0) }.should raise_error(ArgumentError, 'Invalid encoding')
|
125
|
+
lambda { Digest.digest_lengths(-1) }.should raise_error(ArgumentError, 'Invalid encoding')
|
126
|
+
lambda { Digest.digest_lengths(-100) }.should raise_error(ArgumentError, 'Invalid encoding')
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should reject bit length requests for unknown encodings' do
|
130
|
+
lambda { Digest.digest_lengths(:my_digest) }.should raise_error(ArgumentError, 'Invalid encoding')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "digest helper" do
|
135
|
+
DIGESTS.each do |dig, bits|
|
136
|
+
it "should run the digest for #{dig}" do
|
137
|
+
Digest.digest(dig, 'foobar').length.should == bits / 8
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should still have working original digest methods" do
|
141
|
+
"Digest::#{dig.to_s.upcase}".constantize.digest('foobar').length.should == bits / 8
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should fail invalid digest" do
|
146
|
+
lambda { Digest.digest(:my_digest, 'foobar') }.should raise_error(LoadError)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "detection" do
|
151
|
+
DIGESTS.each do |dig, bits|
|
152
|
+
it "should detect #{dig} in binary" do
|
153
|
+
str = Digest.digest(dig, 'foobar')
|
154
|
+
Digest.detect_digest(str).should == (dig == :sha2 ? :sha256 : dig)
|
155
|
+
Digest.detect_digest(str, :binary).should == (dig == :sha2 ? :sha256 : dig)
|
156
|
+
Digest.detect_digest!(str).should == (dig == :sha2 ? :sha256 : dig)
|
157
|
+
Digest.detect_digest!(str, :binary).should == (dig == :sha2 ? :sha256 : dig)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should detect #{dig} in base64" do
|
161
|
+
str = Digest.digest(dig, 'foobar').encode64s
|
162
|
+
Digest.detect_digest(str, :base64).should == (dig == :sha2 ? :sha256 : dig)
|
163
|
+
Digest.detect_digest!(str, :base64).should == (dig == :sha2 ? :sha256 : dig)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should detect #{dig} in hexidecimal" do
|
167
|
+
str = Digest.digest(dig, 'foobar').encode_hexidecimal
|
168
|
+
Digest.detect_digest(str, :hex).should == (dig == :sha2 ? :sha256 : dig)
|
169
|
+
Digest.detect_digest(str, :hexidecimal).should == (dig == :sha2 ? :sha256 : dig)
|
170
|
+
Digest.detect_digest!(str, :hex).should == (dig == :sha2 ? :sha256 : dig)
|
171
|
+
Digest.detect_digest!(str, :hexidecimal).should == (dig == :sha2 ? :sha256 : dig)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should return nil on unknown digest" do
|
176
|
+
Digest.detect_digest('blah').should be_nil
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should fail on unknown digest with !" do
|
180
|
+
lambda { Digest.detect_digest!('blah') }.should raise_error(RuntimeError, "Unknown digest")
|
123
181
|
end
|
124
182
|
end
|
125
183
|
end
|
data/spec/password_salt_spec.rb
CHANGED
@@ -93,6 +93,10 @@ describe PasswordSalt do
|
|
93
93
|
salt.should_not match(/\A[A-Za-z0-9\+\/]{100}\Z/)
|
94
94
|
end
|
95
95
|
end
|
96
|
+
|
97
|
+
it "should raise an error with an invalid format" do
|
98
|
+
lambda { PasswordSalt.generate(10, :foobar) }.should raise_error(ArgumentError, "Invalid format: foobar")
|
99
|
+
end
|
96
100
|
end
|
97
101
|
|
98
102
|
describe "after placement" do
|
@@ -110,6 +114,12 @@ describe PasswordSalt do
|
|
110
114
|
salt = PasswordSalt.new(@salt, :after)
|
111
115
|
salt.salt_password(@password).should == @password+@salt
|
112
116
|
end
|
117
|
+
|
118
|
+
it "should raise an error with a bad placement" do
|
119
|
+
salt = PasswordSalt.new(@salt)
|
120
|
+
salt.instance_variable_set('@placement', :foobar)
|
121
|
+
lambda { salt.salt_password(@password) }.should raise_error(RuntimeError, "Invalid salt placement: foobar")
|
122
|
+
end
|
113
123
|
end
|
114
124
|
|
115
125
|
describe "before placement" do
|
@@ -179,4 +179,26 @@ describe String do
|
|
179
179
|
"abcde\240z405".digest(:md5, :encoding => :binary).should == digest
|
180
180
|
"abcde\240z405".md5(:encoding => :binary).should == digest
|
181
181
|
end
|
182
|
+
|
183
|
+
it "should fallback to super method missing with unavailable digest" do
|
184
|
+
lambda { "abcde\240z405".my_digest }.should raise_error(NoMethodError)
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should raise an error with invalid encoding" do
|
188
|
+
lambda { "abcde\240z405".md5(:encoding => :foobar) }.should raise_error(ArgumentError, 'Invalid encoding: foobar')
|
189
|
+
end
|
190
|
+
|
191
|
+
describe "digest detection" do
|
192
|
+
it "should defer to Digest" do
|
193
|
+
str = "abcde\240z405"
|
194
|
+
Digest.should_receive(:detect_digest).with(str, :binary)
|
195
|
+
str.detect_digest(:binary)
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should defer to Digest" do
|
199
|
+
str = "abcde\240z405"
|
200
|
+
Digest.should_receive(:detect_digest!).with(str, :binary)
|
201
|
+
str.detect_digest!(:binary)
|
202
|
+
end
|
203
|
+
end
|
182
204
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 3
|
8
|
-
-
|
9
|
-
version: 0.3.
|
8
|
+
- 1
|
9
|
+
version: 0.3.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Travis D. Warlick, Jr.
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-04-
|
17
|
+
date: 2010-04-04 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|