diff options
author | Jack Lloyd <[email protected]> | 2018-06-29 16:31:14 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2018-06-29 16:31:14 -0400 |
commit | 485c0a8c9d6cd4c2e28993d5f0e6e27e9c49bc82 (patch) | |
tree | 771d910ad2413b6cc932d602d2a2918bae7b250d /src/lib/passhash/bcrypt | |
parent | 334e170ea169117948ace86c3729f87d1a8c8fe5 (diff) |
Support bcrypt 2b and 2y
Continue to default to 2a since older versions don't know about 2b.
Both 2b and 2y are identical to our implementation of 2a since we never
implemented the relevant bugs which necessitated the new formats.
Diffstat (limited to 'src/lib/passhash/bcrypt')
-rw-r--r-- | src/lib/passhash/bcrypt/bcrypt.cpp | 31 | ||||
-rw-r--r-- | src/lib/passhash/bcrypt/bcrypt.h | 17 |
2 files changed, 36 insertions, 12 deletions
diff --git a/src/lib/passhash/bcrypt/bcrypt.cpp b/src/lib/passhash/bcrypt/bcrypt.cpp index d4dc263e1..5688df0e6 100644 --- a/src/lib/passhash/bcrypt/bcrypt.cpp +++ b/src/lib/passhash/bcrypt/bcrypt.cpp @@ -1,6 +1,6 @@ /* * Bcrypt Password Hashing -* (C) 2010 Jack Lloyd +* (C) 2010,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -89,7 +89,8 @@ std::vector<uint8_t> bcrypt_base64_decode(std::string input) std::string make_bcrypt(const std::string& pass, const std::vector<uint8_t>& salt, - uint16_t work_factor) + uint16_t work_factor, + char version) { static const uint8_t BCRYPT_MAGIC[8*3] = { 0x4F, 0x72, 0x70, 0x68, 0x65, 0x61, 0x6E, 0x42, @@ -116,7 +117,7 @@ std::string make_bcrypt(const std::string& pass, if(work_factor_str.length() == 1) work_factor_str = "0" + work_factor_str; - return "$2a$" + work_factor_str + + return "$2" + std::string(1, version) + "$" + work_factor_str + "$" + salt_b64.substr(0, 22) + bcrypt_base64_encode(ctext.data(), ctext.size() - 1); } @@ -125,16 +126,30 @@ std::string make_bcrypt(const std::string& pass, std::string generate_bcrypt(const std::string& pass, RandomNumberGenerator& rng, - uint16_t work_factor) + uint16_t work_factor, + char version) { - return make_bcrypt(pass, unlock(rng.random_vec(16)), work_factor); + /* + 2a, 2b and 2y are identical for our purposes because our implementation of 2a + never had the truncation or signed char bugs in the first place. + */ + + if(version != 'a' && version != 'b' && version != 'y') + throw Invalid_Argument("Unknown bcrypt version '" + std::string(1, version) + "'"); + return make_bcrypt(pass, unlock(rng.random_vec(16)), work_factor, version); } bool check_bcrypt(const std::string& pass, const std::string& hash) { if(hash.size() != 60 || - hash[0] != '$' || hash[1] != '2' || hash[2] != 'a' || - hash[3] != '$' || hash[6] != '$') + hash[0] != '$' || hash[1] != '2' || hash[3] != '$' || hash[6] != '$') + { + return false; + } + + const char bcrypt_version = hash[2]; + + if(bcrypt_version != 'a' && bcrypt_version != 'b' && bcrypt_version != 'y') { return false; } @@ -145,7 +160,7 @@ bool check_bcrypt(const std::string& pass, const std::string& hash) if(salt.size() != 16) return false; - const std::string compare = make_bcrypt(pass, salt, workfactor); + const std::string compare = make_bcrypt(pass, salt, workfactor, bcrypt_version); return same_mem(hash.data(), compare.data(), compare.size()); } diff --git a/src/lib/passhash/bcrypt/bcrypt.h b/src/lib/passhash/bcrypt/bcrypt.h index f5b811333..7d46e836c 100644 --- a/src/lib/passhash/bcrypt/bcrypt.h +++ b/src/lib/passhash/bcrypt/bcrypt.h @@ -17,15 +17,24 @@ class RandomNumberGenerator; /** * Create a password hash using Bcrypt -* @param password the password +* +* @warning The password is truncated at at most 72 characters; characters after +* that do not have any effect on the resulting hash. To support longer +* passwords, consider pre-hashing the password, for example by using +* the hex encoding of SHA-256 of the password as the input to bcrypt. +* +* @param password the password. * @param rng a random number generator * @param work_factor how much work to do to slow down guessing attacks +* @param version which version to emit (may be 'a', 'b', or 'y' all of which +* have identical behavior in this implementation). * * @see https://www.usenix.org/events/usenix99/provos/provos_html/ */ std::string BOTAN_PUBLIC_API(2,0) generate_bcrypt(const std::string& password, - RandomNumberGenerator& rng, - uint16_t work_factor = 10); + RandomNumberGenerator& rng, + uint16_t work_factor = 10, + char version = 'a'); /** * Check a previously created password hash @@ -33,7 +42,7 @@ std::string BOTAN_PUBLIC_API(2,0) generate_bcrypt(const std::string& password, * @param hash the stored hash to check against */ bool BOTAN_PUBLIC_API(2,0) check_bcrypt(const std::string& password, - const std::string& hash); + const std::string& hash); } |