Botan 3.0.0-alpha0
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 <sstream>
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 std::ostringstream oss;
57
58 if(y == 0)
59 oss << "$argon2d$";
60 else if(y == 1)
61 oss << "$argon2i$";
62 else
63 oss << "$argon2id$";
64
65 oss << "v=19$m=" << std::to_string(M)
66 << ",t=" << std::to_string(t)
67 << ",p=" << std::to_string(p) << "$";
68 oss << strip_padding(base64_encode(salt)) << "$" << strip_padding(base64_encode(output));
69
70 return oss.str();
71 }
72
73bool argon2_check_pwhash(const char* password, size_t password_len,
74 const std::string& input_hash)
75 {
76 const std::vector<std::string> parts = split_on(input_hash, '$');
77
78 if(parts.size() != 5)
79 return false;
80
81 uint8_t family = 0;
82
83 if(parts[0] == "argon2d")
84 family = 0;
85 else if(parts[0] == "argon2i")
86 family = 1;
87 else if(parts[0] == "argon2id")
88 family = 2;
89 else
90 return false;
91
92 if(parts[1] != "v=19")
93 return false;
94
95 const std::vector<std::string> params = split_on(parts[2], ',');
96
97 if(params.size() != 3)
98 return false;
99
100 size_t M = 0, t = 0, p = 0;
101
102 for(const auto& param_str : params)
103 {
104 const std::vector<std::string> param = split_on(param_str, '=');
105
106 if(param.size() != 2)
107 return false;
108
109 const std::string key = param[0];
110 const size_t val = to_u32bit(param[1]);
111 if(key == "m")
112 M = val;
113 else if(key == "t")
114 t = val;
115 else if(key == "p")
116 p = val;
117 else
118 return false;
119 }
120
121 std::vector<uint8_t> salt(base64_decode_max_output(parts[3].size()));
122 salt.resize(base64_decode(salt.data(), parts[3], false));
123
124 std::vector<uint8_t> hash(base64_decode_max_output(parts[4].size()));
125 hash.resize(base64_decode(hash.data(), parts[4], false));
126
127 if(hash.size() < 4)
128 return false;
129
130 std::vector<uint8_t> generated(hash.size());
131 auto pwdhash_fam = PasswordHashFamily::create_or_throw(argon2_family(family));
132 auto pwdhash = pwdhash_fam->from_params(M, t, p);
133
134 pwdhash->derive_key(generated.data(), generated.size(),
135 password, password_len,
136 salt.data(), salt.size());
137
138 return constant_time_compare(generated.data(), hash.data(), generated.size());
139 }
140
141}
static std::unique_ptr< PasswordHashFamily > create_or_throw(const std::string &algo_spec, const std::string &provider="")
Definition: pwdhash.cpp:117
virtual void randomize(uint8_t output[], size_t length)=0
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:209
Definition: alg_id.cpp:13
size_t base64_encode(char out[], const uint8_t in[], size_t input_length, size_t &input_consumed, bool final_inputs)
Definition: base64.cpp:185
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:200
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:82
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:111
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
bool argon2_check_pwhash(const char *password, size_t password_len, const std::string &input_hash)
Definition: argon2fmt.cpp:73
size_t base64_decode_max_output(size_t input_length)
Definition: base64.cpp:243
uint32_t to_u32bit(const std::string &str)
Definition: parsing.cpp:29
MechanismType hash
size_t salt_len
Definition: x509_obj.cpp:25