diff options
author | Adam <Adam@anope.org> | 2012-11-30 02:49:09 -0500 |
---|---|---|
committer | Adam <Adam@anope.org> | 2012-11-30 02:53:03 -0500 |
commit | a4468dd56e96ea915d40627f3cb067084238e34a (patch) | |
tree | a8a497965346e55eeb79fc56797da6bea81bf841 | |
parent | 337f3615264f30d4c9f06653d2dd2a21805546ce (diff) |
Allow modules to use the encryption modules to encrypt arbitrary things.
Made enc_old depend on enc_md5.
Allow not loading any encryption modules if you want to only use an
external mechanism.
Removed ns_sendpass since it's just a bad idea.
-rw-r--r-- | data/example.conf | 29 | ||||
-rw-r--r-- | data/nickserv.example.conf | 12 | ||||
-rw-r--r-- | include/anope.h | 3 | ||||
-rw-r--r-- | modules/commands/ns_sendpass.cpp | 104 | ||||
-rw-r--r-- | modules/encryption/enc_md5.cpp | 454 | ||||
-rw-r--r-- | modules/encryption/enc_old.cpp | 347 | ||||
-rw-r--r-- | modules/encryption/enc_sha1.cpp | 282 | ||||
-rw-r--r-- | modules/encryption/enc_sha256.cpp | 248 | ||||
-rw-r--r-- | modules/encryption/encryption.h | 37 | ||||
-rw-r--r-- | modules/protocol/inspircd11.cpp | 2 | ||||
-rw-r--r-- | modules/protocol/inspircd12.cpp | 2 | ||||
-rw-r--r-- | src/encrypt.cpp | 50 | ||||
-rw-r--r-- | src/init.cpp | 2 | ||||
-rw-r--r-- | src/messages.cpp | 4 | ||||
-rw-r--r-- | src/misc.cpp | 24 |
15 files changed, 661 insertions, 939 deletions
diff --git a/data/example.conf b/data/example.conf index 7bf1ea6ec..d1fc98087 100644 --- a/data/example.conf +++ b/data/example.conf @@ -1174,18 +1174,26 @@ db_sql } /* - * [REQUIRED] Encryption modules. + * [RECOMMENDED] Encryption modules. * * The encryption modules are used when dealing with passwords. This determines how * the passwords are stored in the databases, and does not add any security as * far as transmitting passwords over the network goes. * - * Without any encryption modules, passwords will be stored in plain text, allowing + * Without any encryption modules loaded users will not be able to authenticate unless + * there is another module loaded that provides authentication checking, such as + * m_ldap_authentication or m_sql_authentication. + * + * With enc_none, passwords will be stored in plain text, allowing * for passwords to be recovered later but isn't secure therefore is not recommended. * * The other encryption modules use one-way encryption, so the passwords can not * be recovered later if those are used. * + * The first encryption module loaded is the primary encryption module. All new passwords are + * encrypted by this module. Old passwords stored in another encryption method are + * automatically re-encrypted by the primary encryption module on next identify. + * * NOTE: enc_old is Anope's previous (broken) MD5 implementation, if your databases * were made using that module, continue to use it and do not use enc_md5. * @@ -1196,24 +1204,21 @@ db_sql * that you first try to get everyone's passwords converted to enc_sha256 before * switching OSes by placing enc_sha256 at the beginning of the list. * - * The first encryption module loaded is the primary encryption module. All new passwords are - * encrypted by this module. Old passwords stored in another encryption method are - * automatically re-encrypted by the primary encryption module on next identify. */ -module { name = "enc_md5" } + +module { name = "enc_sha256" } +#module { name = "enc_md5" } #module { name = "enc_sha1" } -#module { name = "enc_sha256" } /* - * When using enc_none, passwords will be stored without encryption in plain - * text, allowing for passwords to be recovered later. This isn't secure therefore - * is not recommended. + * When using enc_none, passwords will be stored without encryption. This isn't secure + * therefore it is not recommended. */ #module { name = "enc_none" } /* - * enc_old is Anope's previous (broken) MD5 implementation, if your databases - * were made using that module, load it here to allow conversion to the primary + * enc_old is Anope's previous (broken) MD5 implementation used from 1.4.x to 1.7.16. + * If your databases were made using that module, load it here to allow conversion to the primary * encryption method. */ #module { name = "enc_old" } diff --git a/data/nickserv.example.conf b/data/nickserv.example.conf index 5c8b3f82e..fd624d24a 100644 --- a/data/nickserv.example.conf +++ b/data/nickserv.example.conf @@ -604,18 +604,6 @@ command { service = "NickServ"; name = "SET SECURE"; command = "nickserv/set/sec command { service = "NickServ"; name = "SASET SECURE"; command = "nickserv/saset/secure"; permission = "nickserv/saset/secure"; } /* - * ns_sendpass - * - * Provides the command nickserv/sendpass. - * - * Used to send users their password via email. - * - * Requires that no encryption is being used. - */ -module { name = "ns_sendpass" } -command { service = "NickServ"; name = "SENDPASS"; command = "nickserv/sendpass"; permission = "nickserv/sendpass"; } - -/* * ns_set_misc * * Provides the command nickserv/set/misc. diff --git a/include/anope.h b/include/anope.h index 0ba950d9b..15944e165 100644 --- a/include/anope.h +++ b/include/anope.h @@ -138,6 +138,9 @@ namespace Anope */ inline void push_back(char c) { return this->_string.push_back(c); } + inline string& append(const string &s) { this->_string.append(s.str()); return *this; } + inline string& append(const char *s, size_t n) { this->_string.append(s, n); return *this; } + /** * Resizes the string content to n characters. */ diff --git a/modules/commands/ns_sendpass.cpp b/modules/commands/ns_sendpass.cpp deleted file mode 100644 index e85690e24..000000000 --- a/modules/commands/ns_sendpass.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* NickServ core functions - * - * (C) 2003-2012 Anope Team - * Contact us at team@anope.org - * - * Please read COPYING and README for further details. - * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. - */ - -/*************************************************************************/ - -#include "module.h" - -static bool SendPassMail(User *u, const NickAlias *na, const BotInfo *bi, const Anope::string &pass); - -class CommandNSSendPass : public Command -{ - public: - CommandNSSendPass(Module *creator) : Command(creator, "nickserv/sendpass", 1, 1) - { - this->SetFlag(CFLAG_ALLOW_UNREGISTERED); - this->SetDesc(_("Forgot your password? Try this")); - this->SetSyntax(_("\037nickname\037")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - const Anope::string &nick = params[0]; - const NickAlias *na; - - if (Config->RestrictMail && !source.HasCommand("nickserv/sendpass")) - source.Reply(ACCESS_DENIED); - else if (!(na = NickAlias::Find(nick))) - source.Reply(NICK_X_NOT_REGISTERED, nick.c_str()); - else - { - Anope::string tmp_pass; - if (Anope::Decrypt(na->nc->pass, tmp_pass) == 1) - { - if (SendPassMail(source.GetUser(), na, source.service, tmp_pass)) - { - Log(Config->RestrictMail ? LOG_ADMIN : LOG_COMMAND, source, this) << "for " << na->nick; - source.Reply(_("Password of \002%s\002 has been sent."), nick.c_str()); - } - } - else - source.Reply(_("%s command unavailable because encryption is in use."), source.command.c_str()); - } - - return; - } - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Send the password of the given nickname to the e-mail address\n" - "set in the nickname record. This command is really useful\n" - "to deal with lost passwords.\n" - " \n" - "May be limited to \002IRC operators\002 on certain networks.")); - return true; - } -}; - -class NSSendPass : public Module -{ - CommandNSSendPass commandnssendpass; - - public: - NSSendPass(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), - commandnssendpass(this) - { - this->SetAuthor("Anope"); - - if (!Config->UseMail) - throw ModuleException("Not using mail."); - - Anope::string tmp_pass = "plain:tmp"; - if (Anope::Decrypt(tmp_pass, tmp_pass) == -1) - throw ModuleException("Incompatible with the encryption module being used"); - - } -}; - -static bool SendPassMail(User *u, const NickAlias *na, const BotInfo *bi, const Anope::string &pass) -{ - Anope::string subject = Language::Translate(na->nc, Config->MailSendpassSubject.c_str()); - Anope::string message = Language::Translate(na->nc, Config->MailSendpassMessage.c_str()); - - subject = subject.replace_all_cs("%n", na->nick); - subject = subject.replace_all_cs("%N", Config->NetworkName); - subject = subject.replace_all_cs("%p", pass); - - message = message.replace_all_cs("%n", na->nick); - message = message.replace_all_cs("%N", Config->NetworkName); - message = message.replace_all_cs("%p", pass); - - return Mail::Send(u, na->nc, bi, subject, message); -} - -MODULE_INIT(NSSendPass) diff --git a/modules/encryption/enc_md5.cpp b/modules/encryption/enc_md5.cpp index 45c7f3df5..ed7cce144 100644 --- a/modules/encryption/enc_md5.cpp +++ b/modules/encryption/enc_md5.cpp @@ -12,6 +12,7 @@ */ #include "module.h" +#include "encryption.h" /*************************************************************************/ @@ -37,43 +38,6 @@ These notices must be retained in any copies of any part of this documentation and/or software. */ -/* MD5 context. */ -struct MD5_CTX -{ - unsigned state[4]; /* state (ABCD) */ - unsigned count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -}; - -/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm - */ - -/* Constants for MD5Transform routine. - */ -enum -{ - S11 = 7, - S12 = 12, - S13 = 17, - S14 = 22, - S21 = 5, - S22 = 9, - S23 = 14, - S24 = 20, - S31 = 4, - S32 = 11, - S33 = 16, - S34 = 23, - S41 = 6, - S42 = 10, - S43 = 15, - S44 = 21 -}; - -void MD5Transform(unsigned [4], const unsigned char [64]); -void Encode(unsigned char *, unsigned *, unsigned); -void Decode(unsigned *, const unsigned char *, unsigned); - static unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -119,203 +83,269 @@ inline static void II(unsigned &a, unsigned b, unsigned c, unsigned d, unsigned a += b; } -/* MD5 initialization. Begins an MD5 operation, writing a new context. - */ -void MD5Init(MD5_CTX *context) +static const uint32_t md5_iv[4] = { - context->count[0] = context->count[1] = 0; - /* Load magic initialization constants. */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; -} + 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 +}; -/* MD5 block update operation. Continues an MD5 message-digest - * operation, processing another message block, and updating the - * context. - */ -void MD5Update(MD5_CTX *context, const unsigned char *input, unsigned inputLen) +class MD5Context : public Encryption::Context { - unsigned i, index, partLen; - - /* Compute number of bytes mod 64 */ - index = (context->count[0] >> 3) & 0x3F; + unsigned state[4]; /* state (ABCD) */ + unsigned count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ + unsigned char digest[16]; /* final digest */ - /* Update number of bits */ - if ((context->count[0] += inputLen << 3) < (inputLen << 3)) - ++context->count[1]; - context->count[1] += inputLen >> 29; + /* Constants for MD5Transform routine. + */ + enum + { + S11 = 7, + S12 = 12, + S13 = 17, + S14 = 22, + S21 = 5, + S22 = 9, + S23 = 14, + S24 = 20, + S31 = 4, + S32 = 11, + S33 = 16, + S34 = 23, + S41 = 6, + S42 = 10, + S43 = 15, + S44 = 21 + }; + + /* MD5 basic transformation. Transforms state based on block. + */ + void Transform(const unsigned char block[64]) + { + unsigned a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode(x, block, 64); + + /* Round 1 */ + FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ + FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ + FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ + FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ + FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ + FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ + FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ + FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ + FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ + FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ + FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ + GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ + GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ + GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ + GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ + GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ + GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ + GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ + GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ + GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ + GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ + HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ + HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ + HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ + HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ + HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ + HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ + HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ + HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ + HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ + II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ + II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ + II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ + II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ + II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ + II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ + II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ + II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ + II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset(x, 0, sizeof(x)); + } - partLen = 64 - index; + /* Encodes input (unsigned) into output (unsigned char). Assumes len is + * a multiple of 4. + */ + void Encode(unsigned char *output, unsigned *input, unsigned len) + { + for (unsigned i = 0, j = 0; j < len; ++i, j += 4) + { + output[j] = static_cast<unsigned char>(input[i] & 0xff); + output[j + 1] = static_cast<unsigned char>((input[i] >> 8) & 0xff); + output[j + 2] = static_cast<unsigned char>((input[i] >> 16) & 0xff); + output[j + 3] = static_cast<unsigned char>((input[i] >> 24) & 0xff); + } + } - /* Transform as many times as possible. */ - if (inputLen >= partLen) + /* Decodes input (unsigned char) into output (unsigned). Assumes len is + * a multiple of 4. + */ + void Decode(unsigned *output, const unsigned char *input, unsigned len) { - memcpy(&context->buffer[index], input, partLen); - MD5Transform(context->state, context->buffer); + for (unsigned i = 0, j = 0; j < len; ++i, j += 4) + output[i] = static_cast<unsigned>(input[j]) | (static_cast<unsigned>(input[j + 1]) << 8) | (static_cast<unsigned>(input[j + 2]) << 16) | (static_cast<unsigned>(input[j + 3]) << 24); + } - for (i = partLen; i + 63 < inputLen; i += 64) - MD5Transform(context->state, &input[i]); + public: + MD5Context(Encryption::IV *iv = NULL) + { + if (iv != NULL) + { + if (iv->second != 4) + throw CoreException("Invalid IV size"); + /* Load magic initialization constants. */ + for (int i = 0; i < 4; ++i) + this->state[i] = iv->first[i]; + } + else + for (int i = 0; i < 4; ++i) + this->state[i] = md5_iv[i]; - index = 0; + this->count[0] = this->count[1] = 0; + memset(this->buffer, 0, sizeof(this->buffer)); } - else - i = 0; - /* Buffer remaining input */ - memcpy(&context->buffer[index], &input[i], inputLen - i); -} + /* MD5 block update operation. Continues an MD5 message-digest + * operation, processing another message block, and updating the + * context. + */ + void Update(const unsigned char *input, size_t len) anope_override + { + unsigned i, index, partLen; -/* MD5 finalization. Ends an MD5 message-digest operation, writing the - * the message digest and zeroizing the context. - */ -void MD5Final(unsigned char digest[17], MD5_CTX *context) -{ - unsigned char bits[8]; - unsigned index, padLen; + /* Compute number of bytes mod 64 */ + index = (this->count[0] >> 3) & 0x3F; - /* Save number of bits */ - Encode(bits, context->count, 8); + /* Update number of bits */ + if ((this->count[0] += len << 3) < (len << 3)) + ++this->count[1]; + this->count[1] += len >> 29; - /* Pad out to 56 mod 64. */ - index = (context->count[0] >> 3) & 0x3f; - padLen = index < 56 ? 56 - index : 120 - index; - MD5Update(context, PADDING, padLen); + partLen = 64 - index; - /* Append length (before padding) */ - MD5Update(context, bits, 8); - /* Store state in digest */ - Encode(digest, context->state, 16); + /* Transform as many times as possible. */ + if (len >= partLen) + { + memcpy(&this->buffer[index], input, partLen); + this->Transform(this->buffer); - /* Zeroize sensitive information. */ - memset(context, 0, sizeof(*context)); -} + for (i = partLen; i + 63 < len; i += 64) + this->Transform(&input[i]); -/* MD5 basic transformation. Transforms state based on block. - */ -void MD5Transform(unsigned state[4], const unsigned char block[64]) -{ - unsigned a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode(x, block, 64); - - /* Round 1 */ - FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ - FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ - FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ - FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ - FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ - FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ - FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ - FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ - FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ - FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ - FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ - GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ - GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ - GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ - GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ - GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ - GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ - GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ - GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ - GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ - GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ - HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ - HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ - HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ - HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ - HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ - HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ - HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ - HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ - HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ - II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ - II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ - II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ - II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ - II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ - II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ - II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ - II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ - II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. */ - memset(x, 0, sizeof(x)); -} + index = 0; + } + else + i = 0; -/* Encodes input (unsigned) into output (unsigned char). Assumes len is - * a multiple of 4. - */ -void Encode(unsigned char *output, unsigned *input, unsigned len) -{ - unsigned i, j; + /* Buffer remaining input */ + memcpy(&this->buffer[index], &input[i], len - i); + } - for (i = 0, j = 0; j < len; ++i, j += 4) + /* MD5 finalization. Ends an MD5 message-digest opera + * the message digest and zeroizing the context. + */ + void Finalize() anope_override { - output[j] = static_cast<unsigned char>(input[i] & 0xff); - output[j + 1] = static_cast<unsigned char>((input[i] >> 8) & 0xff); - output[j + 2] = static_cast<unsigned char>((input[i] >> 16) & 0xff); - output[j + 3] = static_cast<unsigned char>((input[i] >> 24) & 0xff); + unsigned char bits[8]; + unsigned index, padLen; + + /* Save number of bits */ + this->Encode(bits, this->count, 8); + + /* Pad out to 56 mod 64. */ + index = (this->count[0] >> 3) & 0x3f; + padLen = index < 56 ? 56 - index : 120 - index; + this->Update(PADDING, padLen); + + /* Append length (before padding) */ + this->Update(bits, 8); + /* Store state in digest */ + this->Encode(digest, this->state, 16); + + /* Zeroize sensitive information. */ + memset(this->state, 0, sizeof(this->state)); + memset(this->count, 0, sizeof(this->count)); + memset(this->buffer, 0, sizeof(this->buffer)); } -} -/* Decodes input (unsigned char) into output (unsigned). Assumes len is - * a multiple of 4. - */ -void Decode(unsigned *output, const unsigned char *input, unsigned len) -{ - unsigned i, j; + Encryption::Hash GetFinalizedHash() anope_override + { + Encryption::Hash hash; + hash.first = this->digest; + hash.second = sizeof(this->digest); + return hash; + } +}; - for (i = 0, j = 0; j < len; ++i, j += 4) - output[i] = static_cast<unsigned>(input[j]) | (static_cast<unsigned>(input[j + 1]) << 8) | (static_cast<unsigned>(input[j + 2]) << 16) | (static_cast<unsigned>(input[j + 3]) << 24); -} +class MD5Provider : public Encryption::Provider +{ + public: + MD5Provider(Module *creator) : Encryption::Provider(creator, "md5") { } -/*************************************************************************/ + Encryption::Context *CreateContext(Encryption::IV *iv) anope_override + { + return new MD5Context(iv); + } -/* Module stuff. */ + Encryption::IV GetDefaultIV() anope_override + { + Encryption::IV iv; + iv.first = md5_iv; + iv.second = sizeof(md5_iv) / sizeof(uint32_t); + return iv; + } +}; class EMD5 : public Module { + MD5Provider md5provider; + public: - EMD5(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, ENCRYPTION) + EMD5(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, ENCRYPTION), + md5provider(this) { this->SetAuthor("Anope"); @@ -325,15 +355,15 @@ class EMD5 : public Module EventReturn OnEncrypt(const Anope::string &src, Anope::string &dest) anope_override { - MD5_CTX context; - char digest[17] = ""; - Anope::string buf = "md5:"; + MD5Context context; + + context.Update(reinterpret_cast<const unsigned char *>(src.c_str()), src.length()); + context.Finalize(); + + Encryption::Hash hash = context.GetFinalizedHash(); - MD5Init(&context); - MD5Update(&context, reinterpret_cast<const unsigned char *>(src.c_str()), src.length()); - MD5Final(reinterpret_cast<unsigned char *>(digest), &context); + Anope::string buf = "md5:" + Anope::Hex(reinterpret_cast<const char *>(hash.first), hash.second); - buf += Anope::Hex(digest, 16); Log(LOG_DEBUG_2) << "(enc_md5) hashed password from [" << src << "] to [" << buf << "]"; dest = buf; return EVENT_ALLOW; diff --git a/modules/encryption/enc_old.cpp b/modules/encryption/enc_old.cpp index f7c83515d..f1599ccbf 100644 --- a/modules/encryption/enc_old.cpp +++ b/modules/encryption/enc_old.cpp @@ -10,342 +10,75 @@ */ #include "module.h" +#include "encryption.h" -/******** Code specific to the type of encryption. ********/ +static ServiceReference<Encryption::Provider> md5("Encryption::Provider", "md5"); -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. - */ - -/* MD5 context. */ -struct MD5_CTX -{ - unsigned state[4]; /* state (ABCD) */ - unsigned count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -}; - -/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm - */ - -/* Constants for MD5Transform routine. - */ -enum -{ - S11 = 7, - S12 = 12, - S13 = 17, - S14 = 22, - S21 = 5, - S22 = 9, - S23 = 14, - S24 = 20, - S31 = 4, - S32 = 11, - S33 = 16, - S34 = 23, - S41 = 6, - S42 = 10, - S43 = 15, - S44 = 21 -}; - -static void MD5Transform(unsigned [4], const unsigned char[64]); -static void Encode(unsigned char *, unsigned *, unsigned); -static void Decode(unsigned *, const unsigned char *, unsigned); - -static unsigned char PADDING[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G, H and I are basic MD5 functions. - */ -inline static unsigned F(unsigned x, unsigned y, unsigned z) { return (x & y) | (~x & z); } -inline static unsigned G(unsigned x, unsigned y, unsigned z) { return (x & z) | (y & ~z); } -inline static unsigned H(unsigned x, unsigned y, unsigned z) { return x ^ y ^ z; } -inline static unsigned MD5_I(unsigned x, unsigned y, unsigned z) { return y ^ (x | ~z); } - -/* ROTATE_LEFT rotates x left n bits. - */ -inline static unsigned ROTATE_LEFT(unsigned x, unsigned n) { return (x << n) | (x >> (32 - n)); } - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. - * Rotation is separate from addition to prevent recomputation. - */ -inline static void FF(unsigned &a, unsigned b, unsigned c, unsigned d, unsigned x, unsigned s, unsigned ac) -{ - a += F(b, c, d) + x + ac; - a = ROTATE_LEFT(a, s); - a += b; -} -inline static void GG(unsigned &a, unsigned b, unsigned c, unsigned d, unsigned x, unsigned s, unsigned ac) -{ - a += G(b, c, d) + x + ac; - a = ROTATE_LEFT(a, s); - a += b; -} -inline static void HH(unsigned &a, unsigned b, unsigned c, unsigned d, unsigned x, unsigned s, unsigned ac) -{ - a += H(b, c, d) + x + ac; - a = ROTATE_LEFT(a, s); - a += b; -} -inline static void II(unsigned &a, unsigned b, unsigned c, unsigned d, unsigned x, unsigned s, unsigned ac) -{ - a += MD5_I(b, c, d) + x + ac; - a = ROTATE_LEFT(a, s); - a += b; -} - -/* MD5 initialization. Begins an MD5 operation, writing a new context. - */ -static void MD5Init(MD5_CTX *context) -{ - context->count[0] = context->count[1] = 0; - /* Load magic initialization constants. - */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; -} - -/* MD5 block update operation. Continues an MD5 message-digest - * operation, processing another message block, and updating the - * context. - */ -static void MD5Update(MD5_CTX *context, const unsigned char *input, unsigned inputLen) +class OldMD5Provider : public Encryption::Provider { - unsigned i, index, partLen; - - /* Compute number of bytes mod 64 */ - index = (context->count[0] >> 3) & 0x3F; - - /* Update number of bits */ - if ((context->count[0] += inputLen << 3) < (inputLen << 3)) - ++context->count[1]; - context->count[1] += inputLen >> 29; - - partLen = 64 - index; + public: + OldMD5Provider(Module *creator) : Encryption::Provider(creator, "oldmd5") { } - /* Transform as many times as possible. - */ - if (inputLen >= partLen) + Encryption::Context *CreateContext(Encryption::IV *iv) anope_override { - memcpy(&context->buffer[index], input, partLen); - MD5Transform(context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) - MD5Transform(context->state, &input[i]); - - index = 0; + if (md5) + return md5->CreateContext(iv); + return NULL; } - else - i = 0; - - /* Buffer remaining input */ - memcpy(&context->buffer[index], &input[i], inputLen - i); -} - -/* MD5 finalization. Ends an MD5 message-digest operation, writing the - * the message digest and zeroizing the context. - */ -static void MD5Final(unsigned char digest[17], MD5_CTX *context) -{ - unsigned char bits[8]; - unsigned index, padLen; - - /* Save number of bits */ - Encode(bits, context->count, 8); - - /* Pad out to 56 mod 64. - */ - index = (context->count[0] >> 3) & 0x3f; - padLen = index < 56 ? 56 - index : 120 - index; - MD5Update(context, PADDING, padLen); - - /* Append length (before padding) */ - MD5Update(context, bits, 8); - /* Store state in digest */ - Encode(digest, context->state, 16); - - /* Zeroize sensitive information. - */ - memset(context, 0, sizeof(*context)); -} - -/* MD5 basic transformation. Transforms state based on block. - */ -static void MD5Transform(unsigned state[4], const unsigned char block[64]) -{ - unsigned a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode(x, block, 64); - - /* Round 1 */ - FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ - FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ - FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ - FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ - FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ - FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ - FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ - FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ - FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ - FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ - FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ - GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ - GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ - GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ - GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ - GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ - GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ - GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ - GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ - GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ - GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ - HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ - HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ - HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ - HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ - HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ - HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ - HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ - HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ - HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ - II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ - II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ - II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ - II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ - II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ - II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ - II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ - II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ - II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. - */ - memset(x, 0, sizeof(x)); -} - -/* Encodes input (unsigned) into output (unsigned char). Assumes len is - * a multiple of 4. - */ -static void Encode(unsigned char *output, unsigned *input, unsigned len) -{ - unsigned i, j; - - for (i = 0, j = 0; j < len; ++i, j += 4) + Encryption::IV GetDefaultIV() anope_override { - output[j] = static_cast<unsigned char>(input[i] & 0xff); - output[j + 1] = static_cast<unsigned char>((input[i] >> 8) & 0xff); - output[j + 2] = static_cast<unsigned char>((input[i] >> 16) & 0xff); - output[j + 3] = static_cast<unsigned char>((input[i] >> 24) & 0xff); + if (md5) + return md5->GetDefaultIV(); + return Encryption::IV(NULL, 0); } -} +}; -/* Decodes input (unsigned char) into output (unsigned). Assumes len is - * a multiple of 4. - */ -static void Decode(unsigned *output, const unsigned char *input, unsigned len) +class EOld : public Module { - unsigned i, j; - - for (i = 0, j = 0; j < len; ++i, j += 4) - output[i] = static_cast<unsigned>(input[j]) | (static_cast<unsigned>(input[j + 1]) << 8) | (static_cast<unsigned>(input[j + 2]) << 16) | (static_cast<unsigned>(input[j + 3]) << 24); -} + OldMD5Provider oldmd5provider; -/*************************************************************************/ + inline static char XTOI(char c) { return c > 9 ? c - 'A' + 10 : c - '0'; } -/******** Our own high-level routines. ********/ - -inline static char XTOI(char c) { return c > 9 ? c - 'A' + 10 : c - '0'; } - -class EOld : public Module -{ public: - EOld(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, ENCRYPTION) + EOld(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, ENCRYPTION), + oldmd5provider(this) { this->SetAuthor("Anope"); + ModuleManager::LoadModule("enc_md5", User::Find(creator)); + if (!md5) + throw ModuleException("Unable to find md5 reference"); + Implementation i[] = { I_OnEncrypt, I_OnCheckAuthentication }; ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); } EventReturn OnEncrypt(const Anope::string &src, Anope::string &dest) anope_override { - MD5_CTX context; - char digest[33] = "", digest2[17] = ""; - int i; - Anope::string buf = "oldmd5:"; + if (!md5) + return EVENT_CONTINUE; + + Encryption::Context *context = md5->CreateContext(); + context->Update(reinterpret_cast<const unsigned char *>(src.c_str()), src.length()); + context->Finalize(); - memset(&context, 0, sizeof(context)); + Encryption::Hash hash = context->GetFinalizedHash(); - MD5Init(&context); - MD5Update(&context, reinterpret_cast<const unsigned char *>(src.c_str()), src.length()); - MD5Final(reinterpret_cast<unsigned char *>(digest), &context); - for (i = 0; i < 32; i += 2) + char digest[32], digest2[16]; + memset(digest, 0, sizeof(digest)); + if (hash.second > sizeof(digest)) + throw CoreException("Hash too large"); + memcpy(digest, hash.first, hash.second); + + for (int i = 0; i < 32; i += 2) digest2[i / 2] = XTOI(digest[i]) << 4 | XTOI(digest[i + 1]); - buf += Anope::Hex(digest2, 16); + Anope::string buf = "oldmd5:" + Anope::Hex(digest2, sizeof(digest2)); + Log(LOG_DEBUG_2) << "(enc_old) hashed password from [" << src << "] to [" << buf << "]"; dest = buf; + delete context; return EVENT_ALLOW; } diff --git a/modules/encryption/enc_sha1.cpp b/modules/encryption/enc_sha1.cpp index 88571d776..0c9c70830 100644 --- a/modules/encryption/enc_sha1.cpp +++ b/modules/encryption/enc_sha1.cpp @@ -15,20 +15,7 @@ A million repetitions of "a" /* #define LITTLE_ENDIAN * This should be #define'd if true. */ #include "module.h" - -struct SHA1_CTX -{ - uint32_t state[5]; - uint32_t count[2]; - unsigned char buffer[64]; -}; - -void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]); -void SHA1Init(SHA1_CTX *context); -void SHA1Update(SHA1_CTX *context, const unsigned char *data, uint32_t len); -void SHA1Final(unsigned char digest[20], SHA1_CTX *context); - -inline static uint32_t rol(uint32_t value, uint32_t bits) { return (value << bits) | (value >> (32 - bits)); } +#include "encryption.h" union CHAR64LONG16 { @@ -36,139 +23,182 @@ union CHAR64LONG16 uint32_t l[16]; }; +inline static uint32_t rol(uint32_t value, uint32_t bits) { return (value << bits) | (value >> (32 - bits)); } + /* blk0() and blk() perform the initial expand. */ /* I got the idea of expanding during the round function from SSLeay */ -inline static uint32_t blk0(CHAR64LONG16 *block, uint32_t i) +inline static uint32_t blk0(CHAR64LONG16 &block, uint32_t i) { #ifdef LITTLE_ENDIAN - return block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF); + return block.l[i] = (rol(block.l[i], 24) & 0xFF00FF00) | (rol(block.l[i], 8) & 0x00FF00FF); #else - return block->l[i]; + return block.l[i]; #endif } -inline static uint32_t blk(CHAR64LONG16 *block, uint32_t i) { return block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15],1); } +inline static uint32_t blk(CHAR64LONG16 &block, uint32_t i) { return block.l[i & 15] = rol(block.l[(i + 13) & 15] ^ block.l[(i + 8) & 15] ^ block.l[(i + 2) & 15] ^ block.l[i & 15],1); } /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -inline static void R0(CHAR64LONG16 *block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); } -inline static void R1(CHAR64LONG16 *block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += ((w & (x ^ y)) ^ y) + blk(block, i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); } -inline static void R2(CHAR64LONG16 *block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += (w ^ x ^ y) + blk(block, i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); } -inline static void R3(CHAR64LONG16 *block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += (((w | x) & y) | (w & x)) + blk(block, i) + 0x8F1BBCDC + rol(v, 5); w = rol(w, 30); } -inline static void R4(CHAR64LONG16 *block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += (w ^ x ^ y) + blk(block, i) + 0xCA62C1D6 + rol(v, 5); w = rol(w, 30); } +inline static void R0(CHAR64LONG16 &block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); } +inline static void R1(CHAR64LONG16 &block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += ((w & (x ^ y)) ^ y) + blk(block, i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); } +inline static void R2(CHAR64LONG16 &block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += (w ^ x ^ y) + blk(block, i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); } +inline static void R3(CHAR64LONG16 &block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += (((w | x) & y) | (w & x)) + blk(block, i) + 0x8F1BBCDC + rol(v, 5); w = rol(w, 30); } +inline static void R4(CHAR64LONG16 &block, uint32_t v, uint32_t &w, uint32_t x, uint32_t y, uint32_t &z, uint32_t i) { z += (w ^ x ^ y) + blk(block, i) + 0xCA62C1D6 + rol(v, 5); w = rol(w, 30); } -/* Hash a single 512-bit block. This is the core of the algorithm. */ +static const uint32_t sha1_iv[5] = +{ + 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 +}; -void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) +class SHA1Context : public Encryption::Context { - uint32_t a, b, c, d, e; - static unsigned char workspace[64]; - CHAR64LONG16 *block = reinterpret_cast<CHAR64LONG16 *>(workspace); - memcpy(block, buffer, 64); - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(block, a, b, c, d, e, 0); R0(block, e, a, b, c, d, 1); R0(block, d, e, a, b, c, 2); R0(block, c, d, e, a, b, 3); - R0(block, b, c, d, e, a, 4); R0(block, a, b, c, d, e, 5); R0(block, e, a, b, c, d, 6); R0(block, d, e, a, b, c, 7); - R0(block, c, d, e, a, b, 8); R0(block, b, c, d, e, a, 9); R0(block, a, b, c, d, e, 10); R0(block, e, a, b, c, d, 11); - R0(block, d, e, a, b, c, 12); R0(block, c, d, e, a, b, 13); R0(block, b, c, d, e, a, 14); R0(block, a, b, c, d, e, 15); - R1(block, e, a, b, c, d, 16); R1(block, d, e, a, b, c, 17); R1(block, c, d, e, a, b, 18); R1(block, b, c, d, e, a, 19); - R2(block, a, b, c, d, e, 20); R2(block, e, a, b, c, d, 21); R2(block, d, e, a, b, c, 22); R2(block, c, d, e, a, b, 23); - R2(block, b, c, d, e, a, 24); R2(block, a, b, c, d, e, 25); R2(block, e, a, b, c, d, 26); R2(block, d, e, a, b, c, 27); - R2(block, c, d, e, a, b, 28); R2(block, b, c, d, e, a, 29); R2(block, a, b, c, d, e, 30); R2(block, e, a, b, c, d, 31); - R2(block, d, e, a, b, c, 32); R2(block, c, d, e, a, b, 33); R2(block, b, c, d, e, a, 34); R2(block, a, b, c, d, e, 35); - R2(block, e, a, b, c, d, 36); R2(block, d, e, a, b, c, 37); R2(block, c, d, e, a, b, 38); R2(block, b, c, d, e, a, 39); - R3(block, a, b, c, d, e, 40); R3(block, e, a, b, c, d, 41); R3(block, d, e, a, b, c, 42); R3(block, c, d, e, a, b, 43); - R3(block, b, c, d, e, a, 44); R3(block, a, b, c, d, e, 45); R3(block, e, a, b, c, d, 46); R3(block, d, e, a, b, c, 47); - R3(block, c, d, e, a, b, 48); R3(block, b, c, d, e, a, 49); R3(block, a, b, c, d, e, 50); R3(block, e, a, b, c, d, 51); - R3(block, d, e, a, b, c, 52); R3(block, c, d, e, a, b, 53); R3(block, b, c, d, e, a, 54); R3(block, a, b, c, d, e, 55); - R3(block, e, a, b, c, d, 56); R3(block, d, e, a, b, c, 57); R3(block, c, d, e, a, b, 58); R3(block, b, c, d, e, a, 59); - R4(block, a, b, c, d, e, 60); R4(block, e, a, b, c, d, 61); R4(block, d, e, a, b, c, 62); R4(block, c, d, e, a, b, 63); - R4(block, b, c, d, e, a, 64); R4(block, a, b, c, d, e, 65); R4(block, e, a, b, c, d, 66); R4(block, d, e, a, b, c, 67); - R4(block, c, d, e, a, b, 68); R4(block, b, c, d, e, a, 69); R4(block, a, b, c, d, e, 70); R4(block, e, a, b, c, d, 71); - R4(block, d, e, a, b, c, 72); R4(block, c, d, e, a, b, 73); R4(block, b, c, d, e, a, 74); R4(block, a, b, c, d, e, 75); - R4(block, e, a, b, c, d, 76); R4(block, d, e, a, b, c, 77); R4(block, c, d, e, a, b, 78); R4(block, b, c, d, e, a, 79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -} + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; + unsigned char digest[20]; -/* SHA1Init - Initialize new context */ + void Transform(const unsigned char buf[64]) + { + uint32_t a, b, c, d, e; + + CHAR64LONG16 block; + memcpy(block.c, buf, 64); + + /* Copy context->state[] to working vars */ + a = this->state[0]; + b = this->state[1]; + c = this->state[2]; + d = this->state[3]; + e = this->state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(block, a, b, c, d, e, 0); R0(block, e, a, b, c, d, 1); R0(block, d, e, a, b, c, 2); R0(block, c, d, e, a, b, 3); + R0(block, b, c, d, e, a, 4); R0(block, a, b, c, d, e, 5); R0(block, e, a, b, c, d, 6); R0(block, d, e, a, b, c, 7); + R0(block, c, d, e, a, b, 8); R0(block, b, c, d, e, a, 9); R0(block, a, b, c, d, e, 10); R0(block, e, a, b, c, d, 11); + R0(block, d, e, a, b, c, 12); R0(block, c, d, e, a, b, 13); R0(block, b, c, d, e, a, 14); R0(block, a, b, c, d, e, 15); + R1(block, e, a, b, c, d, 16); R1(block, d, e, a, b, c, 17); R1(block, c, d, e, a, b, 18); R1(block, b, c, d, e, a, 19); + R2(block, a, b, c, d, e, 20); R2(block, e, a, b, c, d, 21); R2(block, d, e, a, b, c, 22); R2(block, c, d, e, a, b, 23); + R2(block, b, c, d, e, a, 24); R2(block, a, b, c, d, e, 25); R2(block, e, a, b, c, d, 26); R2(block, d, e, a, b, c, 27); + R2(block, c, d, e, a, b, 28); R2(block, b, c, d, e, a, 29); R2(block, a, b, c, d, e, 30); R2(block, e, a, b, c, d, 31); + R2(block, d, e, a, b, c, 32); R2(block, c, d, e, a, b, 33); R2(block, b, c, d, e, a, 34); R2(block, a, b, c, d, e, 35); + R2(block, e, a, b, c, d, 36); R2(block, d, e, a, b, c, 37); R2(block, c, d, e, a, b, 38); R2(block, b, c, d, e, a, 39); + R3(block, a, b, c, d, e, 40); R3(block, e, a, b, c, d, 41); R3(block, d, e, a, b, c, 42); R3(block, c, d, e, a, b, 43); + R3(block, b, c, d, e, a, 44); R3(block, a, b, c, d, e, 45); R3(block, e, a, b, c, d, 46); R3(block, d, e, a, b, c, 47); + R3(block, c, d, e, a, b, 48); R3(block, b, c, d, e, a, 49); R3(block, a, b, c, d, e, 50); R3(block, e, a, b, c, d, 51); + R3(block, d, e, a, b, c, 52); R3(block, c, d, e, a, b, 53); R3(block, b, c, d, e, a, 54); R3(block, a, b, c, d, e, 55); + R3(block, e, a, b, c, d, 56); R3(block, d, e, a, b, c, 57); R3(block, c, d, e, a, b, 58); R3(block, b, c, d, e, a, 59); + R4(block, a, b, c, d, e, 60); R4(block, e, a, b, c, d, 61); R4(block, d, e, a, b, c, 62); R4(block, c, d, e, a, b, 63); + R4(block, b, c, d, e, a, 64); R4(block, a, b, c, d, e, 65); R4(block, e, a, b, c, d, 66); R4(block, d, e, a, b, c, 67); + R4(block, c, d, e, a, b, 68); R4(block, b, c, d, e, a, 69); R4(block, a, b, c, d, e, 70); R4(block, e, a, b, c, d, 71); + R4(block, d, e, a, b, c, 72); R4(block, c, d, e, a, b, 73); R4(block, b, c, d, e, a, 74); R4(block, a, b, c, d, e, 75); + R4(block, e, a, b, c, d, 76); R4(block, d, e, a, b, c, 77); R4(block, c, d, e, a, b, 78); R4(block, b, c, d, e, a, 79); + /* Add the working vars back into context.state[] */ + this->state[0] += a; + this->state[1] += b; + this->state[2] += c; + this->state[3] += d; + this->state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; + } -void SHA1Init(SHA1_CTX *context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} + public: + SHA1Context(Encryption::IV *iv = NULL) + { + if (iv != NULL) + { + if (iv->second != 5) + throw CoreException("Invalid IV size"); + for (int i = 0; i < 5; ++i) + this->state[i] = iv->first[i]; + } + else + for (int i = 0; i < 5; ++i) + this->state[i] = sha1_iv[i]; + + this->count[0] = this->count[1] = 0; + memset(this->buffer, 0, sizeof(this->buffer)); + memset(this->digest, 0, sizeof(this->digest)); + } -/* Run your data through this. */ + void Update(const unsigned char *data, size_t len) anope_override + { + uint32_t i, j; -void SHA1Update(SHA1_CTX *context, const unsigned char *data, uint32_t len) -{ - uint32_t i, j; + j = (this->count[0] >> 3) & 63; + if ((this->count[0] += len << 3) < (len << 3)) + ++this->count[1]; + this->count[1] += len >> 29; + if (j + len > 63) + { + memcpy(&this->buffer[j], data, (i = 64 - j)); + this->Transform(this->buffer); + for (; i + 63 < len; i += 64) + this->Transform(&data[i]); + j = 0; + } + else + i = 0; + memcpy(&this->buffer[j], &data[i], len - i); + } - j = (context->count[0] >> 3) & 63; - if ((context->count[0] += len << 3) < (len << 3)) - ++context->count[1]; - context->count[1] += len >> 29; - if (j + len > 63) + void Finalize() anope_override { - memcpy(&context->buffer[j], data, (i = 64 - j)); - SHA1Transform(context->state, context->buffer); - for (; i + 63 < len; i += 64) - SHA1Transform(context->state, &data[i]); - j = 0; + uint32_t i; + unsigned char finalcount[8]; + + for (i = 0; i < 8; ++i) + finalcount[i] = static_cast<unsigned char>((this->count[i >= 4 ? 0 : 1] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ + this->Update(reinterpret_cast<const unsigned char *>("\200"), 1); + while ((this->count[0] & 504) != 448) + this->Update(reinterpret_cast<const unsigned char *>("\0"), 1); + this->Update(finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; ++i) + this->digest[i] = static_cast<unsigned char>((this->state[i>>2] >> ((3 - (i & 3)) * 8)) & 255); + + /* Wipe variables */ + memset(this->buffer, 0, sizeof(this->buffer)); + memset(this->state, 0, sizeof(this->state)); + memset(this->count, 0, sizeof(this->count)); + memset(&finalcount, 0, sizeof(finalcount)); + + this->Transform(this->buffer); } - else - i = 0; - memcpy(&context->buffer[j], &data[i], len - i); -} -/* Add padding and return the message digest. */ + Encryption::Hash GetFinalizedHash() anope_override + { + Encryption::Hash hash; + hash.first = this->digest; + hash.second = sizeof(this->digest); + return hash; + } +}; -void SHA1Final(unsigned char digest[21], SHA1_CTX *context) +class SHA1Provider : public Encryption::Provider { - uint32_t i; - unsigned char finalcount[8]; - - for (i = 0; i < 8; ++i) - finalcount[i] = static_cast<unsigned char>((context->count[i >= 4 ? 0 : 1] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ - SHA1Update(context, reinterpret_cast<const unsigned char *>("\200"), 1); - while ((context->count[0] & 504) != 448) - SHA1Update(context, reinterpret_cast<const unsigned char *>("\0"), 1); - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; ++i) - digest[i] = static_cast<unsigned char>((context->state[i>>2] >> ((3 - (i & 3)) * 8)) & 255); - /* Wipe variables */ - i = 0; - memset(context->buffer, 0, 64); - memset(context->state, 0, 20); - memset(context->count, 0, 8); - memset(&finalcount, 0, 8); - SHA1Transform(context->state, context->buffer); -} + public: + SHA1Provider(Module *creator) : Encryption::Provider(creator, "sha1") { } -/*****************************************************************************/ -/*****************************************************************************/ + Encryption::Context *CreateContext(Encryption::IV *iv) anope_override + { + return new SHA1Context(iv); + } -/* Module stuff. */ + Encryption::IV GetDefaultIV() anope_override + { + Encryption::IV iv; + iv.first = sha1_iv; + iv.second = sizeof(sha1_iv) / sizeof(uint32_t); + return iv; + } +}; class ESHA1 : public Module { + SHA1Provider sha1provider; + public: - ESHA1(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, ENCRYPTION) + ESHA1(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, ENCRYPTION), + sha1provider(this) { this->SetAuthor("Anope"); @@ -178,15 +208,15 @@ class ESHA1 : public Module EventReturn OnEncrypt(const Anope::string &src, Anope::string &dest) anope_override { - SHA1_CTX context; - char digest[21] = ""; - Anope::string buf = "sha1:"; + SHA1Context context; + + context.Update(reinterpret_cast<const unsigned char *>(src.c_str()), src.length()); + context.Finalize(); + + Encryption::Hash hash = context.GetFinalizedHash(); - SHA1Init(&context); - SHA1Update(&context, reinterpret_cast<const unsigned char *>(src.c_str()), src.length()); - SHA1Final(reinterpret_cast<unsigned char *>(digest), &context); + Anope::string buf = "sha1:" + Anope::Hex(reinterpret_cast<const char *>(hash.first), hash.second); - buf += Anope::Hex(digest, 20); Log(LOG_DEBUG_2) << "(enc_sha1) hashed password from [" << src << "] to [" << buf << "]"; dest = buf; return EVENT_ALLOW; diff --git a/modules/encryption/enc_sha256.cpp b/modules/encryption/enc_sha256.cpp index 396f975ed..8c0c4b342 100644 --- a/modules/encryption/enc_sha256.cpp +++ b/modules/encryption/enc_sha256.cpp @@ -1,9 +1,4 @@ /* This module generates and compares password hashes using SHA256 algorithms. - * To help reduce the risk of dictionary attacks, the code appends random bytes - * (so-called "salt") to the original plain text before generating hashes and - * stores this salt appended to the result. To verify another plain text value - * against the given hash, this module will retrieve the salt value from the - * password string and use it when computing a new hash of the plain text. * * If an intruder gets access to your system or uses a brute force attack, * salt will not provide much value. @@ -53,21 +48,11 @@ */ #include "module.h" +#include "encryption.h" static const unsigned SHA256_DIGEST_SIZE = 256 / 8; static const unsigned SHA256_BLOCK_SIZE = 512 / 8; -/** An sha256 context - */ -class SHA256Context -{ - public: - unsigned tot_len; - unsigned len; - unsigned char block[2 * SHA256_BLOCK_SIZE]; - uint32_t h[8]; -}; - inline static uint32_t SHFR(uint32_t x, uint32_t n) { return x >> n; } inline static uint32_t ROTR(uint32_t x, uint32_t n) { return (x >> n) | (x << ((sizeof(x) << 3) - n)); } inline static uint32_t ROTL(uint32_t x, uint32_t n) { return (x << n) | (x >> ((sizeof(x) << 3) - n)); } @@ -99,7 +84,13 @@ inline static void SHA256_SCR(uint32_t w[64], int i) w[i] = SHA256_F4(w[i - 2]) + w[i - 7] + SHA256_F3(w[i - 15]) + w[i - 16]; } -uint32_t sha256_k[64] = +static const uint32_t sha256_h0[8] = +{ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +static const uint32_t sha256_k[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, @@ -119,49 +110,11 @@ uint32_t sha256_k[64] = 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; -class ESHA256 : public Module +/** An sha256 context + */ +class SHA256Context : public Encryption::Context { - unsigned iv[8]; - bool use_iv; - - /* initializes the IV with a new random value */ - void NewRandomIV() - { - for (int i = 0; i < 8; ++i) - iv[i] = static_cast<uint32_t>(rand()); - } - - /* returns the IV as base64-encrypted string */ - Anope::string GetIVString() - { - char buf[33]; - for (int i = 0; i < 8; ++i) - UNPACK32(iv[i], reinterpret_cast<unsigned char *>(&buf[i << 2])); - buf[32] = '\0'; - return Anope::Hex(buf, 32); - } - - /* splits the appended IV from the password string so it can be used for the next encryption */ - /* password format: <hashmethod>:<password_b64>:<iv_b64> */ - void GetIVFromPass(const Anope::string &password) - { - size_t pos = password.find(':'); - Anope::string buf = password.substr(password.find(':', pos + 1) + 1, password.length()); - char buf2[33]; - Anope::Unhex(buf, buf2, sizeof(buf2)); - for (int i = 0 ; i < 8; ++i) - PACK32(reinterpret_cast<unsigned char *>(&buf2[i << 2]), iv[i]); - } - - void SHA256Init(SHA256Context *ctx) - { - for (int i = 0; i < 8; ++i) - ctx->h[i] = iv[i]; - ctx->len = 0; - ctx->tot_len = 0; - } - - void SHA256Transform(SHA256Context *ctx, unsigned char *message, unsigned block_nb) + void Transform(unsigned char *message, unsigned block_nb) { uint32_t w[64], wv[8]; unsigned char *sub_block; @@ -175,7 +128,7 @@ class ESHA256 : public Module for (j = 16; j < 64; ++j) SHA256_SCR(w, j); for (j = 0; j < 8; ++j) - wv[j] = ctx->h[j]; + wv[j] = this->h[j]; for (j = 0; j < 64; ++j) { uint32_t t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j]; @@ -190,64 +143,139 @@ class ESHA256 : public Module wv[0] = t1 + t2; } for (j = 0; j < 8; ++j) - ctx->h[j] += wv[j]; + this->h[j] += wv[j]; + } + } + + unsigned tot_len; + unsigned len; + unsigned char block[2 * SHA256_BLOCK_SIZE]; + uint32_t h[8]; + unsigned char digest[SHA256_DIGEST_SIZE + 1]; + + public: + SHA256Context(Encryption::IV *iv) + { + if (iv != NULL) + { + if (iv->second != 8) + throw CoreException("Invalid IV size"); + for (int i = 0; i < 8; ++i) + this->h[i] = iv->first[i]; } + else + for (int i = 0; i < 8; ++i) + this->h[i] = sha256_h0[i]; + + this->tot_len = 0; + this->len = 0; + memset(this->block, 0, sizeof(this->block)); + memset(this->digest, 0, sizeof(this->digest)); } - void SHA256Update(SHA256Context *ctx, const unsigned char *message, unsigned len) + void Update(const unsigned char *message, size_t mlen) anope_override { - /* - * XXX here be dragons! - * After many hours of pouring over this, I think I've found the problem. - * When Special created our module from the reference one, he used: - * - * unsigned rem_len = SHA256_BLOCK_SIZE - ctx->len; - * - * instead of the reference's version of: - * - * unsigned tmp_len = SHA256_BLOCK_SIZE - ctx->len; - * unsigned rem_len = len < tmp_len ? len : tmp_len; - * - * I've changed back to the reference version of this code, and it seems to work with no errors. - * So I'm inclined to believe this was the problem.. - * -- w00t (January 06, 2008) - */ - unsigned tmp_len = SHA256_BLOCK_SIZE - ctx->len, rem_len = len < tmp_len ? len : tmp_len; - - memcpy(&ctx->block[ctx->len], message, rem_len); - if (ctx->len + len < SHA256_BLOCK_SIZE) + unsigned tmp_len = SHA256_BLOCK_SIZE - this->len, rem_len = mlen < tmp_len ? mlen : tmp_len; + + memcpy(&this->block[this->len], message, rem_len); + if (this->len + mlen < SHA256_BLOCK_SIZE) { - ctx->len += len; + this->len += mlen; return; } - unsigned new_len = len - rem_len, block_nb = new_len / SHA256_BLOCK_SIZE; - unsigned char *shifted_message = new unsigned char[len - rem_len]; - memcpy(shifted_message, message + rem_len, len - rem_len); - SHA256Transform(ctx, ctx->block, 1); - SHA256Transform(ctx, shifted_message, block_nb); + unsigned new_len = mlen - rem_len, block_nb = new_len / SHA256_BLOCK_SIZE; + unsigned char *shifted_message = new unsigned char[mlen - rem_len]; + memcpy(shifted_message, message + rem_len, mlen - rem_len); + this->Transform(this->block, 1); + this->Transform(shifted_message, block_nb); rem_len = new_len % SHA256_BLOCK_SIZE; - memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len); + memcpy(this->block, &shifted_message[block_nb << 6], rem_len); delete [] shifted_message; - ctx->len = rem_len; - ctx->tot_len += (block_nb + 1) << 6; + this->len = rem_len; + this->tot_len += (block_nb + 1) << 6; } - void SHA256Final(SHA256Context *ctx, unsigned char *digest) + void Finalize() anope_override { - unsigned block_nb = 1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE)); - unsigned len_b = (ctx->tot_len + ctx->len) << 3; + unsigned block_nb = 1 + ((SHA256_BLOCK_SIZE - 9) < (this->len % SHA256_BLOCK_SIZE)); + unsigned len_b = (this->tot_len + this->len) << 3; unsigned pm_len = block_nb << 6; - memset(ctx->block + ctx->len, 0, pm_len - ctx->len); - ctx->block[ctx->len] = 0x80; - UNPACK32(len_b, ctx->block + pm_len - 4); - SHA256Transform(ctx, ctx->block, block_nb); + memset(this->block + this->len, 0, pm_len - this->len); + this->block[this->len] = 0x80; + UNPACK32(len_b, this->block + pm_len - 4); + this->Transform(this->block, block_nb); + for (int i = 0 ; i < 8; ++i) + UNPACK32(this->h[i], &this->digest[i << 2]); + this->digest[SHA256_BLOCK_SIZE] = 0; + } + + Encryption::Hash GetFinalizedHash() anope_override + { + Encryption::Hash hash; + hash.first = this->digest; + hash.second = SHA256_BLOCK_SIZE; + return hash; + } +}; + +class SHA256Provider : public Encryption::Provider +{ + public: + SHA256Provider(Module *creator) : Encryption::Provider(creator, "sha256") { } + + Encryption::Context *CreateContext(Encryption::IV *iv) anope_override + { + return new SHA256Context(iv); + } + + Encryption::IV GetDefaultIV() anope_override + { + Encryption::IV iv; + iv.first = sha256_h0; + iv.second = sizeof(sha256_h0) / sizeof(uint32_t); + return iv; + } +}; + +class ESHA256 : public Module +{ + SHA256Provider sha256provider; + + unsigned iv[8]; + bool use_iv; + + /* initializes the IV with a new random value */ + void NewRandomIV() + { + for (int i = 0; i < 8; ++i) + iv[i] = static_cast<uint32_t>(rand()); + } + + /* returns the IV as base64-encrypted string */ + Anope::string GetIVString() + { + char buf[33]; + for (int i = 0; i < 8; ++i) + UNPACK32(iv[i], reinterpret_cast<unsigned char *>(&buf[i << 2])); + buf[32] = '\0'; + return Anope::Hex(buf, 32); + } + + /* splits the appended IV from the password string so it can be used for the next encryption */ + /* password format: <hashmethod>:<password_b64>:<iv_b64> */ + void GetIVFromPass(const Anope::string &password) + { + size_t pos = password.find(':'); + Anope::string buf = password.substr(password.find(':', pos + 1) + 1, password.length()); + char buf2[33]; + Anope::Unhex(buf, buf2, sizeof(buf2)); for (int i = 0 ; i < 8; ++i) - UNPACK32(ctx->h[i], &digest[i << 2]); + PACK32(reinterpret_cast<unsigned char *>(&buf2[i << 2]), iv[i]); } -/********** ANOPE ******/ public: - ESHA256(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, ENCRYPTION) + ESHA256(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, ENCRYPTION), + sha256provider(this) { this->SetAuthor("Anope"); @@ -259,20 +287,20 @@ class ESHA256 : public Module EventReturn OnEncrypt(const Anope::string &src, Anope::string &dest) anope_override { - char digest[SHA256_DIGEST_SIZE + 1]; - SHA256Context ctx; - std::stringstream buf; - if (!use_iv) NewRandomIV(); else use_iv = false; - SHA256Init(&ctx); - SHA256Update(&ctx, reinterpret_cast<const unsigned char *>(src.c_str()), src.length()); - SHA256Final(&ctx, reinterpret_cast<unsigned char *>(digest)); - digest[SHA256_DIGEST_SIZE] = '\0'; - buf << "sha256:" << Anope::Hex(digest, SHA256_DIGEST_SIZE) << ":" << GetIVString(); + Encryption::IV initilization(this->iv, 8); + SHA256Context ctx(&initilization); + ctx.Update(reinterpret_cast<const unsigned char *>(src.c_str()), src.length()); + ctx.Finalize(); + + Encryption::Hash hash = ctx.GetFinalizedHash(); + + std::stringstream buf; + buf << "sha256:" << Anope::Hex(reinterpret_cast<const char *>(hash.first), hash.second) << ":" << GetIVString(); Log(LOG_DEBUG_2) << "(enc_sha256) hashed password from [" << src << "] to [" << buf.str() << " ]"; dest = buf.str(); return EVENT_ALLOW; diff --git a/modules/encryption/encryption.h b/modules/encryption/encryption.h new file mode 100644 index 000000000..95e5a7299 --- /dev/null +++ b/modules/encryption/encryption.h @@ -0,0 +1,37 @@ +/* + * + * (C) 2003-2012 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + * + */ + +namespace Encryption +{ + typedef std::pair<const unsigned char *, size_t> Hash; + typedef std::pair<const uint32_t *, size_t> IV; + + class Context + { + public: + virtual ~Context() { } + virtual void Update(const unsigned char *data, size_t len) = 0; + virtual void Finalize() = 0; + virtual Hash GetFinalizedHash() = 0; + }; + + class Provider : public Service + { + public: + Provider(Module *creator, const Anope::string &sname) : Service(creator, "Encryption::Provider", sname) { } + virtual ~Provider() { } + + virtual Context *CreateContext(IV * = NULL) = 0; + virtual IV GetDefaultIV() = 0; + }; +} + diff --git a/modules/protocol/inspircd11.cpp b/modules/protocol/inspircd11.cpp index 2b4851fcd..23bd5bca8 100644 --- a/modules/protocol/inspircd11.cpp +++ b/modules/protocol/inspircd11.cpp @@ -256,7 +256,7 @@ class InspIRCdProto : public IRCDProto SendServer(Me); UplinkSocket::Message() << "BURST"; Module *enc = ModuleManager::FindFirstOf(ENCRYPTION); - UplinkSocket::Message(Me) << "VERSION :Anope-" << Anope::Version() << " " << Me->GetName() << " :" << this->GetProtocolName() << " - (" << (enc ? enc->name : "unknown") << ") -- " << Anope::VersionBuildString(); + UplinkSocket::Message(Me) << "VERSION :Anope-" << Anope::Version() << " " << Me->GetName() << " :" << this->GetProtocolName() << " - (" << (enc ? enc->name : "none") << ") -- " << Anope::VersionBuildString(); } /* SVSHOLD - set */ diff --git a/modules/protocol/inspircd12.cpp b/modules/protocol/inspircd12.cpp index edbb27c88..ba2840bad 100644 --- a/modules/protocol/inspircd12.cpp +++ b/modules/protocol/inspircd12.cpp @@ -279,7 +279,7 @@ class InspIRCd12Proto : public IRCDProto SendServer(Me); UplinkSocket::Message(Me) << "BURST"; Module *enc = ModuleManager::FindFirstOf(ENCRYPTION); - UplinkSocket::Message(Me) << "VERSION :Anope-" << Anope::Version() << " " << Config->ServerName << " :" << IRCD->GetProtocolName() << " - (" << (enc ? enc->name : "unknown") << ") -- " << Anope::VersionBuildString(); + UplinkSocket::Message(Me) << "VERSION :Anope-" << Anope::Version() << " " << Config->ServerName << " :" << IRCD->GetProtocolName() << " - (" << (enc ? enc->name : "none") << ") -- " << Anope::VersionBuildString(); } /* SVSHOLD - set */ diff --git a/src/encrypt.cpp b/src/encrypt.cpp deleted file mode 100644 index 0227be2ef..000000000 --- a/src/encrypt.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - * (C) 2003-2012 Anope Team - * Contact us at team@anope.org - * - * Please read COPYING and README for further details. - * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. - * - */ - -#include "services.h" -#include "modules.h" - -/******************************************************************************/ - -/** Encrypt the string src into dest - * @param src The source string - * @param dest The destination strnig - */ -void Anope::Encrypt(const Anope::string &src, Anope::string &dest) -{ - EventReturn MOD_RESULT; - FOREACH_RESULT(I_OnEncrypt, OnEncrypt(src, dest)); -} - -/** Decrypt the encrypted string src into dest - * @param src The encrypted string - * @param desc The destination string - * @return true on success - */ -bool Anope::Decrypt(const Anope::string &src, Anope::string &dest) -{ - size_t pos = src.find(':'); - if (pos == Anope::string::npos) - { - Log() << "Error: Anope::Decrypt() called with invalid password string (" << src << ")"; - return false; - } - Anope::string hashm(src.begin(), src.begin() + pos); - - EventReturn MOD_RESULT; - FOREACH_RESULT(I_OnDecrypt, OnDecrypt(hashm, src, dest)); - if (MOD_RESULT == EVENT_ALLOW) - return true; - - return false; -} - diff --git a/src/init.cpp b/src/init.cpp index e831351ec..e45d2a6f9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -451,8 +451,6 @@ void Anope::Init(int ac, char **av) Module *protocol = ModuleManager::FindFirstOf(PROTOCOL); if (protocol == NULL) throw CoreException("You must load a protocol module!"); - else if (ModuleManager::FindFirstOf(ENCRYPTION) == NULL) - throw CoreException("You must load at least one encryption module"); Log() << "Using IRCd protocol " << protocol->name; diff --git a/src/messages.cpp b/src/messages.cpp index f5e598945..f9dc81c85 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -326,7 +326,7 @@ void Privmsg::Run(MessageSource &source, const std::vector<Anope::string> ¶m else if (message.substr(0, 9).equals_ci("\1VERSION\1")) { Module *enc = ModuleManager::FindFirstOf(ENCRYPTION); - IRCD->SendCTCP(bi, u->nick, "VERSION Anope-%s %s :%s - (%s) -- %s", Anope::Version().c_str(), Config->ServerName.c_str(), IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "unknown", Anope::VersionBuildString().c_str()); + IRCD->SendCTCP(bi, u->nick, "VERSION Anope-%s %s :%s - (%s) -- %s", Anope::Version().c_str(), Config->ServerName.c_str(), IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "(none)", Anope::VersionBuildString().c_str()); } return; } @@ -448,7 +448,7 @@ void Topic::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) void Version::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { Module *enc = ModuleManager::FindFirstOf(ENCRYPTION); - IRCD->SendNumeric(351, source.GetSource(), "Anope-%s %s :%s -(%s) -- %s", Anope::Version().c_str(), Config->ServerName.c_str(), IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "unknown", Anope::VersionBuildString().c_str()); + IRCD->SendNumeric(351, source.GetSource(), "Anope-%s %s :%s -(%s) -- %s", Anope::Version().c_str(), Config->ServerName.c_str(), IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "(none)", Anope::VersionBuildString().c_str()); return; } diff --git a/src/misc.cpp b/src/misc.cpp index 7196a1534..417849df4 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -450,6 +450,30 @@ bool Anope::Match(const Anope::string &str, const Anope::string &mask, bool case return m == mask_len; } +void Anope::Encrypt(const Anope::string &src, Anope::string &dest) +{ + EventReturn MOD_RESULT; + FOREACH_RESULT(I_OnEncrypt, OnEncrypt(src, dest)); +} + +bool Anope::Decrypt(const Anope::string &src, Anope::string &dest) +{ + size_t pos = src.find(':'); + if (pos == Anope::string::npos) + { + Log() << "Error: Anope::Decrypt() called with invalid password string (" << src << ")"; + return false; + } + Anope::string hashm(src.begin(), src.begin() + pos); + + EventReturn MOD_RESULT; + FOREACH_RESULT(I_OnDecrypt, OnDecrypt(hashm, src, dest)); + if (MOD_RESULT == EVENT_ALLOW) + return true; + + return false; +} + Anope::string Anope::printf(const char *fmt, ...) { va_list args; |