]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_password_hash.cpp
Add Base64 encode/decode functions to the core
[user/henk/code/inspircd.git] / src / modules / m_password_hash.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $ModDesc: Allows for hashed oper passwords */
15
16 #include "inspircd.h"
17 #include "m_hash.h"
18
19 static std::string hmac(HashProvider* hp, const std::string& key, const std::string& msg)
20 {
21         std::string hmac1, hmac2;
22         for (size_t n = 0; n < key.length(); n++)
23         {
24                 hmac1.push_back(static_cast<char>(key[n] ^ 0x5C));
25                 hmac2.push_back(static_cast<char>(key[n] ^ 0x36));
26         }
27         hmac2.append(msg);
28         hmac1.append(hp->sum(hmac2));
29         return hp->sum(hmac1);
30 }
31
32 /* Handle /MKPASSWD
33  */
34 class CommandMkpasswd : public Command
35 {
36  public:
37         CommandMkpasswd(Module* Creator) : Command(Creator, "MKPASSWD", 2)
38         {
39                 syntax = "<hashtype> <any-text>";
40                 Penalty = 5;
41         }
42
43         void MakeHash(User* user, const std::string& algo, const std::string& stuff)
44         {
45                 if (algo.substr(0,5) == "hmac-")
46                 {
47                         std::string type = algo.substr(5);
48                         HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + type);
49                         if (!hp)
50                         {
51                                 user->WriteServ("NOTICE %s :Unknown hash type", user->nick.c_str());
52                                 return;
53                         }
54                         std::string salt = GenRandomStr(6, false);
55                         std::string target = hmac(hp, salt, stuff);
56                         std::string str = BinToBase64(salt) + "$" + BinToBase64(target, NULL, 0);
57
58                         user->WriteServ("NOTICE %s :%s hashed password for %s is %s",
59                                 user->nick.c_str(), algo.c_str(), stuff.c_str(), str.c_str());
60                 }
61                 HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + algo);
62                 if (hp)
63                 {
64                         /* Now attempt to generate a hash */
65                         user->WriteServ("NOTICE %s :%s hashed password for %s is %s",
66                                 user->nick.c_str(), algo.c_str(), stuff.c_str(), hp->hexsum(stuff).c_str());
67                 }
68                 else
69                 {
70                         user->WriteServ("NOTICE %s :Unknown hash type", user->nick.c_str());
71                 }
72         }
73
74         CmdResult Handle (const std::vector<std::string>& parameters, User *user)
75         {
76                 MakeHash(user, parameters[0], parameters[1]);
77
78                 return CMD_SUCCESS;
79         }
80 };
81
82 class ModuleOperHash : public Module
83 {
84         CommandMkpasswd cmd;
85  public:
86
87         ModuleOperHash() : cmd(this)
88         {
89                 /* Read the config file first */
90                 OnRehash(NULL);
91
92                 ServerInstance->AddCommand(&cmd);
93                 Implementation eventlist[] = { I_OnPassCompare };
94                 ServerInstance->Modules->Attach(eventlist, this, 1);
95         }
96
97         virtual ModResult OnPassCompare(Extensible* ex, const std::string &data, const std::string &input, const std::string &hashtype)
98         {
99                 if (hashtype.substr(0,5) == "hmac-")
100                 {
101                         std::string type = hashtype.substr(5);
102                         HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + type);
103                         if (!hp)
104                                 return MOD_RES_PASSTHRU;
105                         // this is a valid hash, from here on we either accept or deny
106                         std::string::size_type sep = data.find('$');
107                         if (sep == std::string::npos)
108                                 return MOD_RES_DENY;
109                         std::string salt = Base64ToBin(data.substr(0, sep));
110                         std::string target = Base64ToBin(data.substr(sep + 1));
111
112                         std::string hmac1, hmac2;
113                         for (size_t n = 0; n < salt.length(); n++)
114                         {
115                                 hmac1.push_back(static_cast<char>(salt[n] ^ 0x5C));
116                                 hmac2.push_back(static_cast<char>(salt[n] ^ 0x36));
117                         }
118                         hmac2.append(input);
119                         hmac1.append(hp->sum(hmac2));
120                         if (target == hp->sum(hmac1))
121                                 return MOD_RES_ALLOW;
122                         else
123                                 return MOD_RES_DENY;
124                 }
125
126                 HashProvider* hp = ServerInstance->Modules->FindDataService<HashProvider>("hash/" + hashtype);
127
128                 /* Is this a valid hash name? */
129                 if (hp)
130                 {
131                         /* Compare the hash in the config to the generated hash */
132                         if (data == hp->hexsum(input))
133                                 return MOD_RES_ALLOW;
134                         else
135                                 /* No match, and must be hashed, forbid */
136                                 return MOD_RES_DENY;
137                 }
138
139                 /* Not a hash, fall through to strcmp in core */
140                 return MOD_RES_PASSTHRU;
141         }
142
143         virtual Version GetVersion()
144         {
145                 return Version("Allows for hashed oper passwords",VF_VENDOR);
146         }
147 };
148
149 MODULE_INIT(ModuleOperHash)