Logo Search packages:      
Sourcecode: kmess version File versions  Download package

sha1.cpp

/* sha1.c - SHA1 hash function
 *    Copyright (C) 1998, 2001, 2002 Free Software Foundation, Inc.
 *
 * This file is part of Libgcrypt.
 *
 * Libgcrypt is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * Libgcrypt is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

/* (C) 2002, 2003, 2004 Michael Buesch :
 *   Modified/deleted/added some functions.
 * 2004 further modifications by Michael Jarrett (JudgeBeavis@hotmail.com)
 */

/*  SHA1 Test vectors:
 *
 *  "abc"
 *  A999 3E36 4706 816A BA3E  2571 7850 C26C 9CD0 D89D
 *
 *  "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
 *  8498 3E44 1C3B D26E BAAE  4AA1 F951 29E5 E546 70F1
 */

#include "sha1.h"
#include "bithelp.h"

#include <stdio.h>
#include <sys/stat.h>

#include <cstring>

Sha1::Sha1()
{
      context = new SHA1_CONTEXT;
}

Sha1::~Sha1()
{
      delete context;
}

void Sha1::burn_stack(int bytes)
{
      char buf[128];
      memset(buf, 0, sizeof buf);
      bytes -= sizeof buf;
      if (bytes > 0)
            burn_stack(bytes);
}

void Sha1::sha1_init()
{
      context->h0 = 0x67452301;
      context->h1 = 0xefcdab89;
      context->h2 = 0x98badcfe;
      context->h3 = 0x10325476;
      context->h4 = 0xc3d2e1f0;
      context->nblocks = 0;
      context->count = 0;
}

/****************
 * Transform the message X which consists of 16 32-bit-words
 */
void Sha1::transform(const byte *data)
{
      uint32_t a, b, c, d, e, tm;
      uint32_t x[16];

      /* get values from the chaining vars */
      a = context->h0;
      b = context->h1;
      c = context->h2;
      d = context->h3;
      e = context->h4;

#ifdef BIG_ENDIAN_HOST
      memcpy(x, data, 64);
#else
      {
            int i;
            byte *p2;
            for (i = 0, p2 = (byte *) x; i < 16; i++, p2 += 4) {
                  p2[3] = *data++;
                  p2[2] = *data++;
                  p2[1] = *data++;
                  p2[0] = *data++;
            }
      }
#endif

#define SHA1_K1  0x5A827999L
#define SHA1_K2  0x6ED9EBA1L
#define SHA1_K3  0x8F1BBCDCL
#define SHA1_K4  0xCA62C1D6L
#define SHA1_F1(x,y,z)   ( z ^ ( x & ( y ^ z ) ) )
#define SHA1_F2(x,y,z)   ( x ^ y ^ z )
#define SHA1_F3(x,y,z)   ( ( x & y ) | ( z & ( x | y ) ) )
#define SHA1_F4(x,y,z)   ( x ^ y ^ z )

#define M(i) ( tm =   x[i&0x0f] ^ x[(i-14)&0x0f] \
                ^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f] \
             , (x[i&0x0f] = rol(tm, 1)) )

