Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add support for customizing how the SHA value gets built

  • Loading branch information...
commit 0c85f7f08b7143123581cdbc5966881c8640b8db 1 parent acadbd9
@obrie obrie authored
View
1  CHANGELOG.rdoc
@@ -1,5 +1,6 @@
== master
+* Add support for customizing how the SHA value gets built
* Allow methods or procs to be defined for dynamically generating SHA salts
* Add support for customizing the SHA encryption algorithm
View
48 lib/encrypted_strings/sha_cipher.rb
@@ -18,6 +18,25 @@ module EncryptedStrings
# password = 'shhhh'
# password.encrypt(:sha, :salt => 'secret') # => "ae645b35bb5dfea6c9133ac872e6adfa92a3c2bd"
#
+ # === Customizations
+ #
+ # In addition to customizing the algorithm, you can further tweak how values
+ # get encrypted by defining dynamic salts and how to build the value that
+ # actually gets hashed.
+ #
+ # For example:
+ #
+ # password = 'shhhh'
+ # password.encrypt(:sha,
+ # :salt => lambda {Time.now.to_s},
+ # :builder => lambda {|data, salt| "#{data}|#{salt}"}
+ # )
+ #
+ # The above example will generate a salt based on the current time and then
+ # use a custom builder for determining how the salt and data get concatenated
+ # to determine the value that gets hashed. This is particularly useful for
+ # providing compatibility with legacy systems.
+ #
# == Decrypting
#
# SHA-encrypted strings cannot be decrypted. The only way to determine
@@ -34,11 +53,16 @@ class << self
# The default salt value to use during encryption
attr_accessor :default_salt
+
+ # The default algorithm to use for building the value that gets hashed.
+ # Default is lambda {|data, salt| "#{data}#{salt}"}.
+ attr_accessor :default_builder
end
# Set defaults
@default_algorithm = 'SHA1'
@default_salt = 'salt'
+ @default_builder = lambda {|data, salt| "#{data}#{salt}"}
# The algorithm to use for encryption/decryption
attr_accessor :algorithm
@@ -46,6 +70,9 @@ class << self
# The salt value to use for encryption
attr_accessor :salt
+ # The function to use to build the value that gets hashed
+ attr_accessor :builder
+
# Creates a new cipher that uses an SHA encryption strategy.
#
# Configuration options:
@@ -54,17 +81,22 @@ class << self
# * <tt>:salt</tt> - Specifies a method, proc or string to call to determine
# the random bytes used as one of the inputs for generating the encrypted
# string
+ # * <tt>:builder</tt> - Specifies a method or proc to call to determine the
+ # actual value that gets hashed. This takes two arguments: the data and
+ # the salt for the encryption.
def initialize(options = {})
- invalid_options = options.keys - [:algorithm, :salt]
+ invalid_options = options.keys - [:algorithm, :salt, :builder]
raise ArgumentError, "Unknown key(s): #{invalid_options.join(", ")}" unless invalid_options.empty?
options = {
:algorithm => ShaCipher.default_algorithm,
- :salt => ShaCipher.default_salt
+ :salt => ShaCipher.default_salt,
+ :builder => ShaCipher.default_builder
}.merge(options)
self.algorithm = options[:algorithm].upcase
self.salt = salt_value(options[:salt])
+ self.builder = options[:builder]
super()
end
@@ -76,7 +108,7 @@ def can_decrypt?
# Returns the encrypted value of the data
def encrypt(data)
- Digest::const_get(algorithm.upcase).hexdigest(data + salt)
+ Digest::const_get(algorithm.upcase).hexdigest(build(data, salt))
end
private
@@ -94,5 +126,15 @@ def salt_value(value)
value.to_s
end
end
+
+ # Builds the value to hash based on the data being encrypted and the salt
+ # being used to seed the encryption algorithm
+ def build(data, salt)
+ if builder.is_a?(Proc)
+ builder.call(data, salt)
+ else
+ builder.send(:build, data, salt)
+ end
+ end
end
end
View
27 test/sha_cipher_test.rb
@@ -123,3 +123,30 @@ def test_should_use_salt_method
assert_equal 'val', @sha_cipher.salt
end
end
+
+class ShaCipherWithProcBuilderTest < Test::Unit::TestCase
+ def setup
+ @sha_cipher = EncryptedStrings::ShaCipher.new(:builder => lambda {|data, salt| "#{data}|#{salt}"})
+ end
+
+ def test_should_encrypt_based_on_custom_builder
+ assert_equal EncryptedStrings::ShaCipher.new.encrypt('test|'), @sha_cipher.encrypt('test')
+ end
+end
+
+class ShaCipherWithObjectBuilderTest < Test::Unit::TestCase
+ def setup
+ @object = Object.new
+ class << @object
+ def build(data, salt)
+ "#{data}|#{salt}"
+ end
+ end
+
+ @sha_cipher = EncryptedStrings::ShaCipher.new(:builder => @object)
+ end
+
+ def test_should_encrypt_based_on_custom_builder
+ assert_equal EncryptedStrings::ShaCipher.new.encrypt('test|'), @sha_cipher.encrypt('test')
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.