]>
Commit | Line | Data |
---|---|---|
a2c1332b | 1 | /* xnu_uuid.c - transform 64-bit serial number |
693fe637 | 2 | to 128-bit uuid suitable for xnu. */ |
3 | /* | |
4 | * GRUB -- GRand Unified Bootloader | |
5 | * Copyright (C) 1995,1996,1998,1999,2001,2002, | |
6 | * 2003, 2009 Free Software Foundation, Inc. | |
7 | * | |
8 | * GRUB is free software: you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation, either version 3 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * GRUB is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. | |
20 | */ | |
21 | ||
22 | #include <grub/types.h> | |
23 | #include <grub/misc.h> | |
24 | #include <grub/mm.h> | |
25 | #include <grub/err.h> | |
26 | #include <grub/dl.h> | |
27 | #include <grub/device.h> | |
28 | #include <grub/disk.h> | |
29 | #include <grub/fs.h> | |
30 | #include <grub/file.h> | |
31 | #include <grub/misc.h> | |
32 | #include <grub/env.h> | |
33 | #include <grub/command.h> | |
34 | ||
35 | struct tohash | |
36 | { | |
37 | grub_uint8_t prefix[16]; | |
38 | grub_uint64_t serial; | |
39 | } __attribute__ ((packed)); | |
40 | ||
a2c1332b | 41 | /* This prefix is used by xnu and boot-132 to hash |
693fe637 | 42 | together with volume serial. */ |
a2c1332b FZ |
43 | static grub_uint8_t hash_prefix[16] |
44 | = {0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, | |
693fe637 | 45 | 0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC}; |
46 | ||
47 | #define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) | |
48 | #define ror(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) ) | |
49 | ||
50 | typedef struct { | |
51 | grub_uint32_t A,B,C,D; /* chaining variables */ | |
52 | grub_uint32_t nblocks; | |
53 | grub_uint8_t buf[64]; | |
54 | int count; | |
55 | } MD5_CONTEXT; | |
56 | ||
57 | static void | |
58 | md5_init( void *context ) | |
59 | { | |
60 | MD5_CONTEXT *ctx = context; | |
61 | ||
62 | ctx->A = 0x67452301; | |
63 | ctx->B = 0xefcdab89; | |
64 | ctx->C = 0x98badcfe; | |
65 | ctx->D = 0x10325476; | |
66 | ||
67 | ctx->nblocks = 0; | |
68 | ctx->count = 0; | |
69 | } | |
70 | ||
71 | /* These are the four functions used in the four steps of the MD5 algorithm | |
72 | and defined in the RFC 1321. The first function is a little bit optimized | |
73 | (as found in Colin Plumbs public domain implementation). */ | |
74 | /* #define FF(b, c, d) ((b & c) | (~b & d)) */ | |
75 | #define FF(b, c, d) (d ^ (b & (c ^ d))) | |
76 | #define FG(b, c, d) FF (d, b, c) | |
77 | #define FH(b, c, d) (b ^ c ^ d) | |
78 | #define FI(b, c, d) (c ^ (b | ~d)) | |
79 | ||
80 | ||
81 | /**************** | |
82 | * transform n*64 grub_uint8_ts | |
83 | */ | |
84 | static void | |
85 | transform ( MD5_CONTEXT *ctx, const unsigned char *data ) | |
86 | { | |
87 | grub_uint32_t correct_words[16]; | |
88 | register grub_uint32_t A = ctx->A; | |
89 | register grub_uint32_t B = ctx->B; | |
90 | register grub_uint32_t C = ctx->C; | |
91 | register grub_uint32_t D = ctx->D; | |
92 | grub_uint32_t *cwp = correct_words; | |
93 | ||
ef3c317f | 94 | #ifdef GRUB_CPU_WORDS_BIGENDIAN |
95 | { | |
693fe637 | 96 | int i; |
ef3c317f | 97 | const grub_uint32_t *p = (const grub_uint32_t *) data; |
98 | ||
99 | for (i = 0; i < 16; i++) | |
100 | correct_words[i] = grub_le_to_cpu32 (p[i]); | |
693fe637 | 101 | } |
102 | #else | |
11d1c769 | 103 | grub_memcpy (correct_words, data, 64); |
693fe637 | 104 | #endif |
105 | ||
106 | #define OP(a, b, c, d, s, T) \ | |
107 | do \ | |
108 | { \ | |
109 | a += FF (b, c, d) + (*cwp++) + T; \ | |
110 | a = rol(a, s); \ | |
111 | a += b; \ | |
112 | } \ | |
113 | while (0) | |
114 | ||
115 | /* Before we start, one word about the strange constants. | |
116 | They are defined in RFC 1321 as | |
117 | ||
118 | T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 | |
119 | */ | |
120 | ||
121 | /* Round 1. */ | |
122 | OP (A, B, C, D, 7, 0xd76aa478); | |
123 | OP (D, A, B, C, 12, 0xe8c7b756); | |
124 | OP (C, D, A, B, 17, 0x242070db); | |
125 | OP (B, C, D, A, 22, 0xc1bdceee); | |
126 | OP (A, B, C, D, 7, 0xf57c0faf); | |
127 | OP (D, A, B, C, 12, 0x4787c62a); | |
128 | OP (C, D, A, B, 17, 0xa8304613); | |
129 | OP (B, C, D, A, 22, 0xfd469501); | |
130 | OP (A, B, C, D, 7, 0x698098d8); | |
131 | OP (D, A, B, C, 12, 0x8b44f7af); | |
132 | OP (C, D, A, B, 17, 0xffff5bb1); | |
133 | OP (B, C, D, A, 22, 0x895cd7be); | |
134 | OP (A, B, C, D, 7, 0x6b901122); | |
135 | OP (D, A, B, C, 12, 0xfd987193); | |
136 | OP (C, D, A, B, 17, 0xa679438e); | |
137 | OP (B, C, D, A, 22, 0x49b40821); | |
138 | ||
139 | #undef OP | |
140 | #define OP(f, a, b, c, d, k, s, T) \ | |
141 | do \ | |
142 | { \ | |
143 | a += f (b, c, d) + correct_words[k] + T; \ | |
144 | a = rol(a, s); \ | |
145 | a += b; \ | |
146 | } \ | |
147 | while (0) | |
148 | ||
149 | /* Round 2. */ | |
150 | OP (FG, A, B, C, D, 1, 5, 0xf61e2562); | |
151 | OP (FG, D, A, B, C, 6, 9, 0xc040b340); | |
152 | OP (FG, C, D, A, B, 11, 14, 0x265e5a51); | |
153 | OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); | |
154 | OP (FG, A, B, C, D, 5, 5, 0xd62f105d); | |
155 | OP (FG, D, A, B, C, 10, 9, 0x02441453); | |
156 | OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); | |
157 | OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); | |
158 | OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); | |
159 | OP (FG, D, A, B, C, 14, 9, 0xc33707d6); | |
160 | OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); | |
161 | OP (FG, B, C, D, A, 8, 20, 0x455a14ed); | |
162 | OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); | |
163 | OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); | |
164 | OP (FG, C, D, A, B, 7, 14, 0x676f02d9); | |
165 | OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); | |
166 | ||
167 | /* Round 3. */ | |
168 | OP (FH, A, B, C, D, 5, 4, 0xfffa3942); | |
169 | OP (FH, D, A, B, C, 8, 11, 0x8771f681); | |
170 | OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); | |
171 | OP (FH, B, C, D, A, 14, 23, 0xfde5380c); | |
172 | OP (FH, A, B, C, D, 1, 4, 0xa4beea44); | |
173 | OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); | |
174 | OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); | |
175 | OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); | |
176 | OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); | |
177 | OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); | |
178 | OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); | |
179 | OP (FH, B, C, D, A, 6, 23, 0x04881d05); | |
180 | OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); | |
181 | OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); | |
182 | OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); | |
183 | OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); | |
184 | ||
185 | /* Round 4. */ | |
186 | OP (FI, A, B, C, D, 0, 6, 0xf4292244); | |
187 | OP (FI, D, A, B, C, 7, 10, 0x432aff97); | |
188 | OP (FI, C, D, A, B, 14, 15, 0xab9423a7); | |
189 | OP (FI, B, C, D, A, 5, 21, 0xfc93a039); | |
190 | OP (FI, A, B, C, D, 12, 6, 0x655b59c3); | |
191 | OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); | |
192 | OP (FI, C, D, A, B, 10, 15, 0xffeff47d); | |
193 | OP (FI, B, C, D, A, 1, 21, 0x85845dd1); | |
194 | OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); | |
195 | OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); | |
196 | OP (FI, C, D, A, B, 6, 15, 0xa3014314); | |
197 | OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); | |
198 | OP (FI, A, B, C, D, 4, 6, 0xf7537e82); | |
199 | OP (FI, D, A, B, C, 11, 10, 0xbd3af235); | |
200 | OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); | |
201 | OP (FI, B, C, D, A, 9, 21, 0xeb86d391); | |
202 | ||
203 | /* Put checksum in context given as argument. */ | |
204 | ctx->A += A; | |
205 | ctx->B += B; | |
206 | ctx->C += C; | |
207 | ctx->D += D; | |
208 | } | |
209 | ||
210 | /* The routine updates the message-digest context to | |
211 | * account for the presence of each of the characters inBuf[0..inLen-1] | |
212 | * in the message whose digest is being computed. | |
213 | */ | |
214 | static void | |
215 | md5_write( void *context, const void *inbuf_arg , grub_size_t inlen) | |
216 | { | |
217 | const unsigned char *inbuf = inbuf_arg; | |
218 | MD5_CONTEXT *hd = context; | |
219 | ||
220 | if( hd->count == 64 ) /* flush the buffer */ | |
221 | { | |
222 | transform( hd, hd->buf ); | |
223 | // _gcry_burn_stack (80+6*sizeof(void*)); | |
224 | hd->count = 0; | |
225 | hd->nblocks++; | |
226 | } | |
227 | if( !inbuf ) | |
228 | return; | |
229 | ||
230 | if( hd->count ) | |
231 | { | |
232 | for( ; inlen && hd->count < 64; inlen-- ) | |
233 | hd->buf[hd->count++] = *inbuf++; | |
234 | md5_write( hd, NULL, 0 ); | |
235 | if( !inlen ) | |
236 | return; | |
237 | } | |
238 | // _gcry_burn_stack (80+6*sizeof(void*)); | |
239 | ||
a2c1332b | 240 | while( inlen >= 64 ) |
693fe637 | 241 | { |
242 | transform( hd, inbuf ); | |
243 | hd->count = 0; | |
244 | hd->nblocks++; | |
245 | inlen -= 64; | |
246 | inbuf += 64; | |
247 | } | |
248 | for( ; inlen && hd->count < 64; inlen-- ) | |
249 | hd->buf[hd->count++] = *inbuf++; | |
250 | ||
251 | } | |
252 | ||
253 | ||
254 | ||
255 | /* The routine final terminates the message-digest computation and | |
256 | * ends with the desired message digest in mdContext->digest[0...15]. | |
257 | * The handle is prepared for a new MD5 cycle. | |
258 | * Returns 16 grub_uint8_ts representing the digest. | |
259 | */ | |
260 | static void | |
261 | md5_final( void *context) | |
262 | { | |
263 | MD5_CONTEXT *hd = context; | |
264 | grub_uint32_t t, msb, lsb; | |
ef3c317f | 265 | grub_uint32_t *p; |
693fe637 | 266 | |
267 | md5_write(hd, NULL, 0); /* flush */; | |
268 | ||
269 | t = hd->nblocks; | |
270 | /* multiply by 64 to make a grub_uint8_t count */ | |
271 | lsb = t << 6; | |
272 | msb = t >> 26; | |
273 | /* add the count */ | |
274 | t = lsb; | |
275 | if( (lsb += hd->count) < t ) | |
276 | msb++; | |
277 | /* multiply by 8 to make a bit count */ | |
278 | t = lsb; | |
279 | lsb <<= 3; | |
280 | msb <<= 3; | |
281 | msb |= t >> 29; | |
282 | ||
283 | if( hd->count < 56 ) /* enough room */ | |
284 | { | |
285 | hd->buf[hd->count++] = 0x80; /* pad */ | |
286 | while( hd->count < 56 ) | |
287 | hd->buf[hd->count++] = 0; /* pad */ | |
288 | } | |
289 | else /* need one extra block */ | |
290 | { | |
291 | hd->buf[hd->count++] = 0x80; /* pad character */ | |
292 | while( hd->count < 64 ) | |
293 | hd->buf[hd->count++] = 0; | |
294 | md5_write(hd, NULL, 0); /* flush */; | |
295 | grub_memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ | |
296 | } | |
297 | /* append the 64 bit count */ | |
298 | hd->buf[56] = lsb ; | |
299 | hd->buf[57] = lsb >> 8; | |
300 | hd->buf[58] = lsb >> 16; | |
301 | hd->buf[59] = lsb >> 24; | |
302 | hd->buf[60] = msb ; | |
303 | hd->buf[61] = msb >> 8; | |
304 | hd->buf[62] = msb >> 16; | |
305 | hd->buf[63] = msb >> 24; | |
306 | transform( hd, hd->buf ); | |
307 | // _gcry_burn_stack (80+6*sizeof(void*)); | |
308 | ||
ef3c317f | 309 | p = (grub_uint32_t *) hd->buf; |
310 | #define X(a) do { *p = grub_le_to_cpu32 (hd->a); p++; } while (0) | |
693fe637 | 311 | X(A); |
312 | X(B); | |
313 | X(C); | |
314 | X(D); | |
315 | #undef X | |
316 | ||
317 | } | |
318 | ||
319 | /** | |
320 | * GRUB2 Crypto Interface | |
321 | * Written by Michael Gorven | |
322 | */ | |
323 | static grub_err_t | |
324 | md5 (const char *in, grub_size_t insize, char *out) | |
325 | { | |
326 | MD5_CONTEXT hd; | |
327 | ||
328 | md5_init (&hd); | |
329 | md5_write (&hd, in, insize); | |
330 | md5_final (&hd); | |
331 | grub_memcpy (out, hd.buf, 16); | |
332 | ||
333 | return GRUB_ERR_NONE; | |
334 | } | |
335 | ||
336 | static grub_err_t | |
337 | grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)), | |
338 | int argc, char **args) | |
339 | { | |
340 | struct tohash hashme; | |
341 | grub_uint8_t xnu_uuid[16]; | |
342 | char uuid_string[sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]; | |
343 | char *ptr; | |
344 | ||
345 | if (argc < 1) | |
346 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required"); | |
347 | ||
348 | hashme.serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16)); | |
349 | grub_memcpy (hashme.prefix, hash_prefix, sizeof (hashme.prefix)); | |
350 | ||
351 | md5 ((char *) &hashme, sizeof (hashme), (char *) xnu_uuid); | |
693fe637 | 352 | grub_sprintf (uuid_string, |
353 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", | |
354 | (unsigned int) xnu_uuid[0], (unsigned int) xnu_uuid[1], | |
355 | (unsigned int) xnu_uuid[2], (unsigned int) xnu_uuid[3], | |
356 | (unsigned int) xnu_uuid[4], (unsigned int) xnu_uuid[5], | |
357 | (unsigned int) ((xnu_uuid[6] & 0xf) | 0x30), | |
358 | (unsigned int) xnu_uuid[7], | |
359 | (unsigned int) ((xnu_uuid[8] & 0x3f) | 0x80), | |
360 | (unsigned int) xnu_uuid[9], | |
361 | (unsigned int) xnu_uuid[10], (unsigned int) xnu_uuid[11], | |
362 | (unsigned int) xnu_uuid[12], (unsigned int) xnu_uuid[13], | |
363 | (unsigned int) xnu_uuid[14], (unsigned int) xnu_uuid[15]); | |
364 | for (ptr = uuid_string; *ptr; ptr++) | |
365 | *ptr = grub_toupper (*ptr); | |
366 | if (argc == 1) | |
367 | grub_printf ("%s", uuid_string); | |
368 | if (argc > 1) | |
369 | grub_env_set (args[1], uuid_string); | |
370 | ||
371 | return GRUB_ERR_NONE; | |
372 | } | |
373 | ||
374 | static grub_command_t cmd; | |
375 | ||
376 | ||
377 | GRUB_MOD_INIT (xnu_uuid) | |
378 | { | |
379 | cmd = grub_register_command ("xnu_uuid", grub_cmd_xnu_uuid, | |
fdcdbb66 | 380 | "GRUBUUID [VARNAME]", |
693fe637 | 381 | "Transform 64-bit UUID to format " |
382 | "suitable for xnu."); | |
383 | } | |
384 | ||
385 | GRUB_MOD_FINI (xnu_uuid) | |
386 | { | |
387 | grub_unregister_command (cmd); | |
388 | } |