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