Botan 3.6.1
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/mem_ops.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 const std::vector<std::string> parts = split_on(input_hash, '$');
79
80 if(parts.size() != 5) {
81 return false;
82 }
83
84 uint8_t family = 0;
85
86 if(parts[0] == "argon2d") {
87 family = 0;
88 } else if(parts[0] == "argon2i") {
89 family = 1;
90 } else if(parts[0] == "argon2id") {
91 family = 2;
92 } else {
93 return false;
94 }
95
96 if(parts[1] != "v=19") {
97 return false;
98 }
99
100 const std::vector<std::string> params = split_on(parts[2], ',');
101
102 if(params.size() != 3) {
103 return false;
104 }
105
106 size_t M = 0, t = 0, p = 0;
107
108 for(const auto& param_str : params) {
109 const std::vector<std::string> param = split_on(param_str, '=');
110
111 if(param.size() != 2) {
112 return false;
113 }
114
115 std::string_view key = param[0];
116 const size_t val = to_u32bit(param[1]);
117 if(key == "m") {
118 M = val;
119 } else if(key == "t") {
120 t = val;
121 } else if(key == "p") {
122 p = val;
123 } else {
124 return false;
125 }
126 }
127
128 std::vector<uint8_t> salt(base64_decode_max_output(parts[3].size()));
129 salt.resize(base64_decode(salt.data(), parts[3], false));
130
131 std::vector<uint8_t> hash(base64_decode_max_output(parts[4].size()));
132 hash.resize(base64_decode(hash.data(), parts[4], false));
133
134 if(hash.size() < 4) {
135 return false;
136 }
137
138 std::vector<uint8_t> generated(hash.size());
139 auto pwdhash_fam = PasswordHashFamily::create_or_throw(argon2_family(family));
140 auto pwdhash = pwdhash_fam->from_params(M, t, p);
141
142 pwdhash->derive_key(generated.data(), generated.size(), password, password_len, salt.data(), salt.size());
143
144 return CT::is_equal(generated.data(), hash.data(), generated.size()).as_bool();
145}
146
147} // namespace Botan
static std::unique_ptr< PasswordHashFamily > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition pwdhash.cpp:109
void randomize(std::span< uint8_t > output)
Definition rng.h:53
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:759
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:160
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:168
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:200