MySQL 9.1.0
Source Code Documentation
kdf_sha_crypt.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2018, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25#ifndef ROUTER_KDF_SHA_CRYPT_INCLUDED
26#define ROUTER_KDF_SHA_CRYPT_INCLUDED
27
28#include <string>
29#include <utility> // std::pair
30#include <vector>
31
32#include "digest.h"
33#include "mcf_error.h"
35
36/**
37 * sha256_crypt and sha512_crypt are SHA based crypt() key derivation functions.
38 * @see https://www.akkadia.org/drepper/SHA-crypt.txt
39 *
40 * caching_sha2_password is key derivation function taken from an internal
41 * MySQL authentication mechanism
42 */
44 public:
45 enum class Type { Sha256, Sha512, CachingSha2Password };
46 static std::string salt();
47 static std::string derive(Type digest, unsigned long rounds,
48 const std::string &salt,
49 const std::string &password);
50
51 private:
52 /**
53 * crypt specific base64 encode.
54 *
55 * different alphabet than RFC4648
56 */
57 static std::string base64_encode(const std::vector<uint8_t> &data);
58};
59
61 public:
63
64 static std::pair<bool, std::string> name(Type type) noexcept {
65 switch (type) {
66 case Type::Sha256:
67 return std::make_pair(true, kTypeSha256);
68 case Type::Sha512:
69 return std::make_pair(true, kTypeSha512);
71 return std::make_pair(true, kTypeCachingSha2Password);
72 }
73
74 return std::make_pair(false, std::string{});
75 }
76
77 static std::pair<bool, Type> type(const std::string &name) noexcept {
78 if (name == kTypeSha256) {
79 return std::make_pair(true, Type::Sha256);
80 } else if (name == kTypeSha512) {
81 return std::make_pair(true, Type::Sha512);
82 } else if (name == kTypeCachingSha2Password) {
83 return std::make_pair(true, Type::CachingSha2Password);
84 }
85
86 return std::make_pair(false, Type{});
87 }
88
89 static bool supports_name(const std::string &name) noexcept {
90 if (name == kTypeSha256) {
91 return true;
92 } else if (name == kTypeSha512) {
93 return true;
94 } else if (name == kTypeCachingSha2Password) {
95 return true;
96 }
97
98 return false;
99 }
100
101 private:
102 static constexpr char kTypeSha256[] = "5";
103 static constexpr char kTypeSha512[] = "6";
104 static constexpr char kTypeCachingSha2Password[] = "A";
105};
106
107/**
108 * MCF reader/writer for ShaCrypt
109 */
111 public:
114
116
117 /**
118 * number of rounds if no rounds was specified in from_mcf().
119 */
120 static constexpr unsigned long kDefaultRounds = 5000;
121 /**
122 * minimum rounds.
123 */
124 static constexpr unsigned long kMinRounds = 1000;
125 /**
126 * maximum rounds.
127 */
128 static constexpr unsigned long kMaxRounds = 999999999;
129 /**
130 * maximum length of the salt.
131 *
132 * only the first kMaxSaltLength bytes of the salt will be used.
133 */
134 static constexpr size_t kMaxSaltLength = 16;
135
136 ShaCryptMcfAdaptor(Type digest, unsigned long rounds, const std::string &salt,
137 const std::string &checksum)
138 : digest_{digest}, rounds_{rounds}, salt_{salt}, checksum_{checksum} {
139 // limit salt, for caching_sha2_password salt has a fixed length of 20
140 if (digest != Type::CachingSha2Password && salt_.size() > kMaxSaltLength) {
141 salt_.resize(kMaxSaltLength);
142 }
143
144 // limit rounds to allowed range
145 if (rounds_ < kMinRounds) rounds_ = kMinRounds;
146 if (rounds_ > kMaxRounds) rounds_ = kMaxRounds;
147 }
148
149 /**
150 * name of the digest according to MCF.
151 *
152 * - 5 for SHA256
153 * - 6 for SHA512
154 * - A for caching_sha2_password
155 */
156 std::string mcf_digest_name() const {
157 auto r = mcf_type::name(digest());
158 if (r.first) return r.second;
159
160 throw std::invalid_argument("failed to map digest to a name");
161 }
162
163 /**
164 * checksum.
165 *
166 * in crypt-specific base64 encoding
167 */
168 std::string checksum() const { return checksum_; }
169
170 /**
171 * salt.
172 *
173 * @pre must be [a-z0-9]*
174 */
175 std::string salt() const { return salt_; }
176
177 /**
178 *
179 */
180 Type digest() const { return digest_; }
181
182 /**
183 * rounds.
184 *
185 * number of rounds the hash will be applied
186 */
187 unsigned long rounds() const { return rounds_; }
188
189 /**
190 * build ShaCrypt from a MCF notation.
191 *
192 * - ${prefix}$rounds={rounds}${salt}${checksum}
193 * - ${prefix}$rounds={rounds}${salt}
194 * - ${prefix}${salt}${checksum}
195 * - ${prefix}${salt}
196 *
197 * prefix
198 * : [56] (5 is SHA256, 6 is SHA512)
199 *
200 * rounds
201 * : [0-9]+
202 *
203 * salt
204 * : [^$]*
205 *
206 * checksum
207 * : [./a-zA-Z0-0]*
208 */
209 static ShaCryptMcfAdaptor from_mcf(const std::string &data);
210
211 /**
212 * encode to MCF.
213 *
214 * MCF (Modular Crypt Format)
215 */
216 std::string to_mcf() const;
217
218 /**
219 * hash a password into checksum.
220 *
221 * updates checksum
222 */
223 void hash(const std::string &password) {
224 checksum_ = kdf_type::derive(digest_, rounds_, salt_, password);
225 }
226
227 static bool supports_mcf_id(const std::string mcf_id) {
228 return mcf_type::supports_name(mcf_id);
229 }
230
231 static std::error_code validate(const std::string &mcf_line,
232 const std::string &password) {
233 try {
234 auto me = from_mcf(mcf_line);
235 if (kdf_type::derive(me.digest(), me.rounds(), me.salt(), password) ==
236 me.checksum()) {
237 return {};
238 } else {
240 }
241 } catch (const std::exception &) {
242 // treat all exceptions as parse-errors
244 }
245 }
246
247 private:
249 unsigned long rounds_;
250 std::string salt_;
251 std::string checksum_;
252};
253
255 public:
256 static ShaCryptMcfAdaptor from_mcf(const std::string &crypt_data);
257
258 static constexpr unsigned long kCachingSha2SaltLength = 20;
259};
260
261#endif
Definition: kdf_sha_crypt.h:254
static constexpr unsigned long kCachingSha2SaltLength
Definition: kdf_sha_crypt.h:258
static ShaCryptMcfAdaptor from_mcf(const std::string &crypt_data)
Definition: kdf_sha_crypt.cc:125
Definition: authentication.h:43
MCF reader/writer for ShaCrypt.
Definition: kdf_sha_crypt.h:110
static std::error_code validate(const std::string &mcf_line, const std::string &password)
Definition: kdf_sha_crypt.h:231
static bool supports_mcf_id(const std::string mcf_id)
Definition: kdf_sha_crypt.h:227
unsigned long rounds_
Definition: kdf_sha_crypt.h:249
std::string checksum_
Definition: kdf_sha_crypt.h:251
std::string mcf_digest_name() const
name of the digest according to MCF.
Definition: kdf_sha_crypt.h:156
void hash(const std::string &password)
hash a password into checksum.
Definition: kdf_sha_crypt.h:223
std::string salt() const
salt.
Definition: kdf_sha_crypt.h:175
ShaCryptMcfAdaptor(Type digest, unsigned long rounds, const std::string &salt, const std::string &checksum)
Definition: kdf_sha_crypt.h:136
unsigned long rounds() const
rounds.
Definition: kdf_sha_crypt.h:187
Type digest() const
Definition: kdf_sha_crypt.h:180
Type digest_
Definition: kdf_sha_crypt.h:248
std::string salt_
Definition: kdf_sha_crypt.h:250
std::string checksum() const
checksum.
Definition: kdf_sha_crypt.h:168
Definition: kdf_sha_crypt.h:60
static bool supports_name(const std::string &name) noexcept
Definition: kdf_sha_crypt.h:89
static constexpr char kTypeSha512[]
Definition: kdf_sha_crypt.h:103
static constexpr char kTypeSha256[]
Definition: kdf_sha_crypt.h:102
static std::pair< bool, Type > type(const std::string &name) noexcept
Definition: kdf_sha_crypt.h:77
static std::pair< bool, std::string > name(Type type) noexcept
Definition: kdf_sha_crypt.h:64
static constexpr char kTypeCachingSha2Password[]
Definition: kdf_sha_crypt.h:104
sha256_crypt and sha512_crypt are SHA based crypt() key derivation functions.
Definition: kdf_sha_crypt.h:43
Type
Definition: kdf_sha_crypt.h:45
#define HTTP_AUTH_BACKEND_LIB_EXPORT
Definition: http_auth_backend_lib_export.h:15
static int base64_encode(const void *src, size_t src_len, char *dst)
Definition: base64.h:243
@ kPasswordNotMatched
static char * password
Definition: mysql_secure_installation.cc:58
std::error_code make_error_code(DynamicLoaderErrc ec)
make error_code from a DynamicLoaderErrc.
Definition: dynamic_loader.cc:79
Type
Definition: resource_group_basic_types.h:33
const mysql_service_registry_t * r
Definition: pfs_example_plugin_employee.cc:86
case opt name
Definition: sslopt-case.h:29
Constants and functionality that facilitate working with digests.