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.
@@ -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
@@ -1,4 +1,4 @@
1
- Copyright (c) 2005 Rick Olson, 2006-2008 Aaron Pfeifer
1
+ Copyright (c) 2005 Rick Olson, 2006-2010 Aaron Pfeifer
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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.2'
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 'rubyforge'
78
-
79
- ruby_forge = RubyForge.new.configure
80
- ruby_forge.login
86
+ require 'rake/gemcutter'
81
87
 
82
- %w(gem tgz zip).each do |ext|
83
- file = "pkg/#{spec.name}-#{spec.version}.#{ext}"
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>:salt</tt> - Random bytes used as one of the inputs for generating
45
- # the encrypted string
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 = {:salt => ShaCipher.default_salt}.merge(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.salt = options[:salt].to_s
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::SHA1.hexdigest(data + salt)
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
@@ -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 test_should_encrypt_using_custom_default_salt
29
- assert_equal '280f3c516070b09aa3eb755378509c725a9c6561', @sha_cipher.encrypt('test')
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 '18e3256d71529db8fa65b2eef24a69ddad7070f3', @sha_cipher.encrypt('test')
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.2
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: 2009-01-11 00:00:00 -05:00
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/string_test.rb
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.2.0
69
+ rubygems_version: 1.3.5
71
70
  signing_key:
72
- specification_version: 2
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