diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/passhash/bcrypt/bcrypt.cpp | 31 | ||||
-rw-r--r-- | src/lib/passhash/bcrypt/bcrypt.h | 17 | ||||
-rw-r--r-- | src/tests/data/passhash/bcrypt.vec | 11 |
3 files changed, 47 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); } diff --git a/src/tests/data/passhash/bcrypt.vec b/src/tests/data/passhash/bcrypt.vec index de0eefbd2..103fda132 100644 --- a/src/tests/data/passhash/bcrypt.vec +++ b/src/tests/data/passhash/bcrypt.vec @@ -7,6 +7,10 @@ Passhash = $2a$05$DfPyLs.G6.To9fXEFgUL1O6HpYw3jIXgPcl/L3Qt3jESuWmhxtmpS Password = A3 Passhash = $2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq +# Test 2b support +Password = A3 +Passhash = $2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq + # Following values from http://download.openwall.net/pub/projects/crypt/bcrypt-tester-1.0.tar.gz Password = Passhash = $2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy @@ -52,6 +56,13 @@ Passhash = $2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe Password = 4142434445464748494a4b4c4d4e4f505152535455565758595a4142434445464748494a4b4c4d4e4f505152535455565758595a4142434445464748494a4b4c4d4e4f505152535455565758595a4142434445464748494a4b4c4d4e4f505152535455565758595a4142434445464748494a4b4c4d4e4f505152535455565758595a4142434445464748494a4b4c4d4e4f505152535455565758595a4142434445464748494a4b4c4d4e4f505152535455565758595a4142434445464748494a4b4c4d4e4f505152535455565758595a4142434445464748494a4b4c4d4e4f505152535455565758595a4142434445464748494a4b4c4d4e4f505152535455565758595b Passhash = $2a$04$nP0HWhorPRGl309OF27N0Oluj0wfAKWClP9gDcqOU1D.VF4x6bHTi +# Generated by crypt_blowfish +Password = 70617373776F7264 +Passhash = $2y$12$5Xmto5aXd2I.3UhLab4gc.kXojwbikijoAdr4vsnqjs9H2C7VVndK + +Password = 70617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F726470617373776F7264 +Passhash = $2y$12$IkojkAkofcOgOmnjdB4Xt.ZroyJaMQ7thxsdR/orgJfBS8YnkZthe + # Generated by OpenBSD's bcrypt code Password = |