encrypted_strings 0.3.2 → 0.3.3
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.
- 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
|