9#include <botan/pgp_s2k.h>
11#include <botan/exceptn.h>
12#include <botan/internal/fmt.h>
13#include <botan/internal/timer.h>
20void pgp_s2k(HashFunction& hash,
24 const size_t password_size,
28 if(iterations > 1 && salt_len == 0) {
29 throw Invalid_Argument(
"OpenPGP S2K requires a salt in iterated mode");
34 copy_mem(&input_buf[0], salt, salt_len);
36 if(password_size > 0) {
45 while(generated != output_len) {
46 const size_t output_this_pass = std::min(hash_buf.size(), output_len - generated);
49 std::vector<uint8_t> zero_padding(pass);
50 hash.update(zero_padding);
53 if(input_buf.empty() ==
false) {
54 size_t left = std::max(iterations, input_buf.size());
56 const size_t input_to_take = std::min(left, input_buf.size());
57 hash.update(input_buf.data(), input_to_take);
58 left -= input_to_take;
62 hash.final(hash_buf.data());
63 copy_mem(output_buf + generated, hash_buf.data(), output_this_pass);
64 generated += output_this_pass;
73 std::string_view password,
77 std::chrono::milliseconds msec)
const {
78 std::unique_ptr<PasswordHash> pwdhash;
82 iterations = s2k_params.
tune(output_len, msec, 0, std::chrono::milliseconds(10))->iterations();
85 pgp_s2k(*m_hash, output_buf, output_len, password.data(), password.size(), salt, salt_len, iterations);
91 return fmt(
"OpenPGP-S2K({})", m_hash->name());
95 std::chrono::milliseconds msec,
97 std::chrono::milliseconds tune_time)
const {
98 const size_t buf_size = 1024;
99 std::vector<uint8_t> buffer(buf_size);
101 Timer timer(
"RFC4880_S2K", buf_size);
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);
129 m_hash(std::move(hash)), m_iterations(iterations) {}
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
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
RFC4880_S2K(std::unique_ptr< HashFunction > hash, size_t iterations)
void run_until_elapsed(std::chrono::milliseconds msec, F f)
double bytes_per_second() const
std::string fmt(std::string_view format, const T &... args)
std::vector< T, secure_allocator< T > > secure_vector
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)