182b625fe24ef16d0c95f489bd727acf45ea1e12
[people/xl0/gpxe.git] / src / crypto / md5.c
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@intercode.com.au>
14  * Copyright (c) 2006 Michael Brown <mbrown@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 #include <stdint.h>
24 #include <string.h>
25 #include <byteswap.h>
26 #include <gpxe/crypto.h>
27 #include <gpxe/md5.h>
28
29 #define MD5_DIGEST_SIZE         16
30 #define MD5_BLOCK_WORDS         16
31 #define MD5_HASH_WORDS          4
32
33 struct md5_ctx {
34         u32 hash[MD5_HASH_WORDS];
35         u32 block[MD5_BLOCK_WORDS];
36         u64 byte_count;
37 };
38
39 #define __md5step __attribute__ (( regparm ( 3 ) ))
40
41 struct md5_step {
42         u32 __md5step ( * f ) ( u32 b, u32 c, u32 d );
43         u8 coefficient;
44         u8 constant;
45 };
46
47 static u32 __md5step f1(u32 b, u32 c, u32 d)
48 {
49         return ( d ^ ( b & ( c ^ d ) ) );
50 }
51
52 static u32 __md5step f2(u32 b, u32 c, u32 d)
53 {
54         return ( c ^ ( d & ( b ^ c ) ) );
55 }
56
57 static u32 __md5step f3(u32 b, u32 c, u32 d)
58 {
59         return ( b ^ c ^ d );
60 }
61
62 static u32 __md5step f4(u32 b, u32 c, u32 d)
63 {
64         return ( c ^ ( b | ~d ) );
65 }
66
67 struct md5_step md5_steps[4] = {
68         {
69                 .f = f1,
70                 .coefficient = 1,
71                 .constant = 0,
72         },
73         {
74                 .f = f2,
75                 .coefficient = 5,
76                 .constant = 1,
77         },
78         {
79                 .f = f3,
80                 .coefficient = 3,
81                 .constant = 5,
82         },
83         {
84                 .f = f4,
85                 .coefficient = 7,
86                 .constant = 0,
87         }
88 };
89
90 static const u8 r[64] = {
91         7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
92         5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
93         4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
94         6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
95 };
96
97 static const u32 k[64] = {
98         0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL,
99         0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
100         0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL,
101         0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
102         0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL,
103         0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
104         0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL,
105         0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
106         0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL,
107         0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
108         0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL,
109         0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
110         0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL,
111         0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
112         0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL,
113         0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL,
114 };
115
116 static void md5_transform(u32 *hash, const u32 *in)
117 {
118         u32 a, b, c, d, f, g, temp;
119         int i;
120         struct md5_step *step;
121
122         a = hash[0];
123         b = hash[1];
124         c = hash[2];
125         d = hash[3];
126
127         for ( i = 0 ; i < 64 ; i++ ) {
128                 step = &md5_steps[i >> 4];
129                 f = step->f ( b, c, d );
130                 g = ( ( i * step->coefficient + step->constant ) & 0xf );
131                 temp = d;
132                 d = c;
133                 c = b;
134                 a += ( f + k[i] + in[g] );
135                 a = ( ( a << r[i] ) | ( a >> ( 32-r[i] ) ) );
136                 b += a;
137                 a = temp;
138         }
139
140         hash[0] += a;
141         hash[1] += b;
142         hash[2] += c;
143         hash[3] += d;
144 }
145
146 /* XXX: this stuff can be optimized */
147 static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
148 {
149         while (words--) {
150                 le32_to_cpus(buf);
151                 buf++;
152         }
153 }
154
155 static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
156 {
157         while (words--) {
158                 cpu_to_le32s(buf);
159                 buf++;
160         }
161 }
162
163 static inline void md5_transform_helper(struct md5_ctx *ctx)
164 {
165         le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32));
166         md5_transform(ctx->hash, ctx->block);
167 }
168
169 static void md5_init(void *context)
170 {
171         struct md5_ctx *mctx = context;
172
173         mctx->hash[0] = 0x67452301;
174         mctx->hash[1] = 0xefcdab89;
175         mctx->hash[2] = 0x98badcfe;
176         mctx->hash[3] = 0x10325476;
177         mctx->byte_count = 0;
178 }
179
180 static void md5_update(void *context, const void *data, size_t len)
181 {
182         struct md5_ctx *mctx = context;
183         const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
184
185         mctx->byte_count += len;
186
187         if (avail > len) {
188                 memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
189                        data, len);
190                 return;
191         }
192
193         memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
194                data, avail);
195
196         md5_transform_helper(mctx);
197         data += avail;
198         len -= avail;
199
200         while (len >= sizeof(mctx->block)) {
201                 memcpy(mctx->block, data, sizeof(mctx->block));
202                 md5_transform_helper(mctx);
203                 data += sizeof(mctx->block);
204                 len -= sizeof(mctx->block);
205         }
206
207         memcpy(mctx->block, data, len);
208 }
209
210 static void md5_finish(void *context, void *out)
211 {
212         struct md5_ctx *mctx = context;
213         const unsigned int offset = mctx->byte_count & 0x3f;
214         char *p = (char *)mctx->block + offset;
215         int padding = 56 - (offset + 1);
216
217         *p++ = 0x80;
218         if (padding < 0) {
219                 memset(p, 0x00, padding + sizeof (u64));
220                 md5_transform_helper(mctx);
221                 p = (char *)mctx->block;
222                 padding = 56;
223         }
224
225         memset(p, 0, padding);
226         mctx->block[14] = mctx->byte_count << 3;
227         mctx->block[15] = mctx->byte_count >> 29;
228         le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
229                           sizeof(u64)) / sizeof(u32));
230         md5_transform(mctx->hash, mctx->block);
231         cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
232         memcpy(out, mctx->hash, sizeof(mctx->hash));
233         memset(mctx, 0, sizeof(*mctx));
234 }
235
236 struct digest_algorithm md5_algorithm = {
237         .name           = "md5",
238         .context_len    = sizeof ( struct md5_ctx ),
239         .digest_len     = MD5_DIGEST_SIZE,
240         .init           = md5_init,
241         .update         = md5_update,
242         .finish         = md5_finish,
243 };