encrypted_strings 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +7 -0
- data/LICENSE +1 -1
- data/Rakefile +19 -17
- data/lib/encrypted_strings/sha_cipher.rb +79 -6
- data/test/sha_cipher_test.rb +74 -4
- metadata +20 -21
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
== master
|
2
2
|
|
3
|
+
== 0.3.3 / 2010-03-07
|
4
|
+
|
5
|
+
* Release gems via rake-gemcutter instead of rubyforge
|
6
|
+
* Add support for customizing how the SHA value gets built
|
7
|
+
* Allow methods or procs to be defined for dynamically generating SHA salts
|
8
|
+
* Add support for customizing the SHA encryption algorithm
|
9
|
+
|
3
10
|
== 0.3.2 / 2009-01-11
|
4
11
|
|
5
12
|
* Use Array#pack/String#unpack instead of Base64 to be compatible with Ruby 1.9+
|
data/LICENSE
CHANGED
data/Rakefile
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
1
3
|
require 'rake/testtask'
|
2
4
|
require 'rake/rdoctask'
|
3
5
|
require 'rake/gempackagetask'
|
4
|
-
require 'rake/contrib/sshpublisher'
|
5
6
|
|
6
7
|
spec = Gem::Specification.new do |s|
|
7
8
|
s.name = 'encrypted_strings'
|
8
|
-
s.version = '0.3.
|
9
|
+
s.version = '0.3.3'
|
9
10
|
s.platform = Gem::Platform::RUBY
|
10
|
-
s.summary = 'Dead-simple string encryption/decryption syntax
|
11
|
+
s.summary = 'Dead-simple string encryption/decryption syntax'
|
12
|
+
s.description = s.summary
|
11
13
|
|
12
14
|
s.files = FileList['{lib,test}/**/*'] + %w(CHANGELOG.rdoc init.rb LICENSE Rakefile README.rdoc)
|
13
15
|
s.require_path = 'lib'
|
@@ -49,23 +51,30 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
|
|
49
51
|
rdoc.rdoc_dir = 'rdoc'
|
50
52
|
rdoc.title = spec.name
|
51
53
|
rdoc.template = '../rdoc_template.rb'
|
52
|
-
rdoc.options << '--line-numbers'
|
54
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
53
55
|
rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc', 'LICENSE', 'lib/**/*.rb')
|
54
56
|
end
|
55
|
-
|
57
|
+
|
58
|
+
desc 'Generate a gemspec file.'
|
59
|
+
task :gemspec do
|
60
|
+
File.open("#{spec.name}.gemspec", 'w') do |f|
|
61
|
+
f.write spec.to_ruby
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
56
65
|
Rake::GemPackageTask.new(spec) do |p|
|
57
66
|
p.gem_spec = spec
|
58
|
-
p.need_tar = true
|
59
|
-
p.need_zip = true
|
60
67
|
end
|
61
68
|
|
62
69
|
desc 'Publish the beta gem.'
|
63
70
|
task :pgem => [:package] do
|
71
|
+
require 'rake/contrib/sshpublisher'
|
64
72
|
Rake::SshFilePublisher.new('aaron@pluginaweek.org', '/home/aaron/gems.pluginaweek.org/public/gems', 'pkg', "#{spec.name}-#{spec.version}.gem").upload
|
65
73
|
end
|
66
74
|
|
67
75
|
desc 'Publish the API documentation.'
|
68
76
|
task :pdoc => [:rdoc] do
|
77
|
+
require 'rake/contrib/sshpublisher'
|
69
78
|
Rake::SshDirPublisher.new('aaron@pluginaweek.org', "/home/aaron/api.pluginaweek.org/public/#{spec.name}", 'rdoc').upload
|
70
79
|
end
|
71
80
|
|
@@ -74,15 +83,8 @@ task :publish => [:pgem, :pdoc, :release]
|
|
74
83
|
|
75
84
|
desc 'Publish the release files to RubyForge.'
|
76
85
|
task :release => [:gem, :package] do
|
77
|
-
require '
|
78
|
-
|
79
|
-
ruby_forge = RubyForge.new.configure
|
80
|
-
ruby_forge.login
|
86
|
+
require 'rake/gemcutter'
|
81
87
|
|
82
|
-
|
83
|
-
|
84
|
-
puts "Releasing #{File.basename(file)}..."
|
85
|
-
|
86
|
-
ruby_forge.add_release(spec.rubyforge_project, spec.name, spec.version, file)
|
87
|
-
end
|
88
|
+
Rake::Gemcutter::Tasks.new(spec)
|
89
|
+
Rake::Task['gem:push'].invoke
|
88
90
|
end
|
@@ -9,6 +9,7 @@ module EncryptedStrings
|
|
9
9
|
# algorithm must be specified. You can define the default for this value
|
10
10
|
# like so:
|
11
11
|
#
|
12
|
+
# EncryptedStrings::ShaCipher.default_algorithm = 'sha512'
|
12
13
|
# EncryptedStrings::ShaCipher.default_salt = 'secret'
|
13
14
|
#
|
14
15
|
# If these configuration options are not passed in to #encrypt, then the
|
@@ -17,6 +18,25 @@ module EncryptedStrings
|
|
17
18
|
# password = 'shhhh'
|
18
19
|
# password.encrypt(:sha, :salt => 'secret') # => "ae645b35bb5dfea6c9133ac872e6adfa92a3c2bd"
|
19
20
|
#
|
21
|
+
# === Customizations
|
22
|
+
#
|
23
|
+
# In addition to customizing the algorithm, you can further tweak how values
|
24
|
+
# get encrypted by defining dynamic salts and how to build the value that
|
25
|
+
# actually gets hashed.
|
26
|
+
#
|
27
|
+
# For example:
|
28
|
+
#
|
29
|
+
# password = 'shhhh'
|
30
|
+
# password.encrypt(:sha,
|
31
|
+
# :salt => lambda {Time.now.to_s},
|
32
|
+
# :builder => lambda {|data, salt| "#{data}|#{salt}"}
|
33
|
+
# )
|
34
|
+
#
|
35
|
+
# The above example will generate a salt based on the current time and then
|
36
|
+
# use a custom builder for determining how the salt and data get concatenated
|
37
|
+
# to determine the value that gets hashed. This is particularly useful for
|
38
|
+
# providing compatibility with legacy systems.
|
39
|
+
#
|
20
40
|
# == Decrypting
|
21
41
|
#
|
22
42
|
# SHA-encrypted strings cannot be decrypted. The only way to determine
|
@@ -28,28 +48,55 @@ module EncryptedStrings
|
|
28
48
|
# password == input # => true
|
29
49
|
class ShaCipher < Cipher
|
30
50
|
class << self
|
51
|
+
# The default algorithm to use for encryption. Default is SHA1.
|
52
|
+
attr_accessor :default_algorithm
|
53
|
+
|
31
54
|
# The default salt value to use during encryption
|
32
55
|
attr_accessor :default_salt
|
56
|
+
|
57
|
+
# The default algorithm to use for building the value that gets hashed.
|
58
|
+
# Default is lambda {|data, salt| "#{data}#{salt}"}.
|
59
|
+
attr_accessor :default_builder
|
33
60
|
end
|
34
61
|
|
35
62
|
# Set defaults
|
63
|
+
@default_algorithm = 'SHA1'
|
36
64
|
@default_salt = 'salt'
|
65
|
+
@default_builder = lambda {|data, salt| "#{data}#{salt}"}
|
66
|
+
|
67
|
+
# The algorithm to use for encryption/decryption
|
68
|
+
attr_accessor :algorithm
|
37
69
|
|
38
70
|
# The salt value to use for encryption
|
39
71
|
attr_accessor :salt
|
40
72
|
|
73
|
+
# The function to use to build the value that gets hashed
|
74
|
+
attr_accessor :builder
|
75
|
+
|
41
76
|
# Creates a new cipher that uses an SHA encryption strategy.
|
42
77
|
#
|
43
78
|
# Configuration options:
|
44
|
-
# * <tt>:
|
45
|
-
#
|
79
|
+
# * <tt>:algorithm</tt> - The hashing algorithm to use for generating the
|
80
|
+
# encrypted string
|
81
|
+
# * <tt>:salt</tt> - Specifies a method, proc or string to call to determine
|
82
|
+
# the random bytes used as one of the inputs for generating the encrypted
|
83
|
+
# string
|
84
|
+
# * <tt>:builder</tt> - Specifies a method or proc to call to determine the
|
85
|
+
# actual value that gets hashed. This takes two arguments: the data and
|
86
|
+
# the salt for the encryption.
|
46
87
|
def initialize(options = {})
|
47
|
-
invalid_options = options.keys - [:salt]
|
88
|
+
invalid_options = options.keys - [:algorithm, :salt, :builder]
|
48
89
|
raise ArgumentError, "Unknown key(s): #{invalid_options.join(", ")}" unless invalid_options.empty?
|
49
90
|
|
50
|
-
options = {
|
91
|
+
options = {
|
92
|
+
:algorithm => ShaCipher.default_algorithm,
|
93
|
+
:salt => ShaCipher.default_salt,
|
94
|
+
:builder => ShaCipher.default_builder
|
95
|
+
}.merge(options)
|
51
96
|
|
52
|
-
self.
|
97
|
+
self.algorithm = options[:algorithm].upcase
|
98
|
+
self.salt = salt_value(options[:salt])
|
99
|
+
self.builder = options[:builder]
|
53
100
|
|
54
101
|
super()
|
55
102
|
end
|
@@ -61,7 +108,33 @@ module EncryptedStrings
|
|
61
108
|
|
62
109
|
# Returns the encrypted value of the data
|
63
110
|
def encrypt(data)
|
64
|
-
Digest::
|
111
|
+
Digest::const_get(algorithm.upcase).hexdigest(build(data, salt))
|
65
112
|
end
|
113
|
+
|
114
|
+
private
|
115
|
+
# Evaluates one of several different types of methods to determine the
|
116
|
+
# value of the salt. Methods can be one of the following types:
|
117
|
+
# * Method / Proc
|
118
|
+
# * String
|
119
|
+
# * Object that responds to :salt
|
120
|
+
def salt_value(value)
|
121
|
+
if value.is_a?(Proc)
|
122
|
+
value.call
|
123
|
+
elsif value.respond_to?(:salt)
|
124
|
+
value.salt
|
125
|
+
else
|
126
|
+
value.to_s
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Builds the value to hash based on the data being encrypted and the salt
|
131
|
+
# being used to seed the encryption algorithm
|
132
|
+
def build(data, salt)
|
133
|
+
if builder.is_a?(Proc)
|
134
|
+
builder.call(data, salt)
|
135
|
+
else
|
136
|
+
builder.send(:build, data, salt)
|
137
|
+
end
|
138
|
+
end
|
66
139
|
end
|
67
140
|
end
|
data/test/sha_cipher_test.rb
CHANGED
@@ -16,20 +16,28 @@ end
|
|
16
16
|
|
17
17
|
class ShaCipherWithCustomDefaultsTest < Test::Unit::TestCase
|
18
18
|
def setup
|
19
|
+
@original_default_algorithm = EncryptedStrings::ShaCipher.default_algorithm
|
19
20
|
@original_default_salt = EncryptedStrings::ShaCipher.default_salt
|
21
|
+
|
22
|
+
EncryptedStrings::ShaCipher.default_algorithm = 'sha512'
|
20
23
|
EncryptedStrings::ShaCipher.default_salt = 'custom_salt'
|
21
24
|
@sha_cipher = EncryptedStrings::ShaCipher.new
|
22
25
|
end
|
23
26
|
|
27
|
+
def test_should_use_custom_default_algorithm
|
28
|
+
assert_equal 'SHA512', @sha_cipher.algorithm
|
29
|
+
end
|
30
|
+
|
24
31
|
def test_should_use_custom_default_salt
|
25
32
|
assert_equal 'custom_salt', @sha_cipher.salt
|
26
33
|
end
|
27
34
|
|
28
|
-
def
|
29
|
-
assert_equal '
|
35
|
+
def test_should_encrypt_using_custom_default_configuration
|
36
|
+
assert_equal '22e38b0da46ab455cdb61375c58f66a7160227fe58727042087a59419258184b72ee0e4198110b951778dc76ace4402a377cdc31bb04195bce75196fe7684218', @sha_cipher.encrypt('test')
|
30
37
|
end
|
31
38
|
|
32
39
|
def teardown
|
40
|
+
EncryptedStrings::ShaCipher.default_algorithm = @original_default_algorithm
|
33
41
|
EncryptedStrings::ShaCipher.default_salt = @original_default_salt
|
34
42
|
end
|
35
43
|
end
|
@@ -56,7 +64,11 @@ end
|
|
56
64
|
|
57
65
|
class ShaCipherWithCustomOptionsTest < Test::Unit::TestCase
|
58
66
|
def setup
|
59
|
-
@sha_cipher = EncryptedStrings::ShaCipher.new(:salt => 'different salt')
|
67
|
+
@sha_cipher = EncryptedStrings::ShaCipher.new(:algorithm => 'sha512', :salt => 'different salt')
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_should_use_custom_algorithm
|
71
|
+
assert_equal 'SHA512', @sha_cipher.algorithm
|
60
72
|
end
|
61
73
|
|
62
74
|
def test_should_use_custom_salt
|
@@ -64,7 +76,7 @@ class ShaCipherWithCustomOptionsTest < Test::Unit::TestCase
|
|
64
76
|
end
|
65
77
|
|
66
78
|
def test_should_encrypt_using_custom_salt
|
67
|
-
assert_equal '
|
79
|
+
assert_equal 'c0b0d80d279a471d9ad53cdab4a667612ecfbc0a685f502ea7a586acf107a549d17a2e5f515c2fdfe6d90a772072e4e8b0bf3de7b9c51a9c95c43b91d129f7e1', @sha_cipher.encrypt('test')
|
68
80
|
end
|
69
81
|
end
|
70
82
|
|
@@ -80,3 +92,61 @@ class ShaCipherWithNonStringSaltTest < Test::Unit::TestCase
|
|
80
92
|
assert_equal @time.to_s, @sha_cipher.salt
|
81
93
|
end
|
82
94
|
end
|
95
|
+
|
96
|
+
class ShaCipherWithProcSaltTest < Test::Unit::TestCase
|
97
|
+
def setup
|
98
|
+
@sha_cipher = EncryptedStrings::ShaCipher.new(:salt => lambda {|*args| @args = args; 'val'})
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_should_call_proc_without_arguments
|
102
|
+
assert_equal [], @args
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_should_use_return_value_from_proc
|
106
|
+
assert_equal 'val', @sha_cipher.salt
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class ShaCipherWithObjectSaltTest < Test::Unit::TestCase
|
111
|
+
def setup
|
112
|
+
@object = Object.new
|
113
|
+
class << @object
|
114
|
+
def salt
|
115
|
+
'val'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
@sha_cipher = EncryptedStrings::ShaCipher.new(:salt => @object)
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_should_use_salt_method
|
123
|
+
assert_equal 'val', @sha_cipher.salt
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class ShaCipherWithProcBuilderTest < Test::Unit::TestCase
|
128
|
+
def setup
|
129
|
+
@sha_cipher = EncryptedStrings::ShaCipher.new(:builder => lambda {|data, salt| "#{data}|#{salt}"})
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_should_encrypt_based_on_custom_builder
|
133
|
+
assert_equal EncryptedStrings::ShaCipher.new.encrypt('test|'), @sha_cipher.encrypt('test')
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class ShaCipherWithObjectBuilderTest < Test::Unit::TestCase
|
138
|
+
def setup
|
139
|
+
@object = Object.new
|
140
|
+
class << @object
|
141
|
+
def build(data, salt)
|
142
|
+
"#{data}|#{salt}"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
@sha_cipher = EncryptedStrings::ShaCipher.new(:builder => @object)
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_should_encrypt_based_on_custom_builder
|
150
|
+
assert_equal EncryptedStrings::ShaCipher.new.encrypt('test|'), @sha_cipher.encrypt('test')
|
151
|
+
end
|
152
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: encrypted_strings
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Pfeifer
|
@@ -9,11 +9,11 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-03-07 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description:
|
16
|
+
description: Dead-simple string encryption/decryption syntax
|
17
17
|
email: aaron@pluginaweek.org
|
18
18
|
executables: []
|
19
19
|
|
@@ -22,24 +22,21 @@ extensions: []
|
|
22
22
|
extra_rdoc_files: []
|
23
23
|
|
24
24
|
files:
|
25
|
-
- lib/encrypted_strings
|
26
|
-
- lib/encrypted_strings/cipher.rb
|
25
|
+
- lib/encrypted_strings.rb
|
27
26
|
- lib/encrypted_strings/sha_cipher.rb
|
28
|
-
- lib/encrypted_strings/extensions
|
29
|
-
- lib/encrypted_strings/extensions/string.rb
|
30
|
-
- lib/encrypted_strings/symmetric_cipher.rb
|
31
27
|
- lib/encrypted_strings/asymmetric_cipher.rb
|
32
|
-
- lib/encrypted_strings.rb
|
28
|
+
- lib/encrypted_strings/symmetric_cipher.rb
|
29
|
+
- lib/encrypted_strings/cipher.rb
|
30
|
+
- lib/encrypted_strings/extensions/string.rb
|
33
31
|
- test/test_helper.rb
|
34
|
-
- test/symmetric_cipher_test.rb
|
35
|
-
- test/asymmetric_cipher_test.rb
|
36
|
-
- test/sha_cipher_test.rb
|
37
|
-
- test/keys
|
38
32
|
- test/keys/encrypted_private
|
39
|
-
- test/keys/private
|
40
33
|
- test/keys/public
|
41
|
-
- test/
|
34
|
+
- test/keys/private
|
42
35
|
- test/cipher_test.rb
|
36
|
+
- test/string_test.rb
|
37
|
+
- test/sha_cipher_test.rb
|
38
|
+
- test/symmetric_cipher_test.rb
|
39
|
+
- test/asymmetric_cipher_test.rb
|
43
40
|
- CHANGELOG.rdoc
|
44
41
|
- init.rb
|
45
42
|
- LICENSE
|
@@ -47,6 +44,8 @@ files:
|
|
47
44
|
- README.rdoc
|
48
45
|
has_rdoc: true
|
49
46
|
homepage: http://www.pluginaweek.org
|
47
|
+
licenses: []
|
48
|
+
|
50
49
|
post_install_message:
|
51
50
|
rdoc_options: []
|
52
51
|
|
@@ -67,13 +66,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
66
|
requirements: []
|
68
67
|
|
69
68
|
rubyforge_project: pluginaweek
|
70
|
-
rubygems_version: 1.
|
69
|
+
rubygems_version: 1.3.5
|
71
70
|
signing_key:
|
72
|
-
specification_version:
|
73
|
-
summary: Dead-simple string encryption/decryption syntax
|
71
|
+
specification_version: 3
|
72
|
+
summary: Dead-simple string encryption/decryption syntax
|
74
73
|
test_files:
|
74
|
+
- test/cipher_test.rb
|
75
|
+
- test/string_test.rb
|
76
|
+
- test/sha_cipher_test.rb
|
75
77
|
- test/symmetric_cipher_test.rb
|
76
78
|
- test/asymmetric_cipher_test.rb
|
77
|
-
- test/sha_cipher_test.rb
|
78
|
-
- test/string_test.rb
|
79
|
-
- test/cipher_test.rb
|