md5.c

Go to the documentation of this file.
00001 /* 
00002  * Cryptographic API.
00003  *
00004  * MD5 Message Digest Algorithm (RFC1321).
00005  *
00006  * Derived from cryptoapi implementation, originally based on the
00007  * public domain implementation written by Colin Plumb in 1993.
00008  *
00009  * Reduced object size by around 50% compared to the original Linux
00010  * version for use in Etherboot by Michael Brown.
00011  *
00012  * Copyright (c) Cryptoapi developers.
00013  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
00014  * Copyright (c) 2006 Michael Brown <mbrown@fensystems.co.uk>
00015  * 
00016  * This program is free software; you can redistribute it and/or modify it
00017  * under the terms of the GNU General Public License as published by the Free
00018  * Software Foundation; either version 2 of the License, or (at your option) 
00019  * any later version.
00020  *
00021  */
00022 
00023 FILE_LICENCE ( GPL2_OR_LATER );
00024 
00025 #include <stdint.h>
00026 #include <string.h>
00027 #include <byteswap.h>
00028 #include <gpxe/crypto.h>
00029 #include <gpxe/md5.h>
00030 
00031 struct md5_step {
00032         u32 ( * f ) ( u32 b, u32 c, u32 d );
00033         u8 coefficient;
00034         u8 constant;
00035 };
00036 
00037 static u32 f1(u32 b, u32 c, u32 d)
00038 {
00039         return ( d ^ ( b & ( c ^ d ) ) );
00040 }
00041 
00042 static u32 f2(u32 b, u32 c, u32 d)
00043 {
00044         return ( c ^ ( d & ( b ^ c ) ) );
00045 }
00046 
00047 static u32 f3(u32 b, u32 c, u32 d)
00048 {
00049         return ( b ^ c ^ d );
00050 }
00051 
00052 static u32 f4(u32 b, u32 c, u32 d)
00053 {
00054         return ( c ^ ( b | ~d ) );
00055 }
00056 
00057 static struct md5_step md5_steps[4] = {
00058         {
00059                 .f = f1,
00060                 .coefficient = 1,
00061                 .constant = 0,
00062         },
00063         {
00064                 .f = f2,
00065                 .coefficient = 5,
00066                 .constant = 1,
00067         },
00068         {
00069                 .f = f3,
00070                 .coefficient = 3,
00071                 .constant = 5,
00072         },
00073         {
00074                 .f = f4,
00075                 .coefficient = 7,
00076                 .constant = 0,
00077         }
00078 };
00079 
00080 static const u8 r[64] = {
00081         7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
00082         5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
00083         4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
00084         6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
00085 };
00086 
00087 static const u32 k[64] = {
00088         0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL,
00089         0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
00090         0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL,
00091         0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
00092         0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL,
00093         0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
00094         0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL,
00095         0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
00096         0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL,
00097         0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
00098         0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL,
00099         0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
00100         0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL,
00101         0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
00102         0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL,
00103         0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL,
00104 };
00105 
00106 static void md5_transform(u32 *hash, const u32 *in)
00107 {
00108         u32 a, b, c, d, f, g, temp;
00109         int i;
00110         struct md5_step *step;
00111 
00112         a = hash[0];
00113         b = hash[1];
00114         c = hash[2];
00115         d = hash[3];
00116 
00117         for ( i = 0 ; i < 64 ; i++ ) {
00118                 step = &md5_steps[i >> 4];
00119                 f = step->f ( b, c, d );
00120                 g = ( ( i * step->coefficient + step->constant ) & 0xf );
00121                 temp = d;
00122                 d = c;
00123                 c = b;
00124                 a += ( f + k[i] + in[g] );
00125                 a = ( ( a << r[i] ) | ( a >> ( 32-r[i] ) ) );
00126                 b += a;
00127                 a = temp;
00128         }
00129 
00130         hash[0] += a;
00131         hash[1] += b;
00132         hash[2] += c;
00133         hash[3] += d;
00134 }
00135 
00136 /* XXX: this stuff can be optimized */
00137 static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
00138 {
00139         while (words--) {
00140                 le32_to_cpus(buf);
00141                 buf++;
00142         }
00143 }
00144 
00145 static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
00146 {
00147         while (words--) {
00148                 cpu_to_le32s(buf);
00149                 buf++;
00150         }
00151 }
00152 
00153 static inline void md5_transform_helper(struct md5_ctx *ctx)
00154 {
00155         le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32));
00156         md5_transform(ctx->hash, ctx->block);
00157 }
00158 
00159 static void md5_init(void *context)
00160 {
00161         struct md5_ctx *mctx = context;
00162 
00163         mctx->hash[0] = 0x67452301;
00164         mctx->hash[1] = 0xefcdab89;
00165         mctx->hash[2] = 0x98badcfe;
00166         mctx->hash[3] = 0x10325476;
00167         mctx->byte_count = 0;
00168 }
00169 
00170 static void md5_update(void *context, const void *data, size_t len)
00171 {
00172         struct md5_ctx *mctx = context;
00173         const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
00174 
00175         mctx->byte_count += len;
00176 
00177         if (avail > len) {
00178                 memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
00179                        data, len);
00180                 return;
00181         }
00182 
00183         memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
00184                data, avail);
00185 
00186         md5_transform_helper(mctx);
00187         data += avail;
00188         len -= avail;
00189 
00190         while (len >= sizeof(mctx->block)) {
00191                 memcpy(mctx->block, data, sizeof(mctx->block));
00192                 md5_transform_helper(mctx);
00193                 data += sizeof(mctx->block);
00194                 len -= sizeof(mctx->block);
00195         }
00196 
00197         memcpy(mctx->block, data, len);
00198 }
00199 
00200 static void md5_final(void *context, void *out)
00201 {
00202         struct md5_ctx *mctx = context;
00203         const unsigned int offset = mctx->byte_count & 0x3f;
00204         char *p = (char *)mctx->block + offset;
00205         int padding = 56 - (offset + 1);
00206 
00207         *p++ = 0x80;
00208         if (padding < 0) {
00209                 memset(p, 0x00, padding + sizeof (u64));
00210                 md5_transform_helper(mctx);
00211                 p = (char *)mctx->block;
00212                 padding = 56;
00213         }
00214 
00215         memset(p, 0, padding);
00216         mctx->block[14] = mctx->byte_count << 3;
00217         mctx->block[15] = mctx->byte_count >> 29;
00218         le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
00219                           sizeof(u64)) / sizeof(u32));
00220         md5_transform(mctx->hash, mctx->block);
00221         cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
00222         memcpy(out, mctx->hash, sizeof(mctx->hash));
00223         memset(mctx, 0, sizeof(*mctx));
00224 }
00225 
00226 struct digest_algorithm md5_algorithm = {
00227         .name           = "md5",
00228         .ctxsize        = MD5_CTX_SIZE,
00229         .blocksize      = ( MD5_BLOCK_WORDS * 4 ),
00230         .digestsize     = MD5_DIGEST_SIZE,
00231         .init           = md5_init,
00232         .update         = md5_update,
00233         .final          = md5_final,
00234 };

Generated on Tue Apr 6 20:00:52 2010 for gPXE by  doxygen 1.5.7.1