Back to home page

Enduro/X

 
 

    


0001 /*
0002 SHA-1 in C
0003 By Steve Reid <steve@edmweb.com>
0004 100% Public Domain
0005 
0006 Test Vectors (from FIPS PUB 180-1)
0007 "abc"
0008   A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
0009 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
0010   84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
0011 A million repetitions of "a"
0012   34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
0013 */
0014 
0015 /* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
0016 /* #define EXSHA1HANDSOFF * Copies data before messing with it. */
0017 
0018 #define EXSHA1HANDSOFF
0019 
0020 #include <stdio.h>
0021 #include <string.h>
0022 
0023 /* for uint32_t */
0024 #include <stdint.h>
0025 
0026 #include "exsha1.h"
0027 
0028 
0029 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
0030 
0031 /* blk0() and blk() perform the initial expand. */
0032 /* I got the idea of expanding during the round function from SSLeay */
0033 #if BYTE_ORDER == LITTLE_ENDIAN
0034 #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
0035     |(rol(block->l[i],8)&0x00FF00FF))
0036 #elif BYTE_ORDER == BIG_ENDIAN
0037 #define blk0(i) block->l[i]
0038 #else
0039 #error "Endianness not defined!"
0040 #endif
0041 #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
0042     ^block->l[(i+2)&15]^block->l[i&15],1))
0043 
0044 /* (R0+R1), R2, R3, R4 are the different operations used in EXSHA1 */
0045 #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
0046 #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
0047 #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
0048 #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
0049 #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
0050 
0051 
0052 /* Hash a single 512-bit block. This is the core of the algorithm. */
0053 
0054 void EXSHA1Transform(
0055     uint32_t state[5],
0056     const unsigned char buffer[64]
0057 )
0058 {
0059     uint32_t a, b, c, d, e;
0060 
0061     typedef union
0062     {
0063         unsigned char c[64];
0064         uint32_t l[16];
0065     } CHAR64LONG16;
0066 
0067 #ifdef EXSHA1HANDSOFF
0068     CHAR64LONG16 block[1];      /* use array to appear as a pointer */
0069 
0070     memcpy(block, buffer, 64);
0071 #else
0072     /* The following had better never be used because it causes the
0073      * pointer-to-const buffer to be cast into a pointer to non-const.
0074      * And the result is written through.  I threw a "const" in, hoping
0075      * this will cause a diagnostic.
0076      */
0077     CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer;
0078 #endif
0079     /* Copy context->state[] to working vars */
0080     a = state[0];
0081     b = state[1];
0082     c = state[2];
0083     d = state[3];
0084     e = state[4];
0085     /* 4 rounds of 20 operations each. Loop unrolled. */
0086     R0(a, b, c, d, e, 0);
0087     R0(e, a, b, c, d, 1);
0088     R0(d, e, a, b, c, 2);
0089     R0(c, d, e, a, b, 3);
0090     R0(b, c, d, e, a, 4);
0091     R0(a, b, c, d, e, 5);
0092     R0(e, a, b, c, d, 6);
0093     R0(d, e, a, b, c, 7);
0094     R0(c, d, e, a, b, 8);
0095     R0(b, c, d, e, a, 9);
0096     R0(a, b, c, d, e, 10);
0097     R0(e, a, b, c, d, 11);
0098     R0(d, e, a, b, c, 12);
0099     R0(c, d, e, a, b, 13);
0100     R0(b, c, d, e, a, 14);
0101     R0(a, b, c, d, e, 15);
0102     R1(e, a, b, c, d, 16);
0103     R1(d, e, a, b, c, 17);
0104     R1(c, d, e, a, b, 18);
0105     R1(b, c, d, e, a, 19);
0106     R2(a, b, c, d, e, 20);
0107     R2(e, a, b, c, d, 21);
0108     R2(d, e, a, b, c, 22);
0109     R2(c, d, e, a, b, 23);
0110     R2(b, c, d, e, a, 24);
0111     R2(a, b, c, d, e, 25);
0112     R2(e, a, b, c, d, 26);
0113     R2(d, e, a, b, c, 27);
0114     R2(c, d, e, a, b, 28);
0115     R2(b, c, d, e, a, 29);
0116     R2(a, b, c, d, e, 30);
0117     R2(e, a, b, c, d, 31);
0118     R2(d, e, a, b, c, 32);
0119     R2(c, d, e, a, b, 33);
0120     R2(b, c, d, e, a, 34);
0121     R2(a, b, c, d, e, 35);
0122     R2(e, a, b, c, d, 36);
0123     R2(d, e, a, b, c, 37);
0124     R2(c, d, e, a, b, 38);
0125     R2(b, c, d, e, a, 39);
0126     R3(a, b, c, d, e, 40);
0127     R3(e, a, b, c, d, 41);
0128     R3(d, e, a, b, c, 42);
0129     R3(c, d, e, a, b, 43);
0130     R3(b, c, d, e, a, 44);
0131     R3(a, b, c, d, e, 45);
0132     R3(e, a, b, c, d, 46);
0133     R3(d, e, a, b, c, 47);
0134     R3(c, d, e, a, b, 48);
0135     R3(b, c, d, e, a, 49);
0136     R3(a, b, c, d, e, 50);
0137     R3(e, a, b, c, d, 51);
0138     R3(d, e, a, b, c, 52);
0139     R3(c, d, e, a, b, 53);
0140     R3(b, c, d, e, a, 54);
0141     R3(a, b, c, d, e, 55);
0142     R3(e, a, b, c, d, 56);
0143     R3(d, e, a, b, c, 57);
0144     R3(c, d, e, a, b, 58);
0145     R3(b, c, d, e, a, 59);
0146     R4(a, b, c, d, e, 60);
0147     R4(e, a, b, c, d, 61);
0148     R4(d, e, a, b, c, 62);
0149     R4(c, d, e, a, b, 63);
0150     R4(b, c, d, e, a, 64);
0151     R4(a, b, c, d, e, 65);
0152     R4(e, a, b, c, d, 66);
0153     R4(d, e, a, b, c, 67);
0154     R4(c, d, e, a, b, 68);
0155     R4(b, c, d, e, a, 69);
0156     R4(a, b, c, d, e, 70);
0157     R4(e, a, b, c, d, 71);
0158     R4(d, e, a, b, c, 72);
0159     R4(c, d, e, a, b, 73);
0160     R4(b, c, d, e, a, 74);
0161     R4(a, b, c, d, e, 75);
0162     R4(e, a, b, c, d, 76);
0163     R4(d, e, a, b, c, 77);
0164     R4(c, d, e, a, b, 78);
0165     R4(b, c, d, e, a, 79);
0166     /* Add the working vars back into context.state[] */
0167     state[0] += a;
0168     state[1] += b;
0169     state[2] += c;
0170     state[3] += d;
0171     state[4] += e;
0172     /* Wipe variables */
0173     a = b = c = d = e = 0;
0174 #ifdef EXSHA1HANDSOFF
0175     memset(block, '\0', sizeof(block));
0176 #endif
0177 }
0178 
0179 
0180 /* EXSHA1Init - Initialize new context */
0181 
0182 void EXSHA1Init(
0183     EXSHA1_CTX * context
0184 )
0185 {
0186     /* EXSHA1 initialization constants */
0187     context->state[0] = 0x67452301;
0188     context->state[1] = 0xEFCDAB89;
0189     context->state[2] = 0x98BADCFE;
0190     context->state[3] = 0x10325476;
0191     context->state[4] = 0xC3D2E1F0;
0192     context->count[0] = context->count[1] = 0;
0193 }
0194 
0195 
0196 /* Run your data through this. */
0197 
0198 void EXSHA1Update(
0199     EXSHA1_CTX * context,
0200     const unsigned char *data,
0201     uint32_t len
0202 )
0203 {
0204     uint32_t i;
0205 
0206     uint32_t j;
0207 
0208     j = context->count[0];
0209     if ((context->count[0] += len << 3) < j)
0210         context->count[1]++;
0211     context->count[1] += (len >> 29);
0212     j = (j >> 3) & 63;
0213     if ((j + len) > 63)
0214     {
0215         memcpy(&context->buffer[j], data, (i = 64 - j));
0216         EXSHA1Transform(context->state, context->buffer);
0217         for (; i + 63 < len; i += 64)
0218         {
0219             EXSHA1Transform(context->state, &data[i]);
0220         }
0221         j = 0;
0222     }
0223     else
0224         i = 0;
0225     memcpy(&context->buffer[j], &data[i], len - i);
0226 }
0227 
0228 
0229 /* Add padding and return the message digest. */
0230 
0231 void EXSHA1Final(
0232     unsigned char digest[20],
0233     EXSHA1_CTX * context
0234 )
0235 {
0236     unsigned i;
0237 
0238     unsigned char finalcount[8];
0239 
0240     unsigned char c;
0241 
0242 #if 0    /* untested "improvement" by DHR */
0243     /* Convert context->count to a sequence of bytes
0244      * in finalcount.  Second element first, but
0245      * big-endian order within element.
0246      * But we do it all backwards.
0247      */
0248     unsigned char *fcp = &finalcount[8];
0249 
0250     for (i = 0; i < 2; i++)
0251     {
0252         uint32_t t = context->count[i];
0253 
0254         int j;
0255 
0256         for (j = 0; j < 4; t >>= 8, j++)
0257             *--fcp = (unsigned char) t}
0258 #else
0259     for (i = 0; i < 8; i++)
0260     {
0261         finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255);      /* Endian independent */
0262     }
0263 #endif
0264     c = 0200;
0265     EXSHA1Update(context, &c, 1);
0266     while ((context->count[0] & 504) != 448)
0267     {
0268         c = 0000;
0269         EXSHA1Update(context, &c, 1);
0270     }
0271     EXSHA1Update(context, finalcount, 8); /* Should cause a EXSHA1Transform() */
0272     for (i = 0; i < 20; i++)
0273     {
0274         digest[i] = (unsigned char)
0275             ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
0276     }
0277     /* Wipe variables */
0278     memset(context, '\0', sizeof(*context));
0279     memset(&finalcount, '\0', sizeof(finalcount));
0280 }
0281 
0282 void EXSHA1(
0283     char *hash_out,
0284     const char *str,
0285     int len)
0286 {
0287     EXSHA1_CTX ctx;
0288     unsigned int ii;
0289 
0290     EXSHA1Init(&ctx);
0291     for (ii=0; ii<len; ii+=1)
0292         EXSHA1Update(&ctx, (const unsigned char*)str + ii, 1);
0293     EXSHA1Final((unsigned char *)hash_out, &ctx);
0294     hash_out[20] = '\0';
0295 }
0296