• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 6546858227

17 Oct 2023 12:02PM UTC coverage: 91.71% (+0.002%) from 91.708%
6546858227

push

github

randombit
Merge GH #3760 Move constant time memory comparisons to ct_utils.h

80095 of 87335 relevant lines covered (91.71%)

8508512.25 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.72
/src/lib/passhash/argon2fmt/argon2fmt.cpp
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

16
namespace Botan {
17

18
namespace {
19

20
std::string strip_padding(std::string s) {
12✔
21
   while(!s.empty() && s[s.size() - 1] == '=') {
36✔
22
      s.resize(s.size() - 1);
24✔
23
   }
24
   return s;
12✔
25
}
26

27
std::string argon2_family(uint8_t y) {
14✔
28
   if(y == 0) {
14✔
29
      return "Argon2d";
3✔
30
   } else if(y == 1) {
11✔
31
      return "Argon2i";
3✔
32
   } else if(y == 2) {
8✔
33
      return "Argon2id";
8✔
34
   } else {
35
      throw Not_Implemented("Unknown Argon2 family type");
×
36
   }
37
}
38

39
}  // namespace
40

41
std::string argon2_generate_pwhash(const char* password,
6✔
42
                                   size_t password_len,
43
                                   RandomNumberGenerator& rng,
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);
6✔
51
   rng.randomize(salt.data(), salt.size());
6✔
52

53
   std::vector<uint8_t> output(output_len);
6✔
54

55
   auto pwdhash_fam = PasswordHashFamily::create_or_throw(argon2_family(y));
6✔
56
   auto pwdhash = pwdhash_fam->from_params(M, t, p);
6✔
57

58
   pwdhash->derive_key(output.data(), output.size(), password, password_len, salt.data(), salt.size());
6✔
59

60
   const auto enc_salt = strip_padding(base64_encode(salt));
6✔
61
   const auto enc_output = strip_padding(base64_encode(output));
6✔
62

63
   const std::string argon2_mode = [&]() -> std::string {
12✔
64
      if(y == 0) {
6✔
65
         return "d";
1✔
66
      } else if(y == 1) {
5✔
67
         return "i";
1✔
68
      } else {
69
         return "id";
4✔
70
      }
71
   }();
6✔
72

73
   return fmt("$argon2{}$v=19$m={},t={},p={}${}${}", argon2_mode, M, t, p, enc_salt, enc_output);
6✔
74
}
42✔
75

76
bool argon2_check_pwhash(const char* password, size_t password_len, std::string_view input_hash) {
8✔
77
   const std::vector<std::string> parts = split_on(input_hash, '$');
8✔
78

79
   if(parts.size() != 5) {
8✔
80
      return false;
81
   }
82

83
   uint8_t family = 0;
8✔
84

85
   if(parts[0] == "argon2d") {
8✔
86
      family = 0;
87
   } else if(parts[0] == "argon2i") {
6✔
88
      family = 1;
89
   } else if(parts[0] == "argon2id") {
4✔
90
      family = 2;
91
   } else {
92
      return false;
93
   }
94

95
   if(parts[1] != "v=19") {
8✔
96
      return false;
97
   }
98

99
   const std::vector<std::string> params = split_on(parts[2], ',');
8✔
100

101
   if(params.size() != 3) {
8✔
102
      return false;
103
   }
104

105
   size_t M = 0, t = 0, p = 0;
106

107
   for(const auto& param_str : params) {
32✔
108
      const std::vector<std::string> param = split_on(param_str, '=');
24✔
109

110
      if(param.size() != 2) {
24✔
111
         return false;
112
      }
113

114
      std::string_view key = param[0];
24✔
115
      const size_t val = to_u32bit(param[1]);
24✔
116
      if(key == "m") {
48✔
117
         M = val;
118
      } else if(key == "t") {
32✔
119
         t = val;
120
      } else if(key == "p") {
16✔
121
         p = val;
122
      } else {
123
         return false;
×
124
      }
125
   }
24✔
126

127
   std::vector<uint8_t> salt(base64_decode_max_output(parts[3].size()));
8✔
128
   salt.resize(base64_decode(salt.data(), parts[3], false));
8✔
129

130
   std::vector<uint8_t> hash(base64_decode_max_output(parts[4].size()));
8✔
131
   hash.resize(base64_decode(hash.data(), parts[4], false));
8✔
132

133
   if(hash.size() < 4) {
8✔
134
      return false;
135
   }
136

137
   std::vector<uint8_t> generated(hash.size());
8✔
138
   auto pwdhash_fam = PasswordHashFamily::create_or_throw(argon2_family(family));
8✔
139
   auto pwdhash = pwdhash_fam->from_params(M, t, p);
8✔
140

141
   pwdhash->derive_key(generated.data(), generated.size(), password, password_len, salt.data(), salt.size());
8✔
142

143
   return CT::is_equal(generated.data(), hash.data(), generated.size()).as_bool();
16✔
144
}
40✔
145

146
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc