The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

m_sha256.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
00006  * See: http://www.inspircd.org/wiki/index.php/Credits
00007  *
00008  * This program is free but copyrighted software; see
00009  *            the file COPYING for details.
00010  *
00011  * ---------------------------------------------------
00012  */
00013 
00014 /* m_sha256 - Based on m_opersha256 written by Special <john@yarbbles.com>
00015  * Modified and improved by Craig Edwards, December 2006.
00016  *
00017  *
00018  * FIPS 180-2 SHA-224/256/384/512 implementation
00019  * Last update: 05/23/2005
00020  * Issue date:  04/30/2005
00021  *
00022  * Copyright (C) 2005 Olivier Gay <olivier.gay@a3.epfl.ch>
00023  * All rights reserved.
00024  *
00025  * Redistribution and use in source and binary forms, with or without
00026  * modification, are permitted provided that the following conditions
00027  * are met:
00028  * 1. Redistributions of source code must retain the above copyright
00029  *    notice, this list of conditions and the following disclaimer.
00030  * 2. Redistributions in binary form must reproduce the above copyright
00031  *    notice, this list of conditions and the following disclaimer in the
00032  *    documentation and/or other materials provided with the distribution.
00033  * 3. Neither the name of the project nor the names of its contributors
00034  *    may be used to endorse or promote products derived from this software
00035  *    without specific prior written permission.
00036  *
00037  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
00038  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00039  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00040  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
00041  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00042  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00043  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00044  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00045  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00046  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00047  * SUCH DAMAGE.
00048  */
00049 
00050 /* $ModDesc: Allows for SHA-256 encrypted oper passwords */
00051 /* $ModDep: m_hash.h */
00052 
00053 #include "inspircd.h"
00054 #ifdef HAS_STDINT
00055 #include <stdint.h>
00056 #endif
00057 #include "m_hash.h"
00058 
00059 #ifndef HAS_STDINT
00060 typedef unsigned int uint32_t;
00061 #endif
00062 
00065 class SHA256Context : public classbase
00066 {
00067  public:
00068         unsigned int tot_len;
00069         unsigned int len;
00070         unsigned char block[2 * SHA256_BLOCK_SIZE];
00071         uint32_t h[8];
00072 };
00073 
00074 #define SHFR(x, n)    (x >> n)
00075 #define ROTR(x, n)   ((x >> n) | (x << ((sizeof(x) << 3) - n)))
00076 #define ROTL(x, n)   ((x << n) | (x >> ((sizeof(x) << 3) - n)))
00077 #define CH(x, y, z)  ((x & y) ^ (~x & z))
00078 #define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
00079 
00080 #define SHA256_F1(x) (ROTR(x,  2) ^ ROTR(x, 13) ^ ROTR(x, 22))
00081 #define SHA256_F2(x) (ROTR(x,  6) ^ ROTR(x, 11) ^ ROTR(x, 25))
00082 #define SHA256_F3(x) (ROTR(x,  7) ^ ROTR(x, 18) ^ SHFR(x,  3))
00083 #define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
00084 
00085 #define UNPACK32(x, str)                       \
00086 {                                             \
00087         *((str) + 3) = (uint8_t) ((x)      );      \
00088         *((str) + 2) = (uint8_t) ((x) >>  8);      \
00089         *((str) + 1) = (uint8_t) ((x) >> 16);      \
00090         *((str) + 0) = (uint8_t) ((x) >> 24);      \
00091 }
00092 
00093 #define PACK32(str, x)                   \
00094 {                                             \
00095         *(x) = ((uint32_t) *((str) + 3)      )     \
00096         | ((uint32_t) *((str) + 2) <<  8)     \
00097         | ((uint32_t) *((str) + 1) << 16)     \
00098         | ((uint32_t) *((str) + 0) << 24);    \
00099 }
00100 
00101 /* Macros used for loops unrolling */
00102 
00103 #define SHA256_SCR(i)                     \
00104 {                                             \
00105         w[i] =  SHA256_F4(w[i - 2]) + w[i - 7]     \
00106         + SHA256_F3(w[i - 15]) + w[i - 16];  \
00107 }
00108 
00109 const unsigned int sha256_h0[8] =
00110 {
00111         0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
00112         0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
00113 };
00114 
00115 uint32_t sha256_k[64] =
00116 {
00117         0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
00118         0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
00119         0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
00120         0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
00121         0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
00122         0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
00123         0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
00124         0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
00125         0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
00126         0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
00127         0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
00128         0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
00129         0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
00130         0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
00131         0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
00132         0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
00133 };
00134 
00135 class ModuleSHA256 : public Module
00136 {
00137         void SHA256Init(SHA256Context *ctx, const unsigned int* ikey)
00138         {
00139                 if (ikey)
00140                 {
00141                         for (int i = 0; i < 8; i++)
00142                                 ctx->h[i] = ikey[i];
00143                 }
00144                 else
00145                 {
00146                         for (int i = 0; i < 8; i++)
00147                                 ctx->h[i] = sha256_h0[i];
00148                 }
00149                 ctx->len = 0;
00150                 ctx->tot_len = 0;
00151         }
00152 
00153         void SHA256Transform(SHA256Context *ctx, unsigned char *message, unsigned int block_nb)
00154         {
00155                 uint32_t w[64];
00156                 uint32_t wv[8];
00157                 unsigned char *sub_block;
00158                 for (unsigned int i = 1; i <= block_nb; i++)
00159                 {
00160                         int j;
00161                         sub_block = message + ((i - 1) << 6);
00162 
00163                         for (j = 0; j < 16; j++)
00164                                 PACK32(&sub_block[j << 2], &w[j]);
00165                         for (j = 16; j < 64; j++)
00166                                 SHA256_SCR(j);
00167                         for (j = 0; j < 8; j++)
00168                                 wv[j] = ctx->h[j];
00169                         for (j = 0; j < 64; j++)
00170                         {
00171                                 uint32_t t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j];
00172                                 uint32_t t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
00173                                 wv[7] = wv[6];
00174                                 wv[6] = wv[5];
00175                                 wv[5] = wv[4];
00176                                 wv[4] = wv[3] + t1;
00177                                 wv[3] = wv[2];
00178                                 wv[2] = wv[1];
00179                                 wv[1] = wv[0];
00180                                 wv[0] = t1 + t2;
00181                         }
00182                         for (j = 0; j < 8; j++)
00183                                 ctx->h[j] += wv[j];
00184                 }
00185         }
00186 
00187         void SHA256Update(SHA256Context *ctx, unsigned char *message, unsigned int len)
00188         {
00189                 /*
00190                  * XXX here be dragons!
00191                  * After many hours of pouring over this, I think I've found the problem.
00192                  * When Special created our module from the reference one, he used:
00193                  *
00194                  *     unsigned int rem_len = SHA256_BLOCK_SIZE - ctx->len;
00195                  *
00196                  * instead of the reference's version of:
00197                  *
00198                  *     unsigned int tmp_len = SHA256_BLOCK_SIZE - ctx->len;
00199                  *     unsigned int rem_len = len < tmp_len ? len : tmp_len;
00200                  *
00201                  * I've changed back to the reference version of this code, and it seems to work with no errors.
00202                  * So I'm inclined to believe this was the problem..
00203                  *             -- w00t (January 06, 2008)
00204                  */
00205                 unsigned int tmp_len = SHA256_BLOCK_SIZE - ctx->len;
00206                 unsigned int rem_len = len < tmp_len ? len : tmp_len;
00207 
00208 
00209                 memcpy(&ctx->block[ctx->len], message, rem_len);
00210                 if (ctx->len + len < SHA256_BLOCK_SIZE)
00211                 {
00212                         ctx->len += len;
00213                         return;
00214                 }
00215                 unsigned int new_len = len - rem_len;
00216                 unsigned int block_nb = new_len / SHA256_BLOCK_SIZE;
00217                 unsigned char *shifted_message = message + rem_len;
00218                 SHA256Transform(ctx, ctx->block, 1);
00219                 SHA256Transform(ctx, shifted_message, block_nb);
00220                 rem_len = new_len % SHA256_BLOCK_SIZE;
00221                 memcpy(ctx->block, &shifted_message[block_nb << 6],rem_len);
00222                 ctx->len = rem_len;
00223                 ctx->tot_len += (block_nb + 1) << 6;
00224         }
00225 
00226         void SHA256Final(SHA256Context *ctx, unsigned char *digest)
00227         {
00228                 unsigned int block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE)));
00229                 unsigned int len_b = (ctx->tot_len + ctx->len) << 3;
00230                 unsigned int pm_len = block_nb << 6;
00231                 memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
00232                 ctx->block[ctx->len] = 0x80;
00233                 UNPACK32(len_b, ctx->block + pm_len - 4);
00234                 SHA256Transform(ctx, ctx->block, block_nb);
00235                 for (int i = 0 ; i < 8; i++)
00236                         UNPACK32(ctx->h[i], &digest[i << 2]);
00237         }
00238 
00239         void SHA256(const char *src, char *dest, int len, const char* hxc, const unsigned int* ikey = NULL)
00240         {
00241                 // Generate the hash
00242                 unsigned char bytehash[SHA256_DIGEST_SIZE];
00243                 SHA256Context ctx;
00244                 SHA256Init(&ctx, ikey);
00245                 SHA256Update(&ctx, (unsigned char *)src, (unsigned int)len);
00246                 SHA256Final(&ctx, bytehash);
00247                 // Convert it to hex
00248                 for (int i = 0, j = 0; i < SHA256_DIGEST_SIZE; i++)
00249                 {
00250                         dest[j++] = hxc[bytehash[i] / 16];
00251                         dest[j++] = hxc[bytehash[i] % 16];
00252                         dest[j] = '\0';
00253                 }
00254         }
00255 
00256         unsigned int* key;
00257         char* chars;
00258 
00259  public:
00260 
00261         ModuleSHA256(InspIRCd* Me) : Module(Me), key(NULL), chars(NULL)
00262         {
00263                 ServerInstance->Modules->PublishInterface("HashRequest", this);
00264                 Implementation eventlist[] = { I_OnRequest };
00265                 ServerInstance->Modules->Attach(eventlist, this, 1);
00266         }
00267 
00268         virtual ~ModuleSHA256()
00269         {
00270                 ServerInstance->Modules->UnpublishInterface("HashRequest", this);
00271         }
00272 
00273 
00274         virtual const char* OnRequest(Request* request)
00275         {
00276                 HashRequest* SHA = (HashRequest*)request;
00277                 if (strcmp("KEY", request->GetId()) == 0)
00278                 {
00279                         this->key = (unsigned int*)SHA->GetKeyData();
00280                 }
00281                 else if (strcmp("HEX", request->GetId()) == 0)
00282                 {
00283                         this->chars = (char*)SHA->GetOutputs();
00284                 }
00285                 else if (strcmp("SUM", request->GetId()) == 0)
00286                 {
00287                         static char data[MAXBUF];
00288                         SHA256((const char*)SHA->GetHashData().data(), data, SHA->GetHashData().length(), chars ? chars : "0123456789abcdef", key);
00289                         return data;
00290                 }
00291                 else if (strcmp("NAME", request->GetId()) == 0)
00292                 {
00293                         return "sha256";
00294                 }
00295                 else if (strcmp("RESET", request->GetId()) == 0)
00296                 {
00297                         this->chars = NULL;
00298                         this->key = NULL;
00299                 }
00300                 return NULL;
00301         }
00302 
00303         virtual Version GetVersion()
00304         {
00305                 return Version("$Id: m_sha256.cpp 10291 2008-08-25 20:35:51Z w00t $", VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION);
00306         }
00307 };
00308 
00309 MODULE_INIT(ModuleSHA256)