#define SHA1_R(a,b,c,d,e,f,k,m)  do { e += rol( a, 5 )     \
                              + f( b, c, d )  \
                              + k         \
                              + m;        \
                         b = rol( b, 30 );    \
                         } while(0)
      SHA1_R(a, b, c, d, e, SHA1_F1, SHA1_K1, x[0]);
      SHA1_R(e, a, b, c, d, SHA1_F1, SHA1_K1, x[1]);
      SHA1_R(d, e, a, b, c, SHA1_F1, SHA1_K1, x[2]);
      SHA1_R(c, d, e, a, b, SHA1_F1, SHA1_K1, x[3]);
      SHA1_R(b, c, d, e, a, SHA1_F1, SHA1_K1, x[4]);
      SHA1_R(a, b, c, d, e, SHA1_F1, SHA1_K1, x[5]);
      SHA1_R(e, a, b, c, d, SHA1_F1, SHA1_K1, x[6]);
      SHA1_R(d, e, a, b, c, SHA1_F1, SHA1_K1, x[7]);
      SHA1_R(c, d, e, a, b, SHA1_F1, SHA1_K1, x[8]);
      SHA1_R(b, c, d, e, a, SHA1_F1, SHA1_K1, x[9]);
      SHA1_R(a, b, c, d, e, SHA1_F1, SHA1_K1, x[10]);
      SHA1_R(e, a, b, c, d, SHA1_F1, SHA1_K1, x[11]);
      SHA1_R(d, e, a, b, c, SHA1_F1, SHA1_K1, x[12]);
      SHA1_R(c, d, e, a, b, SHA1_F1, SHA1_K1, x[13]);
      SHA1_R(b, c, d, e, a, SHA1_F1, SHA1_K1, x[14]);
      SHA1_R(a, b, c, d, e, SHA1_F1, SHA1_K1, x[15]);
      SHA1_R(e, a, b, c, d, SHA1_F1, SHA1_K1, M(16));
      SHA1_R(d, e, a, b, c, SHA1_F1, SHA1_K1, M(17));
      SHA1_R(c, d, e, a, b, SHA1_F1, SHA1_K1, M(18));
      SHA1_R(b, c, d, e, a, SHA1_F1, SHA1_K1, M(19));
      SHA1_R(a, b, c, d, e, SHA1_F2, SHA1_K2, M(20));
      SHA1_R(e, a, b, c, d, SHA1_F2, SHA1_K2, M(21));
      SHA1_R(d, e, a, b, c, SHA1_F2, SHA1_K2, M(22));
      SHA1_R(c, d, e, a, b, SHA1_F2, SHA1_K2, M(23));
      SHA1_R(b, c, d, e, a, SHA1_F2, SHA1_K2, M(24));
      SHA1_R(a, b, c, d, e, SHA1_F2, SHA1_K2, M(25));
      SHA1_R(e, a, b, c, d, SHA1_F2, SHA1_K2, M(26));
      SHA1_R(d, e, a, b, c, SHA1_F2, SHA1_K2, M(27));
      SHA1_R(c, d, e, a, b, SHA1_F2, SHA1_K2, M(28));
      SHA1_R(b, c, d, e, a, SHA1_F2, SHA1_K2, M(29));
      SHA1_R(a, b, c, d, e, SHA1_F2, SHA1_K2, M(30));
      SHA1_R(e, a, b, c, d, SHA1_F2, SHA1_K2, M(31));
      SHA1_R(d, e, a, b, c, SHA1_F2, SHA1_K2, M(32));
      SHA1_R(c, d, e, a, b, SHA1_F2, SHA1_K2, M(33));
      SHA1_R(b, c, d, e, a, SHA1_F2, SHA1_K2, M(34));
      SHA1_R(a, b, c, d, e, SHA1_F2, SHA1_K2, M(35));
      SHA1_R(e, a, b, c, d, SHA1_F2, SHA1_K2, M(36));
      SHA1_R(d, e, a, b, c, SHA1_F2, SHA1_K2, M(37));
      SHA1_R(c, d, e, a, b, SHA1_F2, SHA1_K2, M(38));
      SHA1_R(b, c, d, e, a, SHA1_F2, SHA1_K2, M(39));
      SHA1_R(a, b, c, d, e, SHA1_F3, SHA1_K3, M(40));
      SHA1_R(e, a, b, c, d, SHA1_F3, SHA1_K3, M(41));
      SHA1_R(d, e, a, b, c, SHA1_F3, SHA1_K3, M(42));
      SHA1_R(c, d, e, a, b, SHA1_F3, SHA1_K3, M(43));
      SHA1_R(b, c, d, e, a, SHA1_F3, SHA1_K3, M(44));
      SHA1_R(a, b, c, d, e, SHA1_F3, SHA1_K3, M(45));
      SHA1_R(e, a, b, c, d, SHA1_F3, SHA1_K3, M(46));
      SHA1_R(d, e, a, b, c, SHA1_F3, SHA1_K3, M(47));
      SHA1_R(c, d, e, a, b, SHA1_F3, SHA1_K3, M(48));
      SHA1_R(b, c, d, e, a, SHA1_F3, SHA1_K3, M(49));
      SHA1_R(a, b, c, d, e, SHA1_F3, SHA1_K3, M(50));
      SHA1_R(e, a, b, c, d, SHA1_F3, SHA1_K3, M(51));
      SHA1_R(d, e, a, b, c, SHA1_F3, SHA1_K3, M(52));
      SHA1_R(c, d, e, a, b, SHA1_F3, SHA1_K3, M(53));
      SHA1_R(b, c, d, e, a, SHA1_F3, SHA1_K3, M(54));
      SHA1_R(a, b, c, d, e, SHA1_F3, SHA1_K3, M(55));
      SHA1_R(e, a, b, c, d, SHA1_F3, SHA1_K3, M(56));
      SHA1_R(d, e, a, b, c, SHA1_F3, SHA1_K3, M(57));
      SHA1_R(c, d, e, a, b, SHA1_F3, SHA1_K3, M(58));
      SHA1_R(b, c, d, e, a, SHA1_F3, SHA1_K3, M(59));
      SHA1_R(a, b, c, d, e, SHA1_F4, SHA1_K4, M(60));
      SHA1_R(e, a, b, c, d, SHA1_F4, SHA1_K4, M(61));
      SHA1_R(d, e, a, b, c, SHA1_F4, SHA1_K4, M(62));
      SHA1_R(c, d, e, a, b, SHA1_F4, SHA1_K4, M(63));
      SHA1_R(b, c, d, e, a, SHA1_F4, SHA1_K4, M(64));
      SHA1_R(a, b, c, d, e, SHA1_F4, SHA1_K4, M(65));
      SHA1_R(e, a, b, c, d, SHA1_F4, SHA1_K4, M(66));
      SHA1_R(d, e, a, b, c, SHA1_F4, SHA1_K4, M(67));
      SHA1_R(c, d, e, a, b, SHA1_F4, SHA1_K4, M(68));
      SHA1_R(b, c, d, e, a, SHA1_F4, SHA1_K4, M(69));
      SHA1_R(a, b, c, d, e, SHA1_F4, SHA1_K4, M(70));
      SHA1_R(e, a, b, c, d, SHA1_F4, SHA1_K4, M(71));
      SHA1_R(d, e, a, b, c, SHA1_F4, SHA1_K4, M(72));
      SHA1_R(c, d, e, a, b, SHA1_F4, SHA1_K4, M(73));
      SHA1_R(b, c, d, e, a, SHA1_F4, SHA1_K4, M(74));
      SHA1_R(a, b, c, d, e, SHA1_F4, SHA1_K4, M(75));
      SHA1_R(e, a, b, c, d, SHA1_F4, SHA1_K4, M(76));
      SHA1_R(d, e, a, b, c, SHA1_F4, SHA1_K4, M(77));
      SHA1_R(c, d, e, a, b, SHA1_F4, SHA1_K4, M(78));
      SHA1_R(b, c, d, e, a, SHA1_F4, SHA1_K4, M(79));

      /* update chainig vars */
      context->h0 += a;
      context->h1 += b;
      context->h2 += c;
      context->h3 += d;
      context->h4 += e;
}

