]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_pbkdf2.cpp
Fix various cases of broken indentation.
[user/henk/code/inspircd.git] / src / modules / m_pbkdf2.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2014 Daniel Vassdal <shutter@canternet.org>
5  *
6  * This file is part of InspIRCd.  InspIRCd is free software: you can
7  * redistribute it and/or modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation, version 2.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
13  * details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #include "inspircd.h"
21 #include "modules/hash.h"
22
23 // Format:
24 // Iterations:B64(Hash):B64(Salt)
25 // E.g.
26 // 10200:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
27 class PBKDF2Hash
28 {
29  public:
30         unsigned int iterations;
31         unsigned int length;
32         std::string salt;
33         std::string hash;
34
35         PBKDF2Hash(unsigned int itr, unsigned int dkl, const std::string& slt, const std::string& hsh = "")
36                 : iterations(itr), length(dkl), salt(slt), hash(hsh)
37         {
38         }
39
40         PBKDF2Hash(const std::string& data)
41         {
42                 irc::sepstream ss(data, ':');
43                 std::string tok;
44
45                 ss.GetToken(tok);
46                 this->iterations = ConvToNum<unsigned int>(tok);
47
48                 ss.GetToken(tok);
49                 this->hash = Base64ToBin(tok);
50
51                 ss.GetToken(tok);
52                 this->salt = Base64ToBin(tok);
53
54                 this->length = this->hash.length();
55         }
56
57         std::string ToString()
58         {
59                 if (!IsValid())
60                         return "";
61                 return ConvToStr(this->iterations) + ":" + BinToBase64(this->hash) + ":" + BinToBase64(this->salt);
62         }
63
64         bool IsValid()
65         {
66                 if (!this->iterations || !this->length || this->salt.empty() || this->hash.empty())
67                         return false;
68                 return true;
69         }
70 };
71
72 class PBKDF2Provider : public HashProvider
73 {
74  public:
75         HashProvider* provider;
76         unsigned int iterations;
77         unsigned int dkey_length;
78
79         std::string PBKDF2(const std::string& pass, const std::string& salt, unsigned int itr = 0, unsigned int dkl = 0)
80         {
81                 size_t blocks = std::ceil((double)dkl / provider->out_size);
82
83                 std::string output;
84                 std::string tmphash;
85                 std::string salt_block = salt;
86                 for (size_t block = 1; block <= blocks; block++)
87                 {
88                         char salt_data[4];
89                         for (size_t i = 0; i < sizeof(salt_data); i++)
90                                 salt_data[i] = block >> (24 - i * 8) & 0x0F;
91
92                         salt_block.erase(salt.length());
93                         salt_block.append(salt_data, sizeof(salt_data));
94
95                         std::string blockdata = provider->hmac(pass, salt_block);
96                         std::string lasthash = blockdata;
97                         for (size_t iter = 1; iter < itr; iter++)
98                         {
99                                 tmphash = provider->hmac(pass, lasthash);
100                                 for (size_t i = 0; i < provider->out_size; i++)
101                                         blockdata[i] ^= tmphash[i];
102
103                                 lasthash.swap(tmphash);
104                         }
105                         output += blockdata;
106                 }
107
108                 output.erase(dkl);
109                 return output;
110         }
111
112         std::string GenerateRaw(const std::string& data) CXX11_OVERRIDE
113         {
114                 PBKDF2Hash hs(this->iterations, this->dkey_length, ServerInstance->GenRandomStr(dkey_length, false));
115                 hs.hash = PBKDF2(data, hs.salt, this->iterations, this->dkey_length);
116                 return hs.ToString();
117         }
118
119         bool Compare(const std::string& input, const std::string& hash) CXX11_OVERRIDE
120         {
121                 PBKDF2Hash hs(hash);
122                 if (!hs.IsValid())
123                         return false;
124
125                 std::string cmp = PBKDF2(input, hs.salt, hs.iterations, hs.length);
126                 return (cmp == hs.hash);
127         }
128
129         std::string ToPrintable(const std::string& raw) CXX11_OVERRIDE
130         {
131                 return raw;
132         }
133
134         PBKDF2Provider(Module* mod, HashProvider* hp)
135                 : HashProvider(mod, "pbkdf2-hmac-" + hp->name.substr(hp->name.find('/') + 1))
136                 , provider(hp)
137         {
138                 DisableAutoRegister();
139         }
140 };
141
142 struct ProviderConfig
143 {
144         unsigned long dkey_length;
145         unsigned long iterations;
146 };
147
148 typedef std::map<std::string, ProviderConfig> ProviderConfigMap;
149
150 class ModulePBKDF2 : public Module
151 {
152         std::vector<PBKDF2Provider*> providers;
153         ProviderConfig globalconfig;
154         ProviderConfigMap providerconfigs;
155
156         ProviderConfig GetConfigForProvider(const std::string& name) const
157         {
158                 ProviderConfigMap::const_iterator it = providerconfigs.find(name);
159                 if (it == providerconfigs.end())
160                         return globalconfig;
161
162                 return it->second;
163         }
164
165         void ConfigureProviders()
166         {
167                 for (std::vector<PBKDF2Provider*>::iterator i = providers.begin(); i != providers.end(); ++i)
168                 {
169                         PBKDF2Provider* pi = *i;
170                         ProviderConfig config = GetConfigForProvider(pi->name);
171                         pi->iterations = config.iterations;
172                         pi->dkey_length = config.dkey_length;
173                 }
174         }
175
176         void GetConfig()
177         {
178                 // First set the common values
179                 ConfigTag* tag = ServerInstance->Config->ConfValue("pbkdf2");
180                 ProviderConfig newglobal;
181                 newglobal.iterations = tag->getUInt("iterations", 12288, 1);
182                 newglobal.dkey_length = tag->getUInt("length", 32, 1, 1024);
183
184                 // Then the specific values
185                 ProviderConfigMap newconfigs;
186                 ConfigTagList tags = ServerInstance->Config->ConfTags("pbkdf2prov");
187                 for (ConfigIter i = tags.first; i != tags.second; ++i)
188                 {
189                         tag = i->second;
190                         std::string hash_name = "hash/" + tag->getString("hash");
191                         ProviderConfig& config = newconfigs[hash_name];
192
193                         config.iterations = tag->getUInt("iterations", newglobal.iterations, 1);
194                         config.dkey_length = tag->getUInt("length", newglobal.dkey_length, 1, 1024);
195                 }
196
197                 // Config is valid, apply it
198                 providerconfigs.swap(newconfigs);
199                 std::swap(globalconfig, newglobal);
200                 ConfigureProviders();
201         }
202
203  public:
204         ~ModulePBKDF2()
205         {
206                 stdalgo::delete_all(providers);
207         }
208
209         void OnServiceAdd(ServiceProvider& provider) CXX11_OVERRIDE
210         {
211                 // Check if it's a hash provider
212                 if (provider.name.compare(0, 5, "hash/"))
213                         return;
214
215                 HashProvider* hp = static_cast<HashProvider*>(&provider);
216                 if (hp->IsKDF())
217                         return;
218
219                 PBKDF2Provider* prov = new PBKDF2Provider(this, hp);
220                 providers.push_back(prov);
221                 ServerInstance->Modules.AddService(*prov);
222
223                 ConfigureProviders();
224         }
225
226         void OnServiceDel(ServiceProvider& prov) CXX11_OVERRIDE
227         {
228                 for (std::vector<PBKDF2Provider*>::iterator i = providers.begin(); i != providers.end(); ++i)
229                 {
230                         PBKDF2Provider* item = *i;
231                         if (item->provider != &prov)
232                                 continue;
233
234                         ServerInstance->Modules->DelService(*item);
235                         delete item;
236                         providers.erase(i);
237                         break;
238                 }
239         }
240
241         void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
242         {
243                 GetConfig();
244         }
245
246         Version GetVersion() CXX11_OVERRIDE
247         {
248                 return Version("Implements PBKDF2 hashing", VF_VENDOR);
249         }
250 };
251
252 MODULE_INIT(ModulePBKDF2)