]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_argon2.cpp
Implement support for setting TLSv1.3 ciphersuites in ssl_openssl.
[user/henk/code/inspircd.git] / src / modules / extra / m_argon2.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2020 Elizabeth Myers <elizabeth@interlinked.me>
5  *   Copyright (C) 2020 Daniel Vassdal <shutter@canternet.org>
6  *
7  * This file is part of InspIRCd.  InspIRCd is free software: you can
8  * redistribute it and/or modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation, version 2.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /// $CompilerFlags: find_compiler_flags("libargon2" "")
21
22 /// $LinkerFlags: find_linker_flags("libargon2" "-largon2")
23
24 /// $PackageInfo: require_system("arch") argon2 pkgconf
25 /// $PackageInfo: require_system("darwin") argon2 pkg-config
26 /// $PackageInfo: require_system("debian" "9.0") libargon2-0 pkg-config
27 /// $PackageInfo: require_system("ubuntu" "18.04") libargon2-0-dev pkg-config
28
29
30 #include "inspircd.h"
31 #include "modules/hash.h"
32
33 #ifdef __GNUC__
34 # pragma GCC diagnostic push
35 #endif
36
37 // Fix warnings about the use of `long long` on C++03
38 #if defined __clang__
39 # pragma clang diagnostic ignored "-Wc++11-long-long"
40 #elif defined __GNUC__
41 # pragma GCC diagnostic ignored "-Wlong-long"
42 #endif
43
44 #include <argon2.h>
45
46 class ProviderConfig
47 {
48  private:
49         static Argon2_version SanitizeArgon2Version(unsigned long version)
50         {
51                 // Note, 10 is 0x10, and 13 is 0x13. Referring to it as
52                 // dec 10 or 13 in the config file, for the name to
53                 // match better.
54                 switch (version)
55                 {
56                         case 10:
57                                 return ARGON2_VERSION_10;
58                         case 13:
59                                 return ARGON2_VERSION_13;
60                 }
61
62                 ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Unknown Argon2 version (%lu) specified; assuming 13",
63                         version);
64                 return ARGON2_VERSION_13;
65         }
66
67  public:
68         uint32_t iterations;
69         uint32_t lanes;
70         uint32_t memory;
71         uint32_t outlen;
72         uint32_t saltlen;
73         uint32_t threads;
74         Argon2_version version;
75
76         ProviderConfig()
77         {
78                 // Nothing interesting happens here.
79         }
80
81         ProviderConfig(const std::string& tagname, ProviderConfig* def)
82         {
83                 ConfigTag* tag = ServerInstance->Config->ConfValue(tagname);
84
85                 uint32_t def_iterations = def ? def->iterations : 3;
86                 this->iterations = tag->getUInt("iterations", def_iterations, 1);
87
88                 uint32_t def_lanes = def ? def->lanes : 1;
89                 this->lanes = tag->getUInt("lanes", def_lanes, ARGON2_MIN_LANES, ARGON2_MAX_LANES);
90
91                 uint32_t def_memory = def ? def->memory : 131072; // 128 MiB
92                 this->memory = tag->getUInt("memory", def_memory, ARGON2_MIN_MEMORY, ARGON2_MAX_MEMORY);
93
94                 uint32_t def_outlen = def ? def->outlen : 32;
95                 this->outlen = tag->getUInt("length", def_outlen, ARGON2_MIN_OUTLEN, ARGON2_MAX_OUTLEN);
96
97                 uint32_t def_saltlen = def ? def->saltlen : 16;
98                 this->saltlen = tag->getUInt("saltlength", def_saltlen, ARGON2_MIN_SALT_LENGTH, ARGON2_MAX_SALT_LENGTH);
99
100                 uint32_t def_threads = def ? def->threads : 1;
101                 this->threads = tag->getUInt("threads", def_threads, ARGON2_MIN_THREADS, ARGON2_MAX_THREADS);
102
103                 uint32_t def_version = def ? def->version : 13;
104                 this->version = SanitizeArgon2Version(tag->getUInt("version", def_version));
105         }
106 };
107
108 class HashArgon2 : public HashProvider
109 {
110  private:
111         const Argon2_type argon2Type;
112
113  public:
114         ProviderConfig config;
115
116         bool Compare(const std::string& input, const std::string& hash) CXX11_OVERRIDE
117         {
118                 int result = argon2_verify(
119                         hash.c_str(),
120                         input.c_str(),
121                         input.length(),
122                         argon2Type);
123
124                 return result == ARGON2_OK;
125         }
126
127         std::string GenerateRaw(const std::string& data) CXX11_OVERRIDE
128         {
129                 const std::string salt = ServerInstance->GenRandomStr(config.saltlen, false);
130
131                 size_t encodedLen = argon2_encodedlen(
132                         config.iterations,
133                         config.memory,
134                         config.lanes,
135                         config.saltlen,
136                         config.outlen,
137                         argon2Type);
138
139                 std::vector<char> raw_data(config.outlen);
140                 std::vector<char> encoded_data(encodedLen + 1);
141
142                 int argonResult = argon2_hash(
143                         config.iterations,
144                         config.memory,
145                         config.threads,
146                         data.c_str(),
147                         data.length(),
148                         salt.c_str(),
149                         salt.length(),
150                         &raw_data[0],
151                         raw_data.size(),
152                         &encoded_data[0],
153                         encoded_data.size(),
154                         argon2Type,
155                         config.version);
156
157                 if (argonResult != ARGON2_OK)
158                         throw ModuleException("Argon2 hashing failed!: " + std::string(argon2_error_message(argonResult)));
159
160                 // This isn't the raw version, but we don't have
161                 // the facilities to juggle around the extra state required
162                 // to do anything useful with them if we don't encode them.
163                 // So we pretend this is the raw version, and instead make
164                 // ToPrintable return its input.
165                 return std::string(&encoded_data[0], encoded_data.size());
166         }
167
168         std::string ToPrintable(const std::string& raw) CXX11_OVERRIDE
169         {
170                 return raw;
171         }
172
173         HashArgon2(Module* parent, const std::string& hashName, Argon2_type type)
174                 : HashProvider(parent, hashName)
175                 , argon2Type(type)
176
177         {
178         }
179 };
180
181 class ModuleArgon2 : public Module
182 {
183  private:
184         HashArgon2 argon2i;
185         HashArgon2 argon2d;
186         HashArgon2 argon2id;
187
188  public:
189         ModuleArgon2()
190                 : argon2i(this, "argon2i", Argon2_i)
191                 , argon2d(this, "argon2d", Argon2_d)
192                 , argon2id(this, "argon2id", Argon2_id)
193         {
194         }
195
196         Version GetVersion() CXX11_OVERRIDE
197         {
198                 return Version("Allows other modules to generate Argon2 hashes.", VF_VENDOR);
199         }
200
201         void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
202         {
203                 ProviderConfig defaultConfig("argon2", NULL);
204                 argon2i.config = ProviderConfig("argon2i", &defaultConfig);
205                 argon2d.config = ProviderConfig("argon2d", &defaultConfig);
206                 argon2id.config = ProviderConfig("argon2id", &defaultConfig);
207         }
208 };
209
210 MODULE_INIT(ModuleArgon2)
211
212 // This needs to be down here because of warnings from macros.
213 #ifdef __GNUC__
214 # pragma GCC diagnostic pop
215 #endif