Fork of François Berder Crypto, fixed AES CBC and small rework

Dependents:   AES_example shaun_larada Smartage

Fork of Crypto by Francois Berder

SHA1.cpp

Committer:
feb11
Date:
2013-09-09
Revision:
1:14a7cea431aa
Parent:
0:7a1237bd2d13
Child:
2:473bac39ae7c

File content as of revision 1:14a7cea431aa:

#include "SHA1.h"
#include <string.h>

static uint32_t f(uint8_t t, uint32_t B, uint32_t C, uint32_t D)
{
    if(t <= 19)
        return (B & C) | ((~B) & D);
    else if(t <= 39)
        return B ^ C ^ D;
    else if(t <= 59)
        return (B & C) | (B & D) | (C & D);
    else if(t <= 79)
        return B ^ C ^ D;
    
    return 0;
}

static uint32_t K(uint8_t t)
{
    if(t <= 19)
      return 0x5A827999;
    else if(t <= 39)
      return 0x6ED9EBA1;
    else if(t <= 59)
      return 0x8F1BBCDC;
    else if(t <= 79)
      return 0xCA62C1D6;
    
    return 0;
}

static uint32_t rotLeft(uint32_t w, uint8_t n)
{
    return (w << n) | (w >> (32-n));
}

static const uint32_t H0 = 0x67452301;
static const uint32_t H1 = 0xEFCDAB89;
static const uint32_t H2 = 0x98BADCFE;
static const uint32_t H3 = 0x10325476;
static const uint32_t H4 = 0xC3D2E1F0;
static const uint32_t MASK = 0x0000000F;


SHA1::SHA1():
HashAlgorithm(),
h0(H0),
h1(H1),
h2(H2),
h3(H3),
h4(H4),
totalBufferLength(0),
buffer(),
bufferLength(0)
{
}

uint8_t SHA1::outputSize() const
{
    return 20;
}

void SHA1::add(uint8_t *in, uint32_t length)
{
    if(length < 64-bufferLength)
    {
        memcpy(&buffer[bufferLength], in, length);
        bufferLength += length;
        totalBufferLength += length;
        return;
    }
    int offset = 64-bufferLength;
    memcpy(&buffer[bufferLength], in, offset);
    computeBlock(&h0,&h1,&h2,&h3,&h4, buffer);
    while(length-offset > 64)
    {
        memcpy(buffer, &in[offset], 64);
        computeBlock(&h0,&h1,&h2,&h3,&h4, buffer);
        offset += 64;
    }
    if(offset > length)
        offset -= 64;
    bufferLength = length - offset;
    memcpy(buffer, &in[offset], bufferLength);
    totalBufferLength += length;
}

void SHA1::computeDigest(uint8_t *digest)
{
    uint16_t padding;
    if(totalBufferLength % 64 < 56)
        padding = 56 - (totalBufferLength % 64);
    else
        padding = 56 + (64 - (totalBufferLength % 64));
    uint8_t val = 0x80;
    add(&val, 1);
    val = 0;
    for(int i = 0; i < padding-1; ++i)
        add(&val,1);
    totalBufferLength -= padding;
    uint64_t lengthBit = totalBufferLength * 8;
    uint32_t lengthBitLow = lengthBit;
    uint32_t lengthBitHigh = lengthBit >> 32;
    uint8_t l[4];

    l[0] = lengthBitHigh >> 24;
    l[1] = lengthBitHigh >> 16;
    l[2] = lengthBitHigh >> 8;
    l[3] = lengthBitHigh;
    add(l, 4);
    l[0] = lengthBitLow >> 24;
    l[1] = lengthBitLow >> 16;
    l[2] = lengthBitLow >> 8;
    l[3] = lengthBitLow;
    add(l, 4);

    digest[0] = h0 >> 24;
    digest[1] = h0 >> 16;
    digest[2] = h0 >> 8;
    digest[3] = h0;
    digest[4] = h1 >> 24;
    digest[5] = h1 >> 16;
    digest[6] = h1 >> 8;
    digest[7] = h1;
    digest[8] = h2 >> 24;
    digest[9] = h2 >> 16;
    digest[10] = h2 >> 8;
    digest[11] = h2;
    digest[12] = h3 >> 24;
    digest[13] = h3 >> 16;
    digest[14] = h3 >> 8;
    digest[15] = h3;
    digest[16] = h4 >> 24;
    digest[17] = h4 >> 16;
    digest[18] = h4 >> 8;
    digest[19] = h4;
    
    // reset state
    h0 = H0;
    h1 = H1;
    h2 = H2;
    h3 = H3;
    h4 = H4;
    totalBufferLength = 0;
    bufferLength = 0;
}

void SHA1::computeBlock(uint32_t *h02, uint32_t *h12, uint32_t *h22, uint32_t *h32, uint32_t *h42, uint8_t *buffer)
{
    uint32_t w[16];
    for(int j = 0; j < 16; ++j)
        w[j] = (buffer[j*4] << 24) | (buffer[j*4+1] << 16) | (buffer[j*4+2] << 8) | buffer[j*4+3];
    
    uint32_t a = *h02, b = *h12, c = *h22, d = *h32, e = *h42;
    for(uint8_t t = 0; t < 80; ++t)
    {
        uint32_t s = t & MASK;
        if(t >= 16)
        {
            w[s%16] = w[((s + 13) & MASK)%16] ^ w[((s + 8) & MASK)%16] ^ w[((s + 2) & MASK)%16] ^ w[s%16];
            w[s%16] = rotLeft(w[s%16], 1);
        }
        
        uint32_t temp = rotLeft(a, 5) + f(t, b, c, d) + e + w[s%16] + K(t);
        e = d;
        d = c;
        c = rotLeft(b,30);
        b = a;
        a = temp;
    }
    *h02 += a;
    *h12 += b;
    *h22 += c;
    *h32 += d;
    *h42 += e;
}



/* method 2 */
void SHA1::computeDigest(uint8_t *digest, uint8_t *in, uint32_t length)
{
    uint16_t padding;
    if(length % 64 < 56)
        padding = 56 - (length % 64);
    else
        padding = 56 + (64 - (length % 64));
        
    uint32_t h0 = H0, h1 = H1, h2 = H2, h3 = H3, h4 = H4;
    uint32_t offset = 0;
    while(length - offset >= 64)
    {
        computeBlock(&h0,&h1,&h2,&h3,&h4, &in[offset]);
        offset += 64;
    }

    uint8_t bufferLength = length - offset;
    uint8_t buffer[64];
    memcpy(buffer, &in[offset], bufferLength);
    buffer[bufferLength++] = 0x80;
    padding--;
    while(padding > 0)
    {
        if(bufferLength == 64)
        {
            computeBlock(&h0,&h1,&h2,&h3,&h4, buffer);
            bufferLength++;
        }
        buffer[bufferLength++] = 0;
        padding--;
    }
    uint64_t lengthBit = length * 8;
    uint32_t lengthBitLow = lengthBit;
    uint32_t lengthBitHigh = lengthBit >> 32;
    uint8_t l[4];
    l[0] = lengthBitLow >> 24;
    l[1] = lengthBitLow >> 16;
    l[2] = lengthBitLow >> 8;
    l[3] = lengthBitLow;
    memcpy(&buffer[60], l, 4);
    l[0] = lengthBitHigh >> 24;
    l[1] = lengthBitHigh >> 16;
    l[2] = lengthBitHigh >> 8;
    l[3] = lengthBitHigh;
    memcpy(&buffer[56], l, 4);
    
    computeBlock(&h0,&h1,&h2,&h3,&h4, buffer);

    digest[0] = h0 >> 24;
    digest[1] = h0 >> 16;
    digest[2] = h0 >> 8;
    digest[3] = h0;
    digest[4] = h1 >> 24;
    digest[5] = h1 >> 16;
    digest[6] = h1 >> 8;
    digest[7] = h1;
    digest[8] = h2 >> 24;
    digest[9] = h2 >> 16;
    digest[10] = h2 >> 8;
    digest[11] = h2;
    digest[12] = h3 >> 24;
    digest[13] = h3 >> 16;
    digest[14] = h3 >> 8;
    digest[15] = h3;
    digest[16] = h4 >> 24;
    digest[17] = h4 >> 16;
    digest[18] = h4 >> 8;
    digest[19] = h4;
}