/* Update the message digest with the contents
 * of INBUF with length INLEN.
 */
void Sha1::sha1_write(const byte *inbuf, size_t inlen)
{
      if (context->count == 64) {   /* flush the buffer */
            transform(context->buf);
            burn_stack(88 + 4 * sizeof(void *));
            context->count = 0;
            context->nblocks++;
      }
      if (unlikely(!inbuf))
            return;
      if (context->count) {
            for (; inlen && context->count < 64; inlen--)
                  context->buf[context->count++] = *inbuf++;
            sha1_write(NULL, 0);
            if (!inlen)
                  return;
      }

      while (inlen >= 64) {
            transform(inbuf);
            context->count = 0;
            context->nblocks++;
            inlen -= 64;
            inbuf += 64;
      }
      burn_stack(88 + 4 * sizeof(void *));
      for (; inlen && context->count < 64; inlen--)
            context->buf[context->count++] = *inbuf++;
}

/* The routine final terminates the computation and
 * returns the digest.
 * The handle is prepared for a new cycle, but adding bytes to the
 * handle will the destroy the returned buffer.
 * Returns: 20 bytes representing the digest.
 */
byte * Sha1::sha1_final()
{
      uint32_t t, msb, lsb;
      byte *p;

      sha1_write(NULL, 0); /* flush */

      t = context->nblocks;
      /* multiply by 64 to make a byte count */
      lsb = t << 6;
      msb = t >> 26;
      /* add the count */
      t = lsb;
      if ((lsb += context->count) < t)
            msb++;
      /* multiply by 8 to make a bit count */
      t = lsb;
      lsb <<= 3;
      msb <<= 3;
      msb |= t >> 29;

      if (context->count < 56) {    /* enough room */
            context->buf[context->count++] = 0x80;    /* pad */
            while (context->count < 56)
                  context->buf[context->count++] = 0; /* pad */
      } else {          /* need one extra block */
            context->buf[context->count++] = 0x80;    /* pad character */
            while (context->count < 64)
                  context->buf[context->count++] = 0;
            sha1_write(NULL, 0); /* flush */
            memset(context->buf, 0, 56);  /* fill next block with zeroes */
      }
      /* append the 64 bit count */
      context->buf[56] = msb >> 24;
      context->buf[57] = msb >> 16;
      context->buf[58] = msb >> 8;
      context->buf[59] = msb;
      context->buf[60] = lsb >> 24;
      context->buf[61] = lsb >> 16;
      context->buf[62] = lsb >> 8;
      context->buf[63] = lsb;
      transform(context->buf);
      burn_stack(88 + 4 * sizeof(void *));

      p = context->buf;
#ifdef BIG_ENDIAN_HOST
#define X(a) do { *(uint32_t*)p = context->h##a ; p += 4; } while(0)
#else                   /* little endian */
#define X(a) do { *p++ = context->h##a >> 24; *p++ = context->h##a >> 16;      \
                  *p++ = context->h##a >> 8; *p++ = context->h##a; } while(0)
#endif
      X(0);
      X(1);
      X(2);
      X(3);
      X(4);
#undef X
      return context->buf;
}

bool Sha1::selfTest()
{
// TODO: Remove me proper
/*
      string test1("abc");
      string test1_md("A9993E364706816ABA3E25717850C26C9CD0D89D");
      string test2("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
      string test2_md("84983E441C3BD26EBAAE4AA1F95129E5E54670F1");
      string test3;
      test3.assign(1000000, 'a');
      string test3_md("34AA973CD4C4DAA4F61EEB2BDBAD27316534016F");

      Sha1 sha1;

      if (unlikely(sha1.calcSha1(test1) != test1_md))
            return false;
      if (unlikely(sha1.calcSha1(test2) != test2_md))
            return false;
      if (unlikely(sha1.calcSha1(test3) != test3_md))
            return false;
*/
      return true;
}

byte *Sha1::calcSha1(const byte *buf, int len)
{
      sha1_init();
      sha1_write(buf, len);
      return sha1_final();
}


Generated by  Doxygen 1.6.0   Back to index