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