/***********************************************************
*       libsrs_alt - A simple SRS implementation           *
***********************************************************/

/* (C)2004 Miles Wilton <miles@mirtol.com> */

/* License: GPL */

/* This file:

   sha1.c

   Perform SHA1
*/

#include <string.h>

#include "sha1.h"


/* mHMAC Structure */

mHMAC_DIGEST mHMACD_SHA1 = {
    64,
    20,
    sizeof(mSHA1),
    mSHA1_start,
    mSHA1_block,
    mSHA1_process,
    mSHA1_end
};


/***********************************************************
    mSHA1_start - Init SHA1 structure

*/

int mSHA1_start(mSHA1 *sha1)
{
    sha1->len = 0;
    sha1->blen = 0;
    sha1->H[0] = 0x67452301;
    sha1->H[1] = 0xEFCDAB89;
    sha1->H[2] = 0x98BADCFE;
    sha1->H[3] = 0x10325476;
    sha1->H[4] = 0xC3D2E1F0;

    return 0;
}


/***********************************************************
    mSHA1_block - Process 512-bit block

*/

int mSHA1_block(mSHA1 *sha1, unsigned char *block)
{
    unsigned long A, B, C, D, E;
    unsigned long W[80];
    int t;

    // Compute Ws
    for(t = 0; t < 16; t++)
    {
        W[t] = (block[0] << 24) | (block[1] << 16) | (block[2] << 8) | block[3]; // Ensure byte order
        block += 4;
    }
    for(t = 16; t < 80; t++)
    {
        register unsigned long X = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16];
        W[t] = (X << 1) | (X >> 31);
    }

    A = sha1->H[0];
    B = sha1->H[1];
    C = sha1->H[2];
    D = sha1->H[3];
    E = sha1->H[4];

    // Digest (in 4 runs for different f-functions/K-values)
    for(t = 0; t < 20; t++)
    {
        register unsigned long TEMP = ((A << 5) | (A >> 27)) + ((B & C) | ((~B) & D)) + E + W[t] + 0x5A827999;
        E = D;
        D = C;
        C = (B << 30) | (B >> 2);
        B = A;
        A = TEMP;
    }
    for(; t < 40; t++)
    {
        register unsigned long TEMP = ((A << 5) | (A >> 27)) + (B ^ C ^ D) + E + W[t] + 0x6ED9EBA1;
        E = D;
        D = C;
        C = (B << 30) | (B >> 2);
        B = A;
        A = TEMP;
    }
    for(; t < 60; t++)
    {
        register unsigned long TEMP = ((A << 5) | (A >> 27)) + ((B & C) | (B & D) | (C & D)) + E + W[t] + 0x8F1BBCDC;
        E = D;
        D = C;
        C = (B << 30) | (B >> 2);
        B = A;
        A = TEMP;
    }
    for(; t < 80; t++)
    {
        register unsigned long TEMP = ((A << 5) | (A >> 27)) + (B ^ C ^ D) + E + W[t] + 0xCA62C1D6;
        E = D;
        D = C;
        C = (B << 30) | (B >> 2);
        B = A;
        A = TEMP;
    }

    // Update hash
    sha1->H[0] += A;
    sha1->H[1] += B;
    sha1->H[2] += C;
    sha1->H[3] += D;
    sha1->H[4] += E;

    return 0;
}


/***********************************************************
    mSHA1_process - Add a string to hash

*/
int mSHA1_process(mSHA1 *sha1, unsigned char *data, int data_len)
{
    int b, n = 0;

    // Fulfill buffered data obligations
    if(sha1->blen)
    {
        b = 64 - sha1->blen;
        if(b > data_len)
        {
            // Just add data to buffer and return
            memcpy(&sha1->b[sha1->blen], data, data_len);
            sha1->blen += data_len;
            return 0;
        }
        else
        {
            // Fill buffer and process block
            memcpy(&sha1->b[sha1->blen], data, b);
            n += b;
            mSHA1_block(sha1, sha1->b);
        }
    }

    // Go until we don't have a full block
    while(data_len - n >= 64)
    {
        mSHA1_block(sha1, &data[n]);
        sha1->len += 512;
        n += 64;
    }

    // copy remaining data to buffer
    sha1->blen = data_len - n;
    memcpy(sha1->b, &data[n], sha1->blen);

    return 0;
}


/***********************************************************
    mSHA1_end - Finalise hash

*/
int mSHA1_end(mSHA1 *sha1, unsigned char *hash_buffer)
{
    // sha1->blen should _NEVER_ be 64
    sha1->b[sha1->blen] = 0x80;

    // Calculate final length
    sha1->len += sha1->blen << 3;

    // Pad remaining data
    if(sha1->blen > 55)
    {
        memset(&sha1->b[sha1->blen+1], 0, 63 - sha1->blen);
        mSHA1_block(sha1, sha1->b);

        memset(sha1->b, 0, 56);
    }
    else
        memset(&sha1->b[sha1->blen+1], 0, 55 - sha1->blen);

    // Add length (ensuring byte order)
    sha1->b[56] = (sha1->len >> 56) & 0xFF;
    sha1->b[57] = (sha1->len >> 48) & 0xFF;
    sha1->b[58] = (sha1->len >> 40) & 0xFF;
    sha1->b[59] = (sha1->len >> 32) & 0xFF;
    sha1->b[60] = (sha1->len >> 24) & 0xFF;
    sha1->b[61] = (sha1->len >> 16) & 0xFF;
    sha1->b[62] = (sha1->len >> 8) & 0xFF;
    sha1->b[63] = sha1->len & 0xFF;

    // Process final block
    mSHA1_block(sha1, sha1->b);

    // Get hash
    if(hash_buffer)
        mSHA1_gethash(sha1, hash_buffer);

    return 0;
}


/***********************************************************
    mSHA1_gethash - Get hash string (fills 20 bytes)

*/
int mSHA1_gethash(mSHA1 *sha1, unsigned char *hash_buffer)
{
    int n;

    for(n = 0; n < 5; n++)
    {
        *hash_buffer++ = (sha1->H[n] >> 24) & 0xFF;
        *hash_buffer++ = (sha1->H[n] >> 16) & 0xFF;
        *hash_buffer++ = (sha1->H[n] >> 8) & 0xFF;
        *hash_buffer++ = sha1->H[n] & 0xFF;
    }

    return 0;
}




syntax highlighted by Code2HTML, v. 0.9.1