1 /* 2 * Cryptographic API. 3 * 4 * MD5 Message Digest Algorithm (RFC1321). 5 * 6 * Derived from cryptoapi implementation, originally based on the 7 * public domain implementation written by Colin Plumb in 1993. 8 * 9 * Reduced object size by around 50% compared to the original Linux 10 * version for use in Etherboot by Michael Brown. 11 * 12 * Copyright (c) Cryptoapi developers. 13 * Copyright (c) 2002 James Morris <jmorris (at) intercode.com.au> 14 * Copyright (c) 2006 Michael Brown <mbrown (at) fensystems.co.uk> 15 * 16 * This program is free software; you can redistribute it and/or modify it 17 * under the terms of the GNU General Public License as published by the Free 18 * Software Foundation; either version 2 of the License, or (at your option) 19 * any later version. 20 * 21 */ 22 23 FILE_LICENCE ( GPL2_OR_LATER ); 24 25 #include <stdint.h> 26 #include <string.h> 27 #include <byteswap.h> 28 #include <gpxe/crypto.h> 29 #include <gpxe/md5.h> 30 31 struct md5_step { 32 u32 ( * f ) ( u32 b, u32 c, u32 d ); 33 u8 coefficient; 34 u8 constant; 35 }; 36 37 static u32 f1(u32 b, u32 c, u32 d) 38 { 39 return ( d ^ ( b & ( c ^ d ) ) ); 40 } 41 42 static u32 f2(u32 b, u32 c, u32 d) 43 { 44 return ( c ^ ( d & ( b ^ c ) ) ); 45 } 46 47 static u32 f3(u32 b, u32 c, u32 d) 48 { 49 return ( b ^ c ^ d ); 50 } 51 52 static u32 f4(u32 b, u32 c, u32 d) 53 { 54 return ( c ^ ( b | ~d ) ); 55 } 56 57 static struct md5_step md5_steps[4] = { 58 { 59 .f = f1, 60 .coefficient = 1, 61 .constant = 0, 62 }, 63 { 64 .f = f2, 65 .coefficient = 5, 66 .constant = 1, 67 }, 68 { 69 .f = f3, 70 .coefficient = 3, 71 .constant = 5, 72 }, 73 { 74 .f = f4, 75 .coefficient = 7, 76 .constant = 0, 77 } 78 }; 79 80 static const u8 r[64] = { 81 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22, 82 5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20, 83 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23, 84 6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21 85 }; 86 87 static const u32 k[64] = { 88 0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL, 89 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL, 90 0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL, 91 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL, 92 0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL, 93 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL, 94 0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL, 95 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL, 96 0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL, 97 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL, 98 0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL, 99 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL, 100 0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL, 101 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL, 102 0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL, 103 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL, 104 }; 105 106 static void md5_transform(u32 *hash, const u32 *in) 107 { 108 u32 a, b, c, d, f, g, temp; 109 int i; 110 struct md5_step *step; 111 112 a = hash[0]; 113 b = hash[1]; 114 c = hash[2]; 115 d = hash[3]; 116 117 for ( i = 0 ; i < 64 ; i++ ) { 118 step = &md5_steps[i >> 4]; 119 f = step->f ( b, c, d ); 120 g = ( ( i * step->coefficient + step->constant ) & 0xf ); 121 temp = d; 122 d = c; 123 c = b; 124 a += ( f + k[i] + in[g] ); 125 a = ( ( a << r[i] ) | ( a >> ( 32-r[i] ) ) ); 126 b += a; 127 a = temp; 128 } 129 130 hash[0] += a; 131 hash[1] += b; 132 hash[2] += c; 133 hash[3] += d; 134 } 135 136 /* XXX: this stuff can be optimized */ 137 static inline void le32_to_cpu_array(u32 *buf, unsigned int words) 138 { 139 while (words--) { 140 le32_to_cpus(buf); 141 buf++; 142 } 143 } 144 145 static inline void cpu_to_le32_array(u32 *buf, unsigned int words) 146 { 147 while (words--) { 148 cpu_to_le32s(buf); 149 buf++; 150 } 151 } 152 153 static inline void md5_transform_helper(struct md5_ctx *ctx) 154 { 155 le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32)); 156 md5_transform(ctx->hash, ctx->block); 157 } 158 159 static void md5_init(void *context) 160 { 161 struct md5_ctx *mctx = context; 162 163 mctx->hash[0] = 0x67452301; 164 mctx->hash[1] = 0xefcdab89; 165 mctx->hash[2] = 0x98badcfe; 166 mctx->hash[3] = 0x10325476; 167 mctx->byte_count = 0; 168 } 169 170 static void md5_update(void *context, const void *data, size_t len) 171 { 172 struct md5_ctx *mctx = context; 173 const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); 174 175 mctx->byte_count += len; 176 177 if (avail > len) { 178 memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), 179 data, len); 180 return; 181 } 182 183 memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), 184 data, avail); 185 186 md5_transform_helper(mctx); 187 data += avail; 188 len -= avail; 189 190 while (len >= sizeof(mctx->block)) { 191 memcpy(mctx->block, data, sizeof(mctx->block)); 192 md5_transform_helper(mctx); 193 data += sizeof(mctx->block); 194 len -= sizeof(mctx->block); 195 } 196 197 memcpy(mctx->block, data, len); 198 } 199 200 static void md5_final(void *context, void *out) 201 { 202 struct md5_ctx *mctx = context; 203 const unsigned int offset = mctx->byte_count & 0x3f; 204 char *p = (char *)mctx->block + offset; 205 int padding = 56 - (offset + 1); 206 207 *p++ = 0x80; 208 if (padding < 0) { 209 memset(p, 0x00, padding + sizeof (u64)); 210 md5_transform_helper(mctx); 211 p = (char *)mctx->block; 212 padding = 56; 213 } 214 215 memset(p, 0, padding); 216 mctx->block[14] = mctx->byte_count << 3; 217 mctx->block[15] = mctx->byte_count >> 29; 218 le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - 219 sizeof(u64)) / sizeof(u32)); 220 md5_transform(mctx->hash, mctx->block); 221 cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32)); 222 memcpy(out, mctx->hash, sizeof(mctx->hash)); 223 memset(mctx, 0, sizeof(*mctx)); 224 } 225 226 struct digest_algorithm md5_algorithm = { 227 .name = "md5", 228 .ctxsize = MD5_CTX_SIZE, 229 .blocksize = ( MD5_BLOCK_WORDS * 4 ), 230 .digestsize = MD5_DIGEST_SIZE, 231 .init = md5_init, 232 .update = md5_update, 233 .final = md5_final, 234 }; 235