8#include <botan/passhash9.h>
10#include <botan/internal/loadstor.h>
11#include <botan/pbkdf2.h>
12#include <botan/base64.h>
18const std::string MAGIC_PREFIX =
"$9$";
20const size_t WORKFACTOR_BYTES = 2;
21const size_t ALGID_BYTES = 1;
22const size_t SALT_BYTES = 12;
23const size_t PASSHASH9_PBKDF_OUTPUT_LEN = 24;
25const size_t WORK_FACTOR_SCALE = 10000;
27std::unique_ptr<MessageAuthenticationCode> get_pbkdf_prf(uint8_t alg_id)
49 BOTAN_ARG_CHECK(work_factor > 0 && work_factor < 512,
"Invalid Passhash9 work factor");
51 auto prf = get_pbkdf_prf(alg_id);
55 std::to_string(alg_id) +
63 const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor;
66 blob.push_back(alg_id);
67 blob.push_back(get_byte<0>(work_factor));
68 blob.push_back(get_byte<1>(work_factor));
70 blob += kdf.
derive_key(PASSHASH9_PBKDF_OUTPUT_LEN,
72 salt.data(), salt.size(),
80 const size_t BINARY_LENGTH =
83 PASSHASH9_PBKDF_OUTPUT_LEN +
86 const size_t BASE64_LENGTH =
87 MAGIC_PREFIX.size() + (BINARY_LENGTH * 8) / 6;
89 if(hash.size() != BASE64_LENGTH)
92 for(
size_t i = 0; i != MAGIC_PREFIX.size(); ++i)
93 if(hash[i] != MAGIC_PREFIX[i])
98 if(bin.size() != BINARY_LENGTH)
101 uint8_t alg_id = bin[0];
109 if(work_factor > 512)
111 std::to_string(work_factor) +
" is too large");
113 const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor;
115 auto pbkdf_prf = get_pbkdf_prf(alg_id);
123 PASSHASH9_PBKDF_OUTPUT_LEN,
125 &bin[ALGID_BYTES + WORKFACTOR_BYTES], SALT_BYTES,
129 &bin[ALGID_BYTES + WORKFACTOR_BYTES + SALT_BYTES],
130 PASSHASH9_PBKDF_OUTPUT_LEN);
135 if (get_pbkdf_prf(alg_id))
#define BOTAN_ARG_CHECK(expr, msg)
static std::unique_ptr< MessageAuthenticationCode > create(std::string_view algo_spec, std::string_view provider="")
secure_vector< uint8_t > bits_of() const
OctetString derive_key(size_t out_len, std::string_view passphrase, const uint8_t salt[], size_t salt_len, size_t iterations) const
void randomize(std::span< uint8_t > output)
std::string generate_passhash9(std::string_view pass, RandomNumberGenerator &rng, uint16_t work_factor, uint8_t alg_id)
bool check_passhash9(std::string_view pass, std::string_view hash)
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)
size_t base64_decode(uint8_t out[], const char in[], size_t input_length, size_t &input_consumed, bool final_inputs, bool ignore_ws)
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
bool is_passhash9_alg_supported(uint8_t alg_id)
constexpr uint16_t load_be< uint16_t >(const uint8_t in[], size_t off)
std::vector< T, secure_allocator< T > > secure_vector