9#include <botan/pgp_s2k.h>
11#include <botan/exceptn.h>
12#include <botan/mem_ops.h>
13#include <botan/internal/fmt.h>
14#include <botan/internal/time_utils.h>
25 const size_t password_size,
29 if(iterations > 1 && salt_len == 0) {
35 copy_mem(&input_buf[0], salt, salt_len);
37 if(password_size > 0) {
46 while(generated != output_len) {
47 const size_t output_this_pass = std::min(hash_buf.size(), output_len - generated);
50 std::vector<uint8_t> zero_padding(pass);
51 hash.update(zero_padding);
54 if(input_buf.empty() ==
false) {
55 size_t left = std::max(iterations, input_buf.size());
57 const size_t input_to_take = std::min(left, input_buf.size());
58 hash.update(input_buf.data(), input_to_take);
59 left -= input_to_take;
63 hash.final(hash_buf.data());
64 copy_mem(output_buf + generated, hash_buf.data(), output_this_pass);
65 generated += output_this_pass;
74 std::string_view password,
78 std::chrono::milliseconds msec)
const {
79 std::unique_ptr<PasswordHash> pwdhash;
83 iterations = s2k_params.
tune(output_len, msec, 0, std::chrono::milliseconds(10))->iterations();
86 pgp_s2k(*m_hash, output_buf, output_len, password.data(), password.size(), salt, salt_len, iterations);
92 return fmt(
"OpenPGP-S2K({})", m_hash->name());
96 std::chrono::milliseconds msec,
98 std::chrono::milliseconds tune_time)
const {
99 constexpr size_t buf_size = 1024;
100 std::vector<uint8_t> buffer(buf_size);
102 const uint64_t measured_nsec =
measure_cost(tune_time, [&]() { m_hash->update(buffer); });
104 const double hash_bytes_per_second = (buf_size * 1000000000.0) / measured_nsec;
105 const uint64_t desired_nsec = msec.count() * 1000000;
107 const size_t hash_size = m_hash->output_length();
108 const size_t blocks_required = (output_len <= hash_size ? 1 : (output_len + hash_size - 1) / hash_size);
110 const double bytes_to_be_hashed = (hash_bytes_per_second * (desired_nsec / 1000000000.0)) / blocks_required;
113 return std::make_unique<RFC4880_S2K>(m_hash->new_object(), iterations);
117 return std::make_unique<RFC4880_S2K>(m_hash->new_object(), iter);
121 return std::make_unique<RFC4880_S2K>(m_hash->new_object(), 50331648);
125 return std::make_unique<RFC4880_S2K>(m_hash->new_object(), iter);
132 return fmt(
"OpenPGP-S2K({},{})", m_hash->name(), m_iterations);
137 const char* password,
138 const size_t password_len,
139 const uint8_t salt[],
140 size_t salt_len)
const {
141 pgp_s2k(*m_hash, out, out_len, password, password_len, salt, salt_len, m_iterations);
size_t pbkdf(uint8_t output_buf[], size_t output_len, std::string_view passphrase, const uint8_t salt[], size_t salt_len, size_t iterations, std::chrono::milliseconds msec) const override
void hash(std::span< uint8_t > out, std::string_view password, std::span< const uint8_t > salt) const
std::unique_ptr< PasswordHash > default_params() const override
std::unique_ptr< PasswordHash > tune(size_t output_len, std::chrono::milliseconds msec, size_t max_mem, std::chrono::milliseconds tune_msec) const override
std::string name() const override
std::unique_ptr< PasswordHash > from_params(size_t iter, size_t, size_t) const override
std::unique_ptr< PasswordHash > from_iterations(size_t iter) const override
std::string to_string() 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
size_t iterations() const override
RFC4880_S2K(std::unique_ptr< HashFunction > hash, size_t iterations)
std::string fmt(std::string_view format, const T &... args)
std::vector< T, secure_allocator< T > > secure_vector
uint64_t measure_cost(std::chrono::milliseconds trial_msec, F func)
constexpr void copy_mem(T *out, const T *in, size_t n)
size_t RFC4880_round_iterations(size_t iterations)
const uint8_t * cast_char_ptr_to_uint8(const char *s)