Botan 3.10.0
Crypto and TLS for C&
argon2fmt.cpp
Go to the documentation of this file.
1/**
2* (C) 2019 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/argon2fmt.h>
8
9#include <botan/base64.h>
10#include <botan/pwdhash.h>
11#include <botan/rng.h>
12#include <botan/internal/ct_utils.h>
13#include <botan/internal/fmt.h>
14#include <botan/internal/parsing.h>
15
16namespace Botan {
17
18namespace {
19
20std::string strip_padding(std::string s) {
21 while(!s.empty() && s[s.size() - 1] == '=') {
22 s.resize(s.size() - 1);
23 }
24 return s;
25}
26
27std::string argon2_family(uint8_t y) {
28 if(y == 0) {
29 return "Argon2d";
30 } else if(y == 1) {
31 return "Argon2i";
32 } else if(y == 2) {
33 return "Argon2id";
34 } else {
35 throw Not_Implemented("Unknown Argon2 family type");
36 }
37}
38
39} // namespace
40
41std::string argon2_generate_pwhash(const char* password,
42 size_t password_len,
44 size_t p,
45 size_t M,
46 size_t t,
47 uint8_t y,
48 size_t salt_len,
49 size_t output_len) {
50 std::vector<uint8_t> salt(salt_len);
51 rng.randomize(salt.data(), salt.size());
52
53 std::vector<uint8_t> output(output_len);
54
55 auto pwdhash_fam = PasswordHashFamily::create_or_throw(argon2_family(y));
56 auto pwdhash = pwdhash_fam->from_params(M, t, p);
57
58 pwdhash->derive_key(output.data(), output.size(), password, password_len, salt.data(), salt.size());
59
60 const auto enc_salt = strip_padding(base64_encode(salt));
61 const auto enc_output = strip_padding(base64_encode(output));
62
63 const std::string argon2_mode = [&]() -> std::string {
64 if(y == 0) {
65 return "d";
66 } else if(y == 1) {
67 return "i";
68 } else {
69 return "id";
70 }
71 }();
72
73 return fmt("$argon2{}$v=19$m={},t={},p={}${}${}", argon2_mode, M, t, p, enc_salt, enc_output);
74}
75
76bool argon2_check_pwhash(const char* password, size_t password_len, std::string_view input_hash) {
77 const std::vector<std::string> parts = split_on(input_hash, '$');
78
79 if(parts.size() != 5) {
80 return false;
81 }
82
83 uint8_t family = 0;
84
85 if(parts[0] == "argon2d") {
86 family = 0;
87 } else if(parts[0] == "argon2i") {
88 family = 1;
89 } else if(parts[0] == "argon2id") {
90 family = 2;
91 } else {
92 return false;
93 }
94
95 if(parts[1] != "v=19") {
96 return false;
97 }
98
99 const std::vector<std::string> params = split_on(parts[2], ',');
100
101 if(params.size() != 3) {
102 return false;
103 }
104
105 size_t M = 0;
106 size_t t = 0;
107 size_t p = 0;
108
109 for(const auto& param_str : params) {
110 const std::vector<std::string> param = split_on(param_str, '=');
111
112 if(param.size() != 2) {
113 return false;
114 }
115
116 std::string_view key = param[0];
117 const size_t val = to_u32bit(param[1]);
118 if(key == "m") {
119 M = val;
120 } else if(key == "t") {
121 t = val;
122 } else if(key == "p") {
123 p = val;
124 } else {
125 return false;
126 }
127 }
128
129 std::vector<uint8_t> salt(base64_decode_max_output(parts[3].size()));
130 salt.resize(base64_decode(salt.data(), parts[3], false));
131
132 std::vector<uint8_t> hash(base64_decode_max_output(parts[4].size()));
133 hash.resize(base64_decode(hash.data(), parts[4], false));
134
135 if(hash.size() < 4) {
136 return false;
137 }
138
139 std::vector<uint8_t> generated(hash.size());
140 auto pwdhash_fam = PasswordHashFamily::create_or_throw(argon2_family(family));
141 auto pwdhash = pwdhash_fam->from_params(M, t, p);
142
143 pwdhash->derive_key(generated.data(), generated.size(), password, password_len, salt.data(), salt.size());
144
145 return CT::is_equal(generated.data(), hash.data(), generated.size()).as_bool();
146}
147
148} // namespace Botan
static std::unique_ptr< PasswordHashFamily > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition pwdhash.cpp:110
void randomize(std::span< uint8_t > output)
Definition rng.h:71
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:826
uint32_t to_u32bit(std::string_view str_view)
Definition parsing.cpp:32
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
std::vector< std::string > split_on(std::string_view str, char delim)
Definition parsing.cpp:111
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition base64.cpp:159
size_t base64_decode(uint8_t out[], const char in[], size_t input_length, size_t &input_consumed, bool final_inputs, bool ignore_ws)
Definition base64.cpp:167
bool argon2_check_pwhash(const char *password, size_t password_len, std::string_view input_hash)
Definition argon2fmt.cpp:76
std::string argon2_generate_pwhash(const char *password, size_t password_len, RandomNumberGenerator &rng, size_t p, size_t M, size_t t, uint8_t y, size_t salt_len, size_t output_len)
Definition argon2fmt.cpp:41
size_t base64_decode_max_output(size_t input_length)
Definition base64.cpp:199