summaryrefslogtreecommitdiffstats
path: root/comm/third_party/botan/src/lib/passhash
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/botan/src/lib/passhash')
-rw-r--r--comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.cpp181
-rw-r--r--comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.h49
-rw-r--r--comm/third_party/botan/src/lib/passhash/bcrypt/info.txt9
-rw-r--r--comm/third_party/botan/src/lib/passhash/passhash9/info.txt9
-rw-r--r--comm/third_party/botan/src/lib/passhash/passhash9/passhash9.cpp142
-rw-r--r--comm/third_party/botan/src/lib/passhash/passhash9/passhash9.h52
6 files changed, 442 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.cpp b/comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.cpp
new file mode 100644
index 0000000000..1d28ddfb4d
--- /dev/null
+++ b/comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.cpp
@@ -0,0 +1,181 @@
+/*
+* Bcrypt Password Hashing
+* (C) 2010,2018 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/bcrypt.h>
+#include <botan/rng.h>
+#include <botan/blowfish.h>
+#include <botan/base64.h>
+#include <botan/parsing.h>
+
+namespace Botan {
+
+namespace {
+
+std::string bcrypt_base64_encode(const uint8_t input[], size_t length)
+ {
+ // Bcrypt uses a non-standard base64 alphabet
+ const uint8_t OPENBSD_BASE64_SUB[256] = {
+ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x38, 0x80, 0x80, 0x80, 0x39,
+ 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x2E, 0x2F, 0x41, 0x42, 0x43, 0x44, 0x45,
+ 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
+ 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+ 0x76, 0x77, 0x78, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80
+ };
+
+ std::string b64 = base64_encode(input, length);
+
+ while(b64.size() && b64[b64.size()-1] == '=')
+ b64 = b64.substr(0, b64.size() - 1);
+
+ for(size_t i = 0; i != b64.size(); ++i)
+ b64[i] = OPENBSD_BASE64_SUB[static_cast<uint8_t>(b64[i])];
+
+ return b64;
+ }
+
+std::vector<uint8_t> bcrypt_base64_decode(std::string input)
+ {
+ const uint8_t OPENBSD_BASE64_SUB[256] = {
+ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x41, 0x42,
+ 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55,
+ 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
+ 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7A, 0x30, 0x31, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80
+ };
+
+ for(size_t i = 0; i != input.size(); ++i)
+ input[i] = OPENBSD_BASE64_SUB[static_cast<uint8_t>(input[i])];
+
+ return unlock(base64_decode(input));
+ }
+
+std::string make_bcrypt(const std::string& pass,
+ const std::vector<uint8_t>& salt,
+ uint16_t work_factor,
+ char version)
+ {
+ /*
+ * On a 4 GHz Skylake, workfactor == 18 takes about 15 seconds to
+ * hash a password. This seems like a reasonable upper bound for the
+ * time being.
+ * Bcrypt allows up to work factor 31 (2^31 iterations)
+ */
+ BOTAN_ARG_CHECK(work_factor >= 4 && work_factor <= 18,
+ "Invalid bcrypt work factor");
+
+ static const uint8_t BCRYPT_MAGIC[8*3] = {
+ 0x4F, 0x72, 0x70, 0x68, 0x65, 0x61, 0x6E, 0x42,
+ 0x65, 0x68, 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x53,
+ 0x63, 0x72, 0x79, 0x44, 0x6F, 0x75, 0x62, 0x74
+ };
+
+ Blowfish blowfish;
+
+ // Include the trailing NULL byte, so we need c_str() not data()
+ blowfish.salted_set_key(cast_char_ptr_to_uint8(pass.c_str()),
+ pass.length() + 1,
+ salt.data(),
+ salt.size(),
+ work_factor);
+
+ std::vector<uint8_t> ctext(BCRYPT_MAGIC, BCRYPT_MAGIC + 8*3);
+
+ for(size_t i = 0; i != 64; ++i)
+ blowfish.encrypt_n(ctext.data(), ctext.data(), 3);
+
+ std::string salt_b64 = bcrypt_base64_encode(salt.data(), salt.size());
+
+ std::string work_factor_str = std::to_string(work_factor);
+ if(work_factor_str.length() == 1)
+ work_factor_str = "0" + 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);
+ }
+
+}
+
+std::string generate_bcrypt(const std::string& pass,
+ RandomNumberGenerator& rng,
+ uint16_t work_factor,
+ char version)
+ {
+ /*
+ 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) + "'");
+
+ std::vector<uint8_t> salt;
+ rng.random_vec(salt, 16);
+ return make_bcrypt(pass, salt, work_factor, version);
+ }
+
+bool check_bcrypt(const std::string& pass, const std::string& hash)
+ {
+ if(hash.size() != 60 ||
+ 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;
+ }
+
+ const uint16_t workfactor = to_uint16(hash.substr(4, 2));
+
+ const std::vector<uint8_t> salt = bcrypt_base64_decode(hash.substr(7, 22));
+ if(salt.size() != 16)
+ return false;
+
+ const std::string compare = make_bcrypt(pass, salt, workfactor, bcrypt_version);
+
+ return same_mem(hash.data(), compare.data(), compare.size());
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.h b/comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.h
new file mode 100644
index 0000000000..cdf9cf3d19
--- /dev/null
+++ b/comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.h
@@ -0,0 +1,49 @@
+/*
+* Bcrypt Password Hashing
+* (C) 2011 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_BCRYPT_H_
+#define BOTAN_BCRYPT_H_
+
+#include <botan/types.h>
+#include <string>
+
+namespace Botan {
+
+class RandomNumberGenerator;
+
+/**
+* Create a password hash using Bcrypt
+*
+* @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 = 12,
+ char version = 'a');
+
+/**
+* Check a previously created password hash
+* @param password the password to check against
+* @param hash the stored hash to check against
+*/
+bool BOTAN_PUBLIC_API(2,0) check_bcrypt(const std::string& password,
+ const std::string& hash);
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/passhash/bcrypt/info.txt b/comm/third_party/botan/src/lib/passhash/bcrypt/info.txt
new file mode 100644
index 0000000000..6be060ea0f
--- /dev/null
+++ b/comm/third_party/botan/src/lib/passhash/bcrypt/info.txt
@@ -0,0 +1,9 @@
+<defines>
+BCRYPT -> 20131128
+</defines>
+
+<requires>
+blowfish
+rng
+base64
+</requires>
diff --git a/comm/third_party/botan/src/lib/passhash/passhash9/info.txt b/comm/third_party/botan/src/lib/passhash/passhash9/info.txt
new file mode 100644
index 0000000000..525427b45d
--- /dev/null
+++ b/comm/third_party/botan/src/lib/passhash/passhash9/info.txt
@@ -0,0 +1,9 @@
+<defines>
+PASSHASH9 -> 20131128
+</defines>
+
+<requires>
+pbkdf2
+rng
+base64
+</requires>
diff --git a/comm/third_party/botan/src/lib/passhash/passhash9/passhash9.cpp b/comm/third_party/botan/src/lib/passhash/passhash9/passhash9.cpp
new file mode 100644
index 0000000000..98f5a54d51
--- /dev/null
+++ b/comm/third_party/botan/src/lib/passhash/passhash9/passhash9.cpp
@@ -0,0 +1,142 @@
+/*
+* Passhash9 Password Hashing
+* (C) 2010 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/passhash9.h>
+#include <botan/rng.h>
+#include <botan/loadstor.h>
+#include <botan/pbkdf2.h>
+#include <botan/base64.h>
+
+namespace Botan {
+
+namespace {
+
+const std::string MAGIC_PREFIX = "$9$";
+
+const size_t WORKFACTOR_BYTES = 2;
+const size_t ALGID_BYTES = 1;
+const size_t SALT_BYTES = 12; // 96 bits of salt
+const size_t PASSHASH9_PBKDF_OUTPUT_LEN = 24; // 192 bits output
+
+const size_t WORK_FACTOR_SCALE = 10000;
+
+std::unique_ptr<MessageAuthenticationCode> get_pbkdf_prf(uint8_t alg_id)
+ {
+ if(alg_id == 0)
+ return MessageAuthenticationCode::create("HMAC(SHA-1)");
+ else if(alg_id == 1)
+ return MessageAuthenticationCode::create("HMAC(SHA-256)");
+ else if(alg_id == 2)
+ return MessageAuthenticationCode::create("CMAC(Blowfish)");
+ else if(alg_id == 3)
+ return MessageAuthenticationCode::create("HMAC(SHA-384)");
+ else if(alg_id == 4)
+ return MessageAuthenticationCode::create("HMAC(SHA-512)");
+ return nullptr;
+ }
+
+}
+
+std::string generate_passhash9(const std::string& pass,
+ RandomNumberGenerator& rng,
+ uint16_t work_factor,
+ uint8_t alg_id)
+ {
+ BOTAN_ARG_CHECK(work_factor > 0 && work_factor < 512, "Invalid Passhash9 work factor");
+
+ std::unique_ptr<MessageAuthenticationCode> prf = get_pbkdf_prf(alg_id);
+
+ if(!prf)
+ throw Invalid_Argument("Passhash9: Algorithm id " +
+ std::to_string(alg_id) +
+ " is not defined");
+
+ PKCS5_PBKDF2 kdf(prf.release()); // takes ownership of pointer
+
+ secure_vector<uint8_t> salt(SALT_BYTES);
+ rng.randomize(salt.data(), salt.size());
+
+ const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor;
+
+ secure_vector<uint8_t> blob;
+ blob.push_back(alg_id);
+ blob.push_back(get_byte(0, work_factor));
+ blob.push_back(get_byte(1, work_factor));
+ blob += salt;
+ blob += kdf.derive_key(PASSHASH9_PBKDF_OUTPUT_LEN,
+ pass,
+ salt.data(), salt.size(),
+ kdf_iterations).bits_of();
+
+ return MAGIC_PREFIX + base64_encode(blob);
+ }
+
+bool check_passhash9(const std::string& pass, const std::string& hash)
+ {
+ const size_t BINARY_LENGTH =
+ ALGID_BYTES +
+ WORKFACTOR_BYTES +
+ PASSHASH9_PBKDF_OUTPUT_LEN +
+ SALT_BYTES;
+
+ const size_t BASE64_LENGTH =
+ MAGIC_PREFIX.size() + (BINARY_LENGTH * 8) / 6;
+
+ if(hash.size() != BASE64_LENGTH)
+ return false;
+
+ for(size_t i = 0; i != MAGIC_PREFIX.size(); ++i)
+ if(hash[i] != MAGIC_PREFIX[i])
+ return false;
+
+ secure_vector<uint8_t> bin = base64_decode(hash.c_str() + MAGIC_PREFIX.size());
+
+ if(bin.size() != BINARY_LENGTH)
+ return false;
+
+ uint8_t alg_id = bin[0];
+
+ const size_t work_factor = load_be<uint16_t>(&bin[ALGID_BYTES], 0);
+
+ // Bug in the format, bad states shouldn't be representable, but are...
+ if(work_factor == 0)
+ return false;
+
+ if(work_factor > 512)
+ throw Invalid_Argument("Requested passhash9 work factor " +
+ std::to_string(work_factor) + " is too large");
+
+ const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor;
+
+ std::unique_ptr<MessageAuthenticationCode> pbkdf_prf = get_pbkdf_prf(alg_id);
+
+ if(!pbkdf_prf)
+ return false; // unknown algorithm, reject
+
+ PKCS5_PBKDF2 kdf(pbkdf_prf.release()); // takes ownership of pointer
+
+ secure_vector<uint8_t> cmp = kdf.derive_key(
+ PASSHASH9_PBKDF_OUTPUT_LEN,
+ pass,
+ &bin[ALGID_BYTES + WORKFACTOR_BYTES], SALT_BYTES,
+ kdf_iterations).bits_of();
+
+ return constant_time_compare(cmp.data(),
+ &bin[ALGID_BYTES + WORKFACTOR_BYTES + SALT_BYTES],
+ PASSHASH9_PBKDF_OUTPUT_LEN);
+ }
+
+bool is_passhash9_alg_supported(uint8_t alg_id)
+ {
+ if (get_pbkdf_prf(alg_id))
+ {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/passhash/passhash9/passhash9.h b/comm/third_party/botan/src/lib/passhash/passhash9/passhash9.h
new file mode 100644
index 0000000000..b312cb1bf9
--- /dev/null
+++ b/comm/third_party/botan/src/lib/passhash/passhash9/passhash9.h
@@ -0,0 +1,52 @@
+/*
+* Passhash9 Password Hashing
+* (C) 2010 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_PASSHASH9_H_
+#define BOTAN_PASSHASH9_H_
+
+#include <botan/types.h>
+#include <string>
+
+namespace Botan {
+
+class RandomNumberGenerator;
+
+/**
+* Create a password hash using PBKDF2
+* @param password the password
+* @param rng a random number generator
+* @param work_factor how much work to do to slow down guessing attacks
+* @param alg_id specifies which PRF to use with PBKDF2
+* 0 is HMAC(SHA-1)
+* 1 is HMAC(SHA-256)
+* 2 is CMAC(Blowfish)
+* 3 is HMAC(SHA-384)
+* 4 is HMAC(SHA-512)
+* all other values are currently undefined
+*/
+std::string BOTAN_PUBLIC_API(2,0) generate_passhash9(const std::string& password,
+ RandomNumberGenerator& rng,
+ uint16_t work_factor = 15,
+ uint8_t alg_id = 4);
+
+/**
+* Check a previously created password hash
+* @param password the password to check against
+* @param hash the stored hash to check against
+*/
+bool BOTAN_PUBLIC_API(2,0) check_passhash9(const std::string& password,
+ const std::string& hash);
+
+/**
+* Check if the PRF used with PBKDF2 is supported
+* @param alg_id alg_id used in generate_passhash9()
+*/
+bool BOTAN_PUBLIC_API(2,3) is_passhash9_alg_supported(uint8_t alg_id);
+
+}
+
+#endif