From 1e7bcfbfaabf7f916011668418bcceeb18947558 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sun, 23 Feb 2020 10:29:37 -0500 Subject: [PATCH 1/6] Fix typo in CONTRINBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dc2fadba..c959982c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,7 +83,7 @@ BUNDLE_GEMFILE=gemfiles/rails_6.0.rb bundle exec rake test ### Version Control Branches We've been trying to follow the rails way, stable branches, but have been -inconsistent. We should have one branche for each minor version, named like +inconsistent. We should have one branch for each minor version, named like `4-3-stable`. Releases should be done on those branches, not in master. So, the "stable" branches should be the only branches with release tags. From 08b04bc0831a54a7ed8c5a118ec97c0a72ca4481 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sun, 23 Feb 2020 11:00:25 -0500 Subject: [PATCH 2/6] Add V2 crypto providers for SHA* and MD5 encryption methods. Fixes original SHA512 crypto provider by digesting bytes instead of hex string. --- lib/authlogic/crypto_providers.rb | 9 +++ lib/authlogic/crypto_providers/v2/md5.rb | 35 ++++++++++++ lib/authlogic/crypto_providers/v2/sha1.rb | 41 ++++++++++++++ lib/authlogic/crypto_providers/v2/sha256.rb | 58 ++++++++++++++++++++ lib/authlogic/crypto_providers/v2/sha512.rb | 39 +++++++++++++ test/acts_as_authentic_test/password_test.rb | 19 +++++++ test/crypto_provider_test/v2/md5_test.rb | 27 +++++++++ test/crypto_provider_test/v2/sha1_test.rb | 27 +++++++++ test/crypto_provider_test/v2/sha256_test.rb | 27 +++++++++ test/crypto_provider_test/v2/sha512_test.rb | 29 ++++++++++ 10 files changed, 311 insertions(+) create mode 100644 lib/authlogic/crypto_providers/v2/md5.rb create mode 100644 lib/authlogic/crypto_providers/v2/sha1.rb create mode 100644 lib/authlogic/crypto_providers/v2/sha256.rb create mode 100644 lib/authlogic/crypto_providers/v2/sha512.rb create mode 100644 test/crypto_provider_test/v2/md5_test.rb create mode 100644 test/crypto_provider_test/v2/sha1_test.rb create mode 100644 test/crypto_provider_test/v2/sha256_test.rb create mode 100644 test/crypto_provider_test/v2/sha512_test.rb diff --git a/lib/authlogic/crypto_providers.rb b/lib/authlogic/crypto_providers.rb index 3e4b4711..6c2d6b11 100644 --- a/lib/authlogic/crypto_providers.rb +++ b/lib/authlogic/crypto_providers.rb @@ -30,6 +30,15 @@ module CryptoProviders autoload :BCrypt, "authlogic/crypto_providers/bcrypt" autoload :SCrypt, "authlogic/crypto_providers/scrypt" + # V2 crypto providers fix their predecessors' encryption schemes by + # hashing byte strings instead of the ehx strings output by `hexdigest` + module V2 + autoload :MD5, "authlogic/crypto_providers/v2/md5" + autoload :SHA1, "authlogic/crypto_providers/v2/sha1" + autoload :SHA256, "authlogic/crypto_providers/v2/sha256" + autoload :SHA512, "authlogic/crypto_providers/v2/sha512" + end + # Guide users to choose a better crypto provider. class Guidance BUILTIN_PROVIDER_PREFIX = "Authlogic::CryptoProviders::" diff --git a/lib/authlogic/crypto_providers/v2/md5.rb b/lib/authlogic/crypto_providers/v2/md5.rb new file mode 100644 index 00000000..3445481e --- /dev/null +++ b/lib/authlogic/crypto_providers/v2/md5.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require "digest/md5" + +module Authlogic + module CryptoProviders + module V2 + # A poor choice. There are known attacks against this algorithm. + class MD5 + class << self + attr_accessor :join_token + + # The number of times to loop through the encryption. + def stretches + @stretches ||= 1 + end + attr_writer :stretches + + # Turns your raw password into a MD5 hash. + def encrypt(*tokens) + digest = tokens.flatten.join(join_token) + stretches.times { digest = Digest::MD5.digest(digest) } + digest.unpack("H*")[0] + end + + # Does the crypted password match the tokens? Uses the same tokens that + # were used to encrypt. + def matches?(crypted, *tokens) + encrypt(*tokens) == crypted + end + end + end + end + end +end diff --git a/lib/authlogic/crypto_providers/v2/sha1.rb b/lib/authlogic/crypto_providers/v2/sha1.rb new file mode 100644 index 00000000..1880a8e4 --- /dev/null +++ b/lib/authlogic/crypto_providers/v2/sha1.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require "digest/sha1" + +module Authlogic + module CryptoProviders + module V2 + # A poor choice. There are known attacks against this algorithm. + class SHA1 + class << self + def join_token + @join_token ||= "--" + end + attr_writer :join_token + + # The number of times to loop through the encryption. + def stretches + @stretches ||= 10 + end + attr_writer :stretches + + # Turns your raw password into a Sha1 hash. + def encrypt(*tokens) + tokens = tokens.flatten + digest = tokens.shift + stretches.times do + digest = Digest::SHA1.digest([digest, *tokens].join(join_token)) + end + digest.unpack("H*")[0] + end + + # Does the crypted password match the tokens? Uses the same tokens that + # were used to encrypt. + def matches?(crypted, *tokens) + encrypt(*tokens) == crypted + end + end + end + end + end +end diff --git a/lib/authlogic/crypto_providers/v2/sha256.rb b/lib/authlogic/crypto_providers/v2/sha256.rb new file mode 100644 index 00000000..f12b034f --- /dev/null +++ b/lib/authlogic/crypto_providers/v2/sha256.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require "digest/sha2" + +module Authlogic + # The acts_as_authentic method has a crypto_provider option. This allows you + # to use any type of encryption you like. Just create a class with a class + # level encrypt and matches? method. See example below. + # + # === Example + # + # class MyAwesomeEncryptionMethod + # def self.encrypt(*tokens) + # # the tokens passed will be an array of objects, what type of object + # # is irrelevant, just do what you need to do with them and return a + # # single encrypted string. for example, you will most likely join all + # # of the objects into a single string and then encrypt that string + # end + # + # def self.matches?(crypted, *tokens) + # # return true if the crypted string matches the tokens. Depending on + # # your algorithm you might decrypt the string then compare it to the + # # token, or you might encrypt the tokens and make sure it matches the + # # crypted string, its up to you. + # end + # end + module CryptoProviders + module V2 + # = Sha256 + # + # Uses the Sha256 hash algorithm to encrypt passwords. + class SHA256 + class << self + attr_accessor :join_token + + # The number of times to loop through the encryption. + def stretches + @stretches ||= 20 + end + attr_writer :stretches + + # Turns your raw password into a Sha256 hash. + def encrypt(*tokens) + digest = tokens.flatten.join(join_token) + stretches.times { digest = Digest::SHA256.digest(digest) } + digest.unpack("H*")[0] + end + + # Does the crypted password match the tokens? Uses the same tokens that + # were used to encrypt. + def matches?(crypted, *tokens) + encrypt(*tokens) == crypted + end + end + end + end + end +end diff --git a/lib/authlogic/crypto_providers/v2/sha512.rb b/lib/authlogic/crypto_providers/v2/sha512.rb new file mode 100644 index 00000000..1a56b366 --- /dev/null +++ b/lib/authlogic/crypto_providers/v2/sha512.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require "digest/sha2" + +module Authlogic + module CryptoProviders + module V2 + # SHA-512 does not have any practical known attacks against it. However, + # there are better choices. We recommend transitioning to a more secure, + # adaptive hashing algorithm, like scrypt. + class SHA512 + class << self + attr_accessor :join_token + + # The number of times to loop through the encryption. + def stretches + @stretches ||= 20 + end + attr_writer :stretches + + # Turns your raw password into a Sha512 hash. + def encrypt(*tokens) + digest = tokens.flatten.join(join_token) + stretches.times do + digest = Digest::SHA512.digest(digest) + end + digest.unpack("H*")[0] + end + + # Does the crypted password match the tokens? Uses the same tokens that + # were used to encrypt. + def matches?(crypted, *tokens) + encrypt(*tokens) == crypted + end + end + end + end + end +end diff --git a/test/acts_as_authentic_test/password_test.rb b/test/acts_as_authentic_test/password_test.rb index 14c2c2a3..47ffd5bb 100644 --- a/test/acts_as_authentic_test/password_test.rb +++ b/test/acts_as_authentic_test/password_test.rb @@ -92,6 +92,25 @@ def test_transitioning_password ) end + def test_v2_crypto_provider_transition + ben = users(:ben) + + providers = [ + Authlogic::CryptoProviders::V2::SHA512, + Authlogic::CryptoProviders::V2::MD5, + Authlogic::CryptoProviders::V2::SHA1, + Authlogic::CryptoProviders::V2::SHA256 + ] + transition_password_to(providers[0], ben) + providers.each_cons(2) do |old_provider, new_provider| + transition_password_to( + new_provider, + ben, + old_provider + ) + end + end + def test_checks_password_against_database ben = users(:aaron) ben.password = "new pass" diff --git a/test/crypto_provider_test/v2/md5_test.rb b/test/crypto_provider_test/v2/md5_test.rb new file mode 100644 index 00000000..f08cab81 --- /dev/null +++ b/test/crypto_provider_test/v2/md5_test.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require "test_helper" + +module CryptoProviderTest + module V2 + class MD5Test < ActiveSupport::TestCase + def test_encrypt + assert Authlogic::CryptoProviders::V2::MD5.encrypt("mypass") + end + + def test_matches + hash = Authlogic::CryptoProviders::V2::MD5.encrypt("mypass") + assert Authlogic::CryptoProviders::V2::MD5.matches?(hash, "mypass") + end + + def test_matches_2 + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + digest = "51563330eb60e0eeb89759b01f08e872" + Authlogic::CryptoProviders::V2::MD5.stretches = 1 + assert Authlogic::CryptoProviders::V2::MD5.matches?(digest, nil, salt, password, nil) + Authlogic::CryptoProviders::V2::MD5.stretches = 10 + end + end + end +end diff --git a/test/crypto_provider_test/v2/sha1_test.rb b/test/crypto_provider_test/v2/sha1_test.rb new file mode 100644 index 00000000..19657ca6 --- /dev/null +++ b/test/crypto_provider_test/v2/sha1_test.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require "test_helper" + +module CryptoProviderTest + module V2 + class SHA1Test < ActiveSupport::TestCase + def test_encrypt + assert Authlogic::CryptoProviders::V2::SHA1.encrypt("mypass") + end + + def test_matches + hash = Authlogic::CryptoProviders::V2::SHA1.encrypt("mypass") + assert Authlogic::CryptoProviders::V2::SHA1.matches?(hash, "mypass") + end + + def test_matches_2 + password = "test" + salt = "abc" + digest = "2d578fb3ab6bdab725080f00d5689f79b7d1df51" + Authlogic::CryptoProviders::V2::SHA1.stretches = 1 + assert Authlogic::CryptoProviders::V2::SHA1.matches?(digest, nil, salt, password, nil) + Authlogic::CryptoProviders::V2::SHA1.stretches = 10 + end + end + end +end diff --git a/test/crypto_provider_test/v2/sha256_test.rb b/test/crypto_provider_test/v2/sha256_test.rb new file mode 100644 index 00000000..cbef6514 --- /dev/null +++ b/test/crypto_provider_test/v2/sha256_test.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require "test_helper" + +module CryptoProviderTest + module V2 + class SHA256Test < ActiveSupport::TestCase + def test_encrypt + assert Authlogic::CryptoProviders::V2::SHA256.encrypt("mypass") + end + + def test_matches + hash = Authlogic::CryptoProviders::V2::SHA256.encrypt("mypass") + assert Authlogic::CryptoProviders::V2::SHA256.matches?(hash, "mypass") + end + + def test_matches_2 + password = "test" + salt = "abc" + digest = "70e0f1ade11debb6732029c267095e092b5b43ff271d4f8d9158cb004322f38b" + Authlogic::CryptoProviders::V2::SHA256.stretches = 1 + assert Authlogic::CryptoProviders::V2::SHA256.matches?(digest, nil, salt, password, nil) + Authlogic::CryptoProviders::V2::SHA256.stretches = 10 + end + end + end +end diff --git a/test/crypto_provider_test/v2/sha512_test.rb b/test/crypto_provider_test/v2/sha512_test.rb new file mode 100644 index 00000000..41c44ff6 --- /dev/null +++ b/test/crypto_provider_test/v2/sha512_test.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require "test_helper" + +module CryptoProviderTest + module V2 + class SHA512Test < ActiveSupport::TestCase + def test_encrypt + assert Authlogic::CryptoProviders::V2::SHA512.encrypt("mypass") + end + + def test_matches + hash = Authlogic::CryptoProviders::V2::SHA512.encrypt("mypass") + assert Authlogic::CryptoProviders::V2::SHA512.matches?(hash, "mypass") + end + + def test_matches_2 + password = "test" + salt = "abc" + # rubocop:disable Metrics/LineLength + digest = "c7cb2b81ccbb686eaefafbfbcf61334fb75f8e5dcb3de8b86fec53ad1a5dd013c0c4c9cc3af7c59aed2afab59dd463f6a84d9531f46e2efeb3681bd79bf57a37" + # rubocop:enable Metrics/LineLength + Authlogic::CryptoProviders::V2::SHA512.stretches = 1 + assert Authlogic::CryptoProviders::V2::SHA512.matches?(digest, nil, salt, password, nil) + Authlogic::CryptoProviders::V2::SHA512.stretches = 10 + end + end + end +end From 0637d6200a8e4ab27b6bcad635e328b4117ceadc Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sat, 29 Feb 2020 14:08:55 -0500 Subject: [PATCH 3/6] Add CryptoProviders::V2 note to Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a11c2e02..21932537 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. the `log_in_after_create` setting when creating a new logged-out user * [#668](https://github.com/binarylogic/authlogic/pull/668) - BCrypt user forced to load SCrypt + * [#697](https://github.com/binarylogic/authlogic/issues/697) - Add Authlogic::CryptoProviders::V2 module containing fixed SHA and MD5 encryption schemes ## 5.0.4 (2019-09-11) From 266f9c42f78afd0476f10a07b3325c5304bd3b13 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sat, 7 Mar 2020 08:30:47 -0500 Subject: [PATCH 4/6] Change V2 crypto provider naming scheme to, for example, MD5::V2 from V2::MD5. Requires using the old-cased class names, such as Sha1::V2, instead of SHA1. --- lib/authlogic/crypto_providers.rb | 9 --- lib/authlogic/crypto_providers/md5.rb | 3 + .../crypto_providers/{v2/md5.rb => md5/v2.rb} | 4 +- lib/authlogic/crypto_providers/sha1.rb | 3 + .../{v2/sha1.rb => sha1/v2.rb} | 4 +- lib/authlogic/crypto_providers/sha256.rb | 3 + .../{v2/sha256.rb => sha256/v2.rb} | 4 +- lib/authlogic/crypto_providers/sha512.rb | 3 + .../{v2/sha512.rb => sha512/v2.rb} | 4 +- test/acts_as_authentic_test/password_test.rb | 8 +-- test/crypto_provider_test/md5/v2_test.rb | 54 +++++++++++++++++ test/crypto_provider_test/sha1/v2_test.rb | 54 +++++++++++++++++ test/crypto_provider_test/sha256/v2_test.rb | 54 +++++++++++++++++ test/crypto_provider_test/sha512/v2_test.rb | 60 +++++++++++++++++++ test/crypto_provider_test/v2/md5_test.rb | 27 --------- test/crypto_provider_test/v2/sha1_test.rb | 27 --------- test/crypto_provider_test/v2/sha256_test.rb | 27 --------- test/crypto_provider_test/v2/sha512_test.rb | 29 --------- 18 files changed, 246 insertions(+), 131 deletions(-) rename lib/authlogic/crypto_providers/{v2/md5.rb => md5/v2.rb} (96%) rename lib/authlogic/crypto_providers/{v2/sha1.rb => sha1/v2.rb} (97%) rename lib/authlogic/crypto_providers/{v2/sha256.rb => sha256/v2.rb} (98%) rename lib/authlogic/crypto_providers/{v2/sha512.rb => sha512/v2.rb} (97%) create mode 100644 test/crypto_provider_test/md5/v2_test.rb create mode 100644 test/crypto_provider_test/sha1/v2_test.rb create mode 100644 test/crypto_provider_test/sha256/v2_test.rb create mode 100644 test/crypto_provider_test/sha512/v2_test.rb delete mode 100644 test/crypto_provider_test/v2/md5_test.rb delete mode 100644 test/crypto_provider_test/v2/sha1_test.rb delete mode 100644 test/crypto_provider_test/v2/sha256_test.rb delete mode 100644 test/crypto_provider_test/v2/sha512_test.rb diff --git a/lib/authlogic/crypto_providers.rb b/lib/authlogic/crypto_providers.rb index 6c2d6b11..3e4b4711 100644 --- a/lib/authlogic/crypto_providers.rb +++ b/lib/authlogic/crypto_providers.rb @@ -30,15 +30,6 @@ module CryptoProviders autoload :BCrypt, "authlogic/crypto_providers/bcrypt" autoload :SCrypt, "authlogic/crypto_providers/scrypt" - # V2 crypto providers fix their predecessors' encryption schemes by - # hashing byte strings instead of the ehx strings output by `hexdigest` - module V2 - autoload :MD5, "authlogic/crypto_providers/v2/md5" - autoload :SHA1, "authlogic/crypto_providers/v2/sha1" - autoload :SHA256, "authlogic/crypto_providers/v2/sha256" - autoload :SHA512, "authlogic/crypto_providers/v2/sha512" - end - # Guide users to choose a better crypto provider. class Guidance BUILTIN_PROVIDER_PREFIX = "Authlogic::CryptoProviders::" diff --git a/lib/authlogic/crypto_providers/md5.rb b/lib/authlogic/crypto_providers/md5.rb index aa7a07f2..6bd5cbfa 100644 --- a/lib/authlogic/crypto_providers/md5.rb +++ b/lib/authlogic/crypto_providers/md5.rb @@ -6,6 +6,9 @@ module Authlogic module CryptoProviders # A poor choice. There are known attacks against this algorithm. class MD5 + # V2 hashes the digest bytes in repeated stretches instead of hex characters. + autoload :V2, File.join(__dir__, "md5", "v2") + class << self attr_accessor :join_token diff --git a/lib/authlogic/crypto_providers/v2/md5.rb b/lib/authlogic/crypto_providers/md5/v2.rb similarity index 96% rename from lib/authlogic/crypto_providers/v2/md5.rb rename to lib/authlogic/crypto_providers/md5/v2.rb index 3445481e..ec498c59 100644 --- a/lib/authlogic/crypto_providers/v2/md5.rb +++ b/lib/authlogic/crypto_providers/md5/v2.rb @@ -4,9 +4,9 @@ module Authlogic module CryptoProviders - module V2 + class MD5 # A poor choice. There are known attacks against this algorithm. - class MD5 + class V2 class << self attr_accessor :join_token diff --git a/lib/authlogic/crypto_providers/sha1.rb b/lib/authlogic/crypto_providers/sha1.rb index 4b70b63b..f992e508 100644 --- a/lib/authlogic/crypto_providers/sha1.rb +++ b/lib/authlogic/crypto_providers/sha1.rb @@ -6,6 +6,9 @@ module Authlogic module CryptoProviders # A poor choice. There are known attacks against this algorithm. class Sha1 + # V2 hashes the digest bytes in repeated stretches instead of hex characters. + autoload :V2, File.join(__dir__, "sha1", "v2") + class << self def join_token @join_token ||= "--" diff --git a/lib/authlogic/crypto_providers/v2/sha1.rb b/lib/authlogic/crypto_providers/sha1/v2.rb similarity index 97% rename from lib/authlogic/crypto_providers/v2/sha1.rb rename to lib/authlogic/crypto_providers/sha1/v2.rb index 1880a8e4..68efd7b5 100644 --- a/lib/authlogic/crypto_providers/v2/sha1.rb +++ b/lib/authlogic/crypto_providers/sha1/v2.rb @@ -4,9 +4,9 @@ module Authlogic module CryptoProviders - module V2 + class Sha1 # A poor choice. There are known attacks against this algorithm. - class SHA1 + class V2 class << self def join_token @join_token ||= "--" diff --git a/lib/authlogic/crypto_providers/sha256.rb b/lib/authlogic/crypto_providers/sha256.rb index 9757f085..c6c7d41d 100644 --- a/lib/authlogic/crypto_providers/sha256.rb +++ b/lib/authlogic/crypto_providers/sha256.rb @@ -29,6 +29,9 @@ module CryptoProviders # # Uses the Sha256 hash algorithm to encrypt passwords. class Sha256 + # V2 hashes the digest bytes in repeated stretches instead of hex characters. + autoload :V2, File.join(__dir__, "sha256", "v2") + class << self attr_accessor :join_token diff --git a/lib/authlogic/crypto_providers/v2/sha256.rb b/lib/authlogic/crypto_providers/sha256/v2.rb similarity index 98% rename from lib/authlogic/crypto_providers/v2/sha256.rb rename to lib/authlogic/crypto_providers/sha256/v2.rb index f12b034f..75ae2c8f 100644 --- a/lib/authlogic/crypto_providers/v2/sha256.rb +++ b/lib/authlogic/crypto_providers/sha256/v2.rb @@ -25,11 +25,11 @@ module Authlogic # end # end module CryptoProviders - module V2 + class Sha256 # = Sha256 # # Uses the Sha256 hash algorithm to encrypt passwords. - class SHA256 + class V2 class << self attr_accessor :join_token diff --git a/lib/authlogic/crypto_providers/sha512.rb b/lib/authlogic/crypto_providers/sha512.rb index 7b3513c8..db8093b9 100644 --- a/lib/authlogic/crypto_providers/sha512.rb +++ b/lib/authlogic/crypto_providers/sha512.rb @@ -8,6 +8,9 @@ module CryptoProviders # there are better choices. We recommend transitioning to a more secure, # adaptive hashing algorithm, like scrypt. class Sha512 + # V2 hashes the digest bytes in repeated stretches instead of hex characters. + autoload :V2, File.join(__dir__, "sha512", "v2") + class << self attr_accessor :join_token diff --git a/lib/authlogic/crypto_providers/v2/sha512.rb b/lib/authlogic/crypto_providers/sha512/v2.rb similarity index 97% rename from lib/authlogic/crypto_providers/v2/sha512.rb rename to lib/authlogic/crypto_providers/sha512/v2.rb index 1a56b366..a88b07dd 100644 --- a/lib/authlogic/crypto_providers/v2/sha512.rb +++ b/lib/authlogic/crypto_providers/sha512/v2.rb @@ -4,11 +4,11 @@ module Authlogic module CryptoProviders - module V2 + class Sha512 # SHA-512 does not have any practical known attacks against it. However, # there are better choices. We recommend transitioning to a more secure, # adaptive hashing algorithm, like scrypt. - class SHA512 + class V2 class << self attr_accessor :join_token diff --git a/test/acts_as_authentic_test/password_test.rb b/test/acts_as_authentic_test/password_test.rb index 47ffd5bb..e13c76dd 100644 --- a/test/acts_as_authentic_test/password_test.rb +++ b/test/acts_as_authentic_test/password_test.rb @@ -96,10 +96,10 @@ def test_v2_crypto_provider_transition ben = users(:ben) providers = [ - Authlogic::CryptoProviders::V2::SHA512, - Authlogic::CryptoProviders::V2::MD5, - Authlogic::CryptoProviders::V2::SHA1, - Authlogic::CryptoProviders::V2::SHA256 + Authlogic::CryptoProviders::Sha512::V2, + Authlogic::CryptoProviders::MD5::V2, + Authlogic::CryptoProviders::Sha1::V2, + Authlogic::CryptoProviders::Sha256::V2 ] transition_password_to(providers[0], ben) providers.each_cons(2) do |old_provider, new_provider| diff --git a/test/crypto_provider_test/md5/v2_test.rb b/test/crypto_provider_test/md5/v2_test.rb new file mode 100644 index 00000000..e9b34965 --- /dev/null +++ b/test/crypto_provider_test/md5/v2_test.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require "test_helper" + +module CryptoProviderTest + module MD5 + class V2Test < ActiveSupport::TestCase + def setup + @default_stretches = Authlogic::CryptoProviders::MD5::V2.stretches + end + + def teardown + Authlogic::CryptoProviders::MD5::V2.stretches = @default_stretches + end + + def test_encrypt + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "3d16884295a68fec30a2ae7ff0634b1e" + + digest = Authlogic::CryptoProviders::MD5::V2.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_encrypt_with_3_stretches + Authlogic::CryptoProviders::MD5::V2.stretches = 3 + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "da62ac8b983606f684cea0b93a558283" + + digest = Authlogic::CryptoProviders::MD5::V2.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_matches + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "3d16884295a68fec30a2ae7ff0634b1e" + + assert Authlogic::CryptoProviders::MD5::V2.matches?(expected_digest, password, salt) + end + + def test_not_matches + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + bad_digest = "12345" + + assert !Authlogic::CryptoProviders::MD5::V2.matches?(bad_digest, password, salt) + end + end + end +end diff --git a/test/crypto_provider_test/sha1/v2_test.rb b/test/crypto_provider_test/sha1/v2_test.rb new file mode 100644 index 00000000..0a0b5d76 --- /dev/null +++ b/test/crypto_provider_test/sha1/v2_test.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require "test_helper" + +module CryptoProviderTest + module VSHA1 + class V2Test < ActiveSupport::TestCase + def setup + @default_stretches = Authlogic::CryptoProviders::Sha1::V2.stretches + end + + def teardown + Authlogic::CryptoProviders::Sha1::V2.stretches = @default_stretches + end + + def test_encrypt + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "12d995b1f0af7d24d6f89d2e63dfbcb752384815" + + digest = Authlogic::CryptoProviders::Sha1::V2.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_encrypt_with_3_stretches + Authlogic::CryptoProviders::Sha1::V2.stretches = 3 + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "af1e00f841ccc742c1e5879af35ca02b1978a1ac" + + digest = Authlogic::CryptoProviders::Sha1::V2.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_matches + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "12d995b1f0af7d24d6f89d2e63dfbcb752384815" + + assert Authlogic::CryptoProviders::Sha1::V2.matches?(expected_digest, password, salt) + end + + def test_not_matches + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + bad_digest = "12345" + + assert !Authlogic::CryptoProviders::Sha1::V2.matches?(bad_digest, password, salt) + end + end + end +end diff --git a/test/crypto_provider_test/sha256/v2_test.rb b/test/crypto_provider_test/sha256/v2_test.rb new file mode 100644 index 00000000..1bfb2098 --- /dev/null +++ b/test/crypto_provider_test/sha256/v2_test.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require "test_helper" + +module CryptoProviderTest + module SHA256 + class V2Test < ActiveSupport::TestCase + def setup + @default_stretches = Authlogic::CryptoProviders::Sha256::V2.stretches + end + + def teardown + Authlogic::CryptoProviders::Sha256::V2.stretches = @default_stretches + end + + def test_encrypt + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "7f42a368b64a3c284c87b3ed3145b0c89f6bc49de931ca083e9c56a5c6b98e22" + + digest = Authlogic::CryptoProviders::Sha256::V2.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_encrypt_with_3_stretches + Authlogic::CryptoProviders::Sha256::V2.stretches = 3 + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "1560ebc3b08d86828a7e9267379f7dbb847b6cc255135fc13210a4155a58b981" + + digest = Authlogic::CryptoProviders::Sha256::V2.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_matches + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "7f42a368b64a3c284c87b3ed3145b0c89f6bc49de931ca083e9c56a5c6b98e22" + + assert Authlogic::CryptoProviders::Sha256::V2.matches?(expected_digest, password, salt) + end + + def test_not_matches + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + bad_digest = "12345" + + assert !Authlogic::CryptoProviders::Sha256::V2.matches?(bad_digest, password, salt) + end + end + end +end diff --git a/test/crypto_provider_test/sha512/v2_test.rb b/test/crypto_provider_test/sha512/v2_test.rb new file mode 100644 index 00000000..2d934b4d --- /dev/null +++ b/test/crypto_provider_test/sha512/v2_test.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require "test_helper" + +module CryptoProviderTest + module SHA512 + class V2Test < ActiveSupport::TestCase + def setup + @default_stretches = Authlogic::CryptoProviders::Sha512::V2.stretches + end + + def teardown + Authlogic::CryptoProviders::Sha512::V2.stretches = @default_stretches + end + + def test_encrypt + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + # rubocop:disable Metrics/LineLength + expected_digest = "60e86eec0e7f858cc5cc6b42b31a847819b65e06317709ce2779245d0776f18094dff9afbc66ae1e509f2b5e49f4d2ff3f632c8ee7c4683749f5fd028de5b085" + # rubocop:enable Metrics/LineLength + + digest = Authlogic::CryptoProviders::Sha512::V2.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_encrypt_with_3_stretches + Authlogic::CryptoProviders::Sha512::V2.stretches = 3 + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + # rubocop:disable Metrics/LineLength + expected_digest = "c4f546026f67a4fcce0e4df5905b845f75d9cfe1371eeaba99a2c045940a7d08aa81837344752a9d4fb93883402114edd03955ed5962cd89b6e335c2ec5ca4a5" + # rubocop:enable Metrics/LineLength + + digest = Authlogic::CryptoProviders::Sha512::V2.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_matches + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + # rubocop:disable Metrics/LineLength + expected_digest = "60e86eec0e7f858cc5cc6b42b31a847819b65e06317709ce2779245d0776f18094dff9afbc66ae1e509f2b5e49f4d2ff3f632c8ee7c4683749f5fd028de5b085" + # rubocop:enable Metrics/LineLength + + assert Authlogic::CryptoProviders::Sha512::V2.matches?(expected_digest, password, salt) + end + + def test_not_matches + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + bad_digest = "12345" + + assert !Authlogic::CryptoProviders::Sha512::V2.matches?(bad_digest, password, salt) + end + end + end +end diff --git a/test/crypto_provider_test/v2/md5_test.rb b/test/crypto_provider_test/v2/md5_test.rb deleted file mode 100644 index f08cab81..00000000 --- a/test/crypto_provider_test/v2/md5_test.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" - -module CryptoProviderTest - module V2 - class MD5Test < ActiveSupport::TestCase - def test_encrypt - assert Authlogic::CryptoProviders::V2::MD5.encrypt("mypass") - end - - def test_matches - hash = Authlogic::CryptoProviders::V2::MD5.encrypt("mypass") - assert Authlogic::CryptoProviders::V2::MD5.matches?(hash, "mypass") - end - - def test_matches_2 - password = "test" - salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" - digest = "51563330eb60e0eeb89759b01f08e872" - Authlogic::CryptoProviders::V2::MD5.stretches = 1 - assert Authlogic::CryptoProviders::V2::MD5.matches?(digest, nil, salt, password, nil) - Authlogic::CryptoProviders::V2::MD5.stretches = 10 - end - end - end -end diff --git a/test/crypto_provider_test/v2/sha1_test.rb b/test/crypto_provider_test/v2/sha1_test.rb deleted file mode 100644 index 19657ca6..00000000 --- a/test/crypto_provider_test/v2/sha1_test.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" - -module CryptoProviderTest - module V2 - class SHA1Test < ActiveSupport::TestCase - def test_encrypt - assert Authlogic::CryptoProviders::V2::SHA1.encrypt("mypass") - end - - def test_matches - hash = Authlogic::CryptoProviders::V2::SHA1.encrypt("mypass") - assert Authlogic::CryptoProviders::V2::SHA1.matches?(hash, "mypass") - end - - def test_matches_2 - password = "test" - salt = "abc" - digest = "2d578fb3ab6bdab725080f00d5689f79b7d1df51" - Authlogic::CryptoProviders::V2::SHA1.stretches = 1 - assert Authlogic::CryptoProviders::V2::SHA1.matches?(digest, nil, salt, password, nil) - Authlogic::CryptoProviders::V2::SHA1.stretches = 10 - end - end - end -end diff --git a/test/crypto_provider_test/v2/sha256_test.rb b/test/crypto_provider_test/v2/sha256_test.rb deleted file mode 100644 index cbef6514..00000000 --- a/test/crypto_provider_test/v2/sha256_test.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" - -module CryptoProviderTest - module V2 - class SHA256Test < ActiveSupport::TestCase - def test_encrypt - assert Authlogic::CryptoProviders::V2::SHA256.encrypt("mypass") - end - - def test_matches - hash = Authlogic::CryptoProviders::V2::SHA256.encrypt("mypass") - assert Authlogic::CryptoProviders::V2::SHA256.matches?(hash, "mypass") - end - - def test_matches_2 - password = "test" - salt = "abc" - digest = "70e0f1ade11debb6732029c267095e092b5b43ff271d4f8d9158cb004322f38b" - Authlogic::CryptoProviders::V2::SHA256.stretches = 1 - assert Authlogic::CryptoProviders::V2::SHA256.matches?(digest, nil, salt, password, nil) - Authlogic::CryptoProviders::V2::SHA256.stretches = 10 - end - end - end -end diff --git a/test/crypto_provider_test/v2/sha512_test.rb b/test/crypto_provider_test/v2/sha512_test.rb deleted file mode 100644 index 41c44ff6..00000000 --- a/test/crypto_provider_test/v2/sha512_test.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" - -module CryptoProviderTest - module V2 - class SHA512Test < ActiveSupport::TestCase - def test_encrypt - assert Authlogic::CryptoProviders::V2::SHA512.encrypt("mypass") - end - - def test_matches - hash = Authlogic::CryptoProviders::V2::SHA512.encrypt("mypass") - assert Authlogic::CryptoProviders::V2::SHA512.matches?(hash, "mypass") - end - - def test_matches_2 - password = "test" - salt = "abc" - # rubocop:disable Metrics/LineLength - digest = "c7cb2b81ccbb686eaefafbfbcf61334fb75f8e5dcb3de8b86fec53ad1a5dd013c0c4c9cc3af7c59aed2afab59dd463f6a84d9531f46e2efeb3681bd79bf57a37" - # rubocop:enable Metrics/LineLength - Authlogic::CryptoProviders::V2::SHA512.stretches = 1 - assert Authlogic::CryptoProviders::V2::SHA512.matches?(digest, nil, salt, password, nil) - Authlogic::CryptoProviders::V2::SHA512.stretches = 10 - end - end - end -end From 3e2f4f01caab6e4b8f05aef9f9f13a34fd3a9542 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sat, 7 Mar 2020 08:52:13 -0500 Subject: [PATCH 5/6] Assert specified hash values in SHA* (V1) tests. Add MD5 test. --- test/crypto_provider_test/md5_test.rb | 52 ++++++++++++++++++++++++ test/crypto_provider_test/sha1_test.rb | 43 ++++++++++++++++---- test/crypto_provider_test/sha256_test.rb | 42 +++++++++++++++++-- test/crypto_provider_test/sha512_test.rb | 48 ++++++++++++++++++++-- 4 files changed, 171 insertions(+), 14 deletions(-) create mode 100644 test/crypto_provider_test/md5_test.rb diff --git a/test/crypto_provider_test/md5_test.rb b/test/crypto_provider_test/md5_test.rb new file mode 100644 index 00000000..fbf9ab70 --- /dev/null +++ b/test/crypto_provider_test/md5_test.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require "test_helper" + +module CryptoProviderTest + class MD5Test < ActiveSupport::TestCase + def setup + @default_stretches = Authlogic::CryptoProviders::MD5.stretches + end + + def teardown + Authlogic::CryptoProviders::MD5.stretches = @default_stretches + end + + def test_encrypt + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "3d16884295a68fec30a2ae7ff0634b1e" + + digest = Authlogic::CryptoProviders::MD5.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_encrypt_with_3_stretches + Authlogic::CryptoProviders::MD5.stretches = 3 + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "9ac3a3a2e68f822f3482cbea3cbed9a3" + + digest = Authlogic::CryptoProviders::MD5.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_matches + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "3d16884295a68fec30a2ae7ff0634b1e" + + assert Authlogic::CryptoProviders::MD5.matches?(expected_digest, password, salt) + end + + def test_not_matches + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + bad_digest = "12345" + + assert !Authlogic::CryptoProviders::MD5.matches?(bad_digest, password, salt) + end + end +end diff --git a/test/crypto_provider_test/sha1_test.rb b/test/crypto_provider_test/sha1_test.rb index cd0d6f52..244259bd 100644 --- a/test/crypto_provider_test/sha1_test.rb +++ b/test/crypto_provider_test/sha1_test.rb @@ -4,22 +4,49 @@ module CryptoProviderTest class Sha1Test < ActiveSupport::TestCase + def setup + @default_stretches = Authlogic::CryptoProviders::Sha1.stretches + end + + def teardown + Authlogic::CryptoProviders::Sha1.stretches = @default_stretches + end + def test_encrypt - assert Authlogic::CryptoProviders::Sha1.encrypt("mypass") + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "5723d69f7ca1f8d63122c9cef4cf3c10d0482d3e" + + digest = Authlogic::CryptoProviders::Sha1.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_encrypt_with_3_stretches + Authlogic::CryptoProviders::Sha1.stretches = 3 + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "969f681d90a7d25679256e38cce3dc10db6d49c5" + + digest = Authlogic::CryptoProviders::Sha1.encrypt(password, salt) + + assert_equal digest, expected_digest end def test_matches - hash = Authlogic::CryptoProviders::Sha1.encrypt("mypass") - assert Authlogic::CryptoProviders::Sha1.matches?(hash, "mypass") + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "5723d69f7ca1f8d63122c9cef4cf3c10d0482d3e" + + assert Authlogic::CryptoProviders::Sha1.matches?(expected_digest, password, salt) end - def test_matches_2 + def test_not_matches password = "test" salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" - digest = "00742970dc9e6319f8019fd54864d3ea740f04b1" - Authlogic::CryptoProviders::Sha1.stretches = 1 - assert Authlogic::CryptoProviders::Sha1.matches?(digest, nil, salt, password, nil) - Authlogic::CryptoProviders::Sha1.stretches = 10 + bad_digest = "12345" + + assert !Authlogic::CryptoProviders::Sha1.matches?(bad_digest, password, salt) end end end diff --git a/test/crypto_provider_test/sha256_test.rb b/test/crypto_provider_test/sha256_test.rb index a944939f..983a1161 100644 --- a/test/crypto_provider_test/sha256_test.rb +++ b/test/crypto_provider_test/sha256_test.rb @@ -4,13 +4,49 @@ module CryptoProviderTest class Sha256Test < ActiveSupport::TestCase + def setup + @default_stretches = Authlogic::CryptoProviders::Sha256.stretches + end + + def teardown + Authlogic::CryptoProviders::Sha256.stretches = @default_stretches + end + def test_encrypt - assert Authlogic::CryptoProviders::Sha256.encrypt("mypass") + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "3c4f802953726704088a3cd6d89237e9a279a8e8f43fa6de8549ca54b80b766c" + + digest = Authlogic::CryptoProviders::Sha256.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_encrypt_with_3_stretches + Authlogic::CryptoProviders::Sha256.stretches = 3 + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "06a2e9cd5552f2cdbc01ec61d52ce80d0bfba8f1bb689a356ac0193d42adc831" + + digest = Authlogic::CryptoProviders::Sha256.encrypt(password, salt) + + assert_equal digest, expected_digest end def test_matches - hash = Authlogic::CryptoProviders::Sha256.encrypt("mypass") - assert Authlogic::CryptoProviders::Sha256.matches?(hash, "mypass") + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + expected_digest = "3c4f802953726704088a3cd6d89237e9a279a8e8f43fa6de8549ca54b80b766c" + + assert Authlogic::CryptoProviders::Sha256.matches?(expected_digest, password, salt) + end + + def test_not_matches + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + bad_digest = "12345" + + assert !Authlogic::CryptoProviders::Sha256.matches?(bad_digest, password, salt) end end end diff --git a/test/crypto_provider_test/sha512_test.rb b/test/crypto_provider_test/sha512_test.rb index a9041f79..c98095f7 100644 --- a/test/crypto_provider_test/sha512_test.rb +++ b/test/crypto_provider_test/sha512_test.rb @@ -4,13 +4,55 @@ module CryptoProviderTest class Sha512Test < ActiveSupport::TestCase + def setup + @default_stretches = Authlogic::CryptoProviders::Sha512.stretches + end + + def teardown + Authlogic::CryptoProviders::Sha512.stretches = @default_stretches + end + def test_encrypt - assert Authlogic::CryptoProviders::Sha512.encrypt("mypass") + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + # rubocop:disable Metrics/LineLength + expected_digest = "9508ba2964d65501aa1d7798e8f250b35f50fadb870871f2bc1f390872e8456e785633d06e17ffa4984a04cfa1a0e1ec29f15c31187b991e591393c6c0bffb61" + # rubocop:enable Metrics/LineLength + + digest = Authlogic::CryptoProviders::Sha512.encrypt(password, salt) + + assert_equal digest, expected_digest + end + + def test_encrypt_with_3_stretches + Authlogic::CryptoProviders::Sha512.stretches = 3 + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + # rubocop:disable Metrics/LineLength + expected_digest = "ed507752ef2e985a9e5661fedcbac8ad7536d4b80c87183c20273f568afb6f2112886fd786de00458eb2a14c640d9060c4688825e715cc1c3ecde8997d4ae556" + # rubocop:enable Metrics/LineLength + + digest = Authlogic::CryptoProviders::Sha512.encrypt(password, salt) + + assert_equal digest, expected_digest end def test_matches - hash = Authlogic::CryptoProviders::Sha512.encrypt("mypass") - assert Authlogic::CryptoProviders::Sha512.matches?(hash, "mypass") + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + # rubocop:disable Metrics/LineLength + expected_digest = "9508ba2964d65501aa1d7798e8f250b35f50fadb870871f2bc1f390872e8456e785633d06e17ffa4984a04cfa1a0e1ec29f15c31187b991e591393c6c0bffb61" + # rubocop:enable Metrics/LineLength + + assert Authlogic::CryptoProviders::Sha512.matches?(expected_digest, password, salt) + end + + def test_not_matches + password = "test" + salt = "7e3041ebc2fc05a40c60028e2c4901a81035d3cd" + bad_digest = "12345" + + assert !Authlogic::CryptoProviders::Sha512.matches?(bad_digest, password, salt) end end end From 25794619ba89aef731a554148b6f491f43abe94c Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sat, 7 Mar 2020 09:10:20 -0500 Subject: [PATCH 6/6] fixup! Add CryptoProviders::V2 note to Changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21932537..5d99a9a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. the `log_in_after_create` setting when creating a new logged-out user * [#668](https://github.com/binarylogic/authlogic/pull/668) - BCrypt user forced to load SCrypt - * [#697](https://github.com/binarylogic/authlogic/issues/697) - Add Authlogic::CryptoProviders::V2 module containing fixed SHA and MD5 encryption schemes + * [#697](https://github.com/binarylogic/authlogic/issues/697) - Add V2 CryptoProviders for MD5 and SHA schemes that fix key stretching by hashing the byte digests instead of the hex strings representing those digests ## 5.0.4 (2019-09-11)