Generalise digest_algorithm to crypto_algorithm.
[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, void *dst __unused,
181                        size_t len)
182 {
183         struct md5_ctx *mctx = context;
184         const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
185
186         mctx->byte_count += len;
187
188         if (avail > len) {
189                 memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
190                        data, len);
191                 return;
192         }
193
194         memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
195                data, avail);
196
197         md5_transform_helper(mctx);
198         data += avail;
199         len -= avail;
200
201         while (len >= sizeof(mctx->block)) {
202                 memcpy(mctx->block, data, sizeof(mctx->block));
203                 md5_transform_helper(mctx);
204                 data += sizeof(mctx->block);
205                 len -= sizeof(mctx->block);
206         }
207
208         memcpy(mctx->block, data, len);
209 }
210
211 static void md5_final(void *context, void *out)
212 {
213         struct md5_ctx *mctx = context;
214         const unsigned int offset = mctx->byte_count & 0x3f;
215         char *p = (char *)mctx->block + offset;
216         int padding = 56 - (offset + 1);
217
218         *p++ = 0x80;
219         if (padding < 0) {
220                 memset(p, 0x00, padding + sizeof (u64));
221                 md5_transform_helper(mctx);
222                 p = (char *)mctx->block;
223                 padding = 56;
224         }
225
226         memset(p, 0, padding);
227         mctx->block[14] = mctx->byte_count << 3;
228         mctx->block[15] = mctx->byte_count >> 29;
229         le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
230                           sizeof(u64)) / sizeof(u32));
231         md5_transform(mctx->hash, mctx->block);
232         cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
233         memcpy(out, mctx->hash, sizeof(mctx->hash));
234         memset(mctx, 0, sizeof(*mctx));
235 }
236
237 struct crypto_algorithm md5_algorithm = {
238         .name           = "md5",
239         .ctxsize        = sizeof ( struct md5_ctx ),
240         .blocksize      = 1,
241         .digestsize     = MD5_DIGEST_SIZE,
242         .init           = md5_init,
243         .encode         = md5_update,
244         .final          = md5_final,
245 };