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

Dependents:   AES_example shaun_larada Smartage

Fork of Crypto by Francois Berder

MD5.cpp

Committer:
feb11
Date:
2013-09-07
Revision:
0:7a1237bd2d13
Child:
1:14a7cea431aa

File content as of revision 0:7a1237bd2d13:

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

static const uint32_t T[] =
{
    0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
    0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
    0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
    0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
    0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
    0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
    0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
    0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
    0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
    0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
    0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
    0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
    0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
    0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
    0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
    0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
};

static const uint32_t A = 0x67452301;
static const uint32_t B = 0xefcdab89;
static const uint32_t C = 0x98badcfe;
static const uint32_t D = 0x10325476;

static uint32_t F(uint32_t x, uint32_t y, uint32_t z)
{
    return (x & y) | ((~x) & z);
}

static uint32_t G(uint32_t x, uint32_t y, uint32_t z)
{
    return (x & z) | (y & (~z));
}

static uint32_t H(uint32_t x, uint32_t y, uint32_t z)
{
    return x ^ y ^ z;
}

static uint32_t I(uint32_t x, uint32_t y, uint32_t z)
{
    return y ^ (x | (~z));
}

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

#define ROUND1(a,b,c,d,k,s,i) \
    a += F(b,c,d) + x[k] + T[i-1]; \
    a = rotLeft(a,s);\
    a += b;
#define ROUND2(a,b,c,d,k,s,i) \
    a += G(b,c,d) + x[k] + T[i-1]; \
    a = rotLeft(a,s);\
    a += b;
#define ROUND3(a,b,c,d,k,s,i) \
    a += H(b,c,d) + x[k] + T[i-1]; \
    a = rotLeft(a,s);\
    a += b;
#define ROUND4(a,b,c,d,k,s,i) \
    a += I(b,c,d) + x[k] + T[i-1]; \
    a = rotLeft(a,s);\
    a += b;

    
MD5::MD5():
HashAlgorithm(),
a(A),
b(B),
c(C),
d(D),
totalBufferLength(0),
buffer(),
bufferLength(0)
{
}

uint8_t MD5::outputSize() const
{
    return 16;
}

void MD5::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);
    uint32_t tmpA = a, tmpB = b, tmpC = c, tmpD = d;
    computeRounds(&a, &b, &c, &d, buffer);
    a += tmpA;
    b += tmpB;
    c += tmpC;
    d += tmpD;
    while(length-offset > 64)
    {
        memcpy(buffer, &in[offset], 64);
        tmpA = a;
        tmpB = b;
        tmpC = c;
        tmpD = d;
        computeRounds(&a, &b, &c, &d, buffer);
        a += tmpA;
        b += tmpB;
        c += tmpC;
        d += tmpD;      
        offset += 64;
    }
    if(offset > length)
        offset -= 64;
    bufferLength = length - offset;
    memcpy(buffer, &in[offset], bufferLength);
    totalBufferLength += length;
}

void MD5::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;
    add((uint8_t*)&lengthBitLow,4);
    add((uint8_t*)&lengthBitHigh,4);

    memcpy(digest, &a, 4);
    memcpy(&digest[4], &b, 4);
    memcpy(&digest[8], &c, 4);
    memcpy(&digest[12], &d, 4);
    // reset state
    a = A;
    b = B;
    c = C;
    d = D;
    totalBufferLength = 0;
    bufferLength = 0;
}

void MD5::computeRounds(uint32_t *a2, uint32_t *b2, uint32_t *c2, uint32_t *d2, uint8_t *buffer)
{
    uint32_t a = *a2, b = *b2, c = *c2, d = *d2;
    uint32_t x[16];
    for(int j = 0; j < 16; ++j)
        memcpy(&x[j], &buffer[j*4], 4); 
        
    // Round 1
    ROUND1(a,b,c,d,0,7,1);      ROUND1(d,a,b,c,1,12,2);     ROUND1(c,d,a,b,2,17,3);     ROUND1(b,c,d,a,3,22,4);
    ROUND1(a,b,c,d,4,7,5);      ROUND1(d,a,b,c,5,12,6);     ROUND1(c,d,a,b,6,17,7);     ROUND1(b,c,d,a,7,22,8);
    ROUND1(a,b,c,d,8,7,9);      ROUND1(d,a,b,c,9,12,10);    ROUND1(c,d,a,b,10,17,11);   ROUND1(b,c,d,a,11,22,12);
    ROUND1(a,b,c,d,12,7,13);    ROUND1(d,a,b,c,13,12,14);   ROUND1(c,d,a,b,14,17,15);   ROUND1(b,c,d,a,15,22,16);
    
    // Round 2      
    ROUND2(a,b,c,d,1,5,17);     ROUND2(d,a,b,c,6,9,18);     ROUND2(c,d,a,b,11,14,19);   ROUND2(b,c,d,a,0,20,20);
    ROUND2(a,b,c,d,5,5,21);     ROUND2(d,a,b,c,10,9,22);    ROUND2(c,d,a,b,15,14,23);   ROUND2(b,c,d,a,4,20,24);
    ROUND2(a,b,c,d,9,5,25);     ROUND2(d,a,b,c,14,9,26);    ROUND2(c,d,a,b,3,14,27);    ROUND2(b,c,d,a,8,20,28);
    ROUND2(a,b,c,d,13,5,29);    ROUND2(d,a,b,c,2,9,30);     ROUND2(c,d,a,b,7,14,31);    ROUND2(b,c,d,a,12,20,32);
    
    // Round 3      
    ROUND3(a,b,c,d,5,4,33);     ROUND3(d,a,b,c,8,11,34);    ROUND3(c,d,a,b,11,16,35);   ROUND3(b,c,d,a,14,23,36);
    ROUND3(a,b,c,d,1,4,37);     ROUND3(d,a,b,c,4,11,38);    ROUND3(c,d,a,b,7,16,39);    ROUND3(b,c,d,a,10,23,40);
    ROUND3(a,b,c,d,13,4,41);    ROUND3(d,a,b,c,0,11,42);    ROUND3(c,d,a,b,3,16,43);    ROUND3(b,c,d,a,6,23,44);
    ROUND3(a,b,c,d,9,4,45);     ROUND3(d,a,b,c,12,11,46);   ROUND3(c,d,a,b,15,16,47);   ROUND3(b,c,d,a,2,23,48);
    
    // Round 4
    ROUND4(a,b,c,d,0,6,49);     ROUND4(d,a,b,c,7,10,50);    ROUND4(c,d,a,b,14,15,51);   ROUND4(b,c,d,a,5,21,52);
    ROUND4(a,b,c,d,12,6,53);    ROUND4(d,a,b,c,3,10,54);    ROUND4(c,d,a,b,10,15,55);   ROUND4(b,c,d,a,1,21,56);
    ROUND4(a,b,c,d,8,6,57);     ROUND4(d,a,b,c,15,10,58);   ROUND4(c,d,a,b,6,15,59);    ROUND4(b,c,d,a,13,21,60);
    ROUND4(a,b,c,d,4,6,61);     ROUND4(d,a,b,c,11,10,62);   ROUND4(c,d,a,b,2,15,63);    ROUND4(b,c,d,a,9,21,64);

    *a2 = a;
    *b2 = b;
    *c2 = c;
    *d2 = d;
}

void MD5::computeDigest(uint8_t *digest, uint8_t *msg, uint32_t length)
{
    uint16_t padding;
    if(length % 64 < 56)
        padding = 56 - (length % 64);
    else
        padding = 56 + (64 - (length % 64));
    uint32_t totalLength = length + padding + 8;
    uint8_t *buffer = new uint8_t[totalLength];
    memcpy(buffer, msg, length);
    buffer[length] = 0x80;
    memset(&buffer[length+1], 0, padding-1);
    uint64_t lengthBit = length * 8;
    uint32_t lengthBitLow = lengthBit;
    uint32_t lengthBitHigh = lengthBit >> 32;
    memcpy(&buffer[length+padding], &lengthBitLow, 4);
    memcpy(&buffer[length+padding+4], &lengthBitHigh, 4);
    
    uint32_t a = A, b = B, c = C, d = D;
    for(int i = 0; i < totalLength/64; ++i)
    {   
        uint32_t tmpA = a, tmpB = b, tmpC = c, tmpD = d;
        computeRounds(&a, &b, &c, &d, &buffer[64*i]);
        
        a += tmpA;
        b += tmpB;
        c += tmpC;
        d += tmpD;
    }
    delete[] buffer;

    memcpy(digest, &a, 4);
    memcpy(&digest[4], &b, 4);
    memcpy(&digest[8], &c, 4);
    memcpy(&digest[12], &d, 4);
}