• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 
f1(u32 b,u32 c,u32 d)37 static u32 f1(u32 b, u32 c, u32 d)
38 {
39 	return ( d ^ ( b & ( c ^ d ) ) );
40 }
41 
f2(u32 b,u32 c,u32 d)42 static u32 f2(u32 b, u32 c, u32 d)
43 {
44 	return ( c ^ ( d & ( b ^ c ) ) );
45 }
46 
f3(u32 b,u32 c,u32 d)47 static u32 f3(u32 b, u32 c, u32 d)
48 {
49 	return ( b ^ c ^ d );
50 }
51 
f4(u32 b,u32 c,u32 d)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 
md5_transform(u32 * hash,const u32 * in)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 */
le32_to_cpu_array(u32 * buf,unsigned int words)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 
cpu_to_le32_array(u32 * buf,unsigned int words)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 
md5_transform_helper(struct md5_ctx * ctx)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 
md5_init(void * context)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 
md5_update(void * context,const void * data,size_t len)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 
md5_final(void * context,void * out)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