7#include <botan/argon2.h>
9#include <botan/assert.h>
10#include <botan/exceptn.h>
11#include <botan/internal/fmt.h>
12#include <botan/internal/time_utils.h>
20std::string argon2_family_name(uint8_t f) {
33constexpr size_t MAX_ARGON_MEMORY_GB =
sizeof(size_t) == 4 ? 2 : 8;
38 BOTAN_ARG_CHECK(m_family == 0 || m_family == 1 || m_family == 2,
"Invalid Argon2 family parameter");
39 BOTAN_ARG_CHECK(m_p >= 1 && m_p <= 128,
"Invalid Argon2 threads parameter");
40 BOTAN_ARG_CHECK(m_M >= 8 * m_p && m_M <= MAX_ARGON_MEMORY_GB * 1024 * 1024,
"Invalid Argon2 M parameter");
41 BOTAN_ARG_CHECK(m_t >= 1 && m_t <= std::numeric_limits<uint32_t>::max(),
"Invalid Argon2 t parameter");
49 size_t salt_len)
const {
50 argon2(output, output_len, password, password_len, salt, salt_len,
nullptr, 0,
nullptr, 0);
62 size_t key_len)
const {
63 argon2(output, output_len, password, password_len, salt, salt_len, key, key_len, ad, ad_len);
67 return fmt(
"{}({},{},{})", argon2_family_name(m_family), m_M, m_t, m_p);
71 if(m_family != 0 && m_family != 1 && m_family != 2) {
77 return argon2_family_name(m_family);
81 uint64_t desired_msec,
82 std::optional<size_t> max_memory,
83 uint64_t tune_msec)
const {
85 const size_t max_kib = std::min(MAX_ARGON_MEMORY_GB * 1024 * 1024, max_memory.value_or(256) * 1024);
89 const size_t tune_M = (desired_msec >= 200 ? 128 : 36) * 1024;
97 auto tune_fn = [&]() {
98 uint8_t output[64] = {0};
99 pwhash->derive_key(output,
sizeof(output),
"test", 4,
nullptr, 0);
102 const uint64_t measured_time =
measure_cost(tune_msec, tune_fn) / (tune_M / M);
104 const uint64_t target_nsec = desired_msec *
static_cast<uint64_t
>(1000000);
114 uint64_t est_nsec = measured_time;
116 if(est_nsec < target_nsec && M < max_kib) {
117 const uint64_t desired_cost_increase = (target_nsec + est_nsec - 1) / est_nsec;
118 const uint64_t mem_headroom = max_kib / M;
120 const uint64_t M_mult = std::min(desired_cost_increase, mem_headroom);
121 M *=
static_cast<size_t>(M_mult);
125 if(est_nsec < target_nsec / 2) {
126 const uint64_t desired_cost_increase = (target_nsec + est_nsec - 1) / est_nsec;
127 t *=
static_cast<size_t>(desired_cost_increase);
143 const size_t M = iter;
150 return std::make_unique<Argon2>(m_family, M, t, p);
#define BOTAN_ARG_CHECK(expr, msg)
std::unique_ptr< PasswordHash > from_params(size_t M, size_t t, size_t p) const override
std::string name() const override
BOTAN_FUTURE_EXPLICIT Argon2_Family(uint8_t family)
std::unique_ptr< PasswordHash > tune_params(size_t output_len, uint64_t desired_runtime_msec, std::optional< size_t > max_memory, uint64_t tune_msec) const override
std::unique_ptr< PasswordHash > default_params() const override
std::unique_ptr< PasswordHash > from_iterations(size_t iter) const override
void derive_key(uint8_t out[], size_t out_len, const char *password, size_t password_len, const uint8_t salt[], size_t salt_len) const override
std::string to_string() const override
Argon2(uint8_t family, size_t M, size_t t, size_t p)
std::string fmt(std::string_view format, const T &... args)
uint64_t measure_cost(uint64_t trial_msec, F func)