core: use GRUB_TERM_ definitions when handling term characters
[grub.git] / grub-core / lib / crypto.c
1 /*
2  *  GRUB  --  GRand Unified Bootloader
3  *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006
4  *                2007, 2008, 2009  Free Software Foundation, Inc.
5  *
6  *  GRUB is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  GRUB is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <grub/crypto.h>
21 #include <grub/misc.h>
22 #include <grub/mm.h>
23 #include <grub/term.h>
24 #include <grub/dl.h>
25 #include <grub/i18n.h>
26 #include <grub/env.h>
27
28 GRUB_MOD_LICENSE ("GPLv3+");
29
30 struct grub_crypto_hmac_handle
31 {
32   const struct gcry_md_spec *md;
33   void *ctx;
34   void *opad;
35 };
36
37 static gcry_cipher_spec_t *grub_ciphers = NULL;
38 static gcry_md_spec_t *grub_digests = NULL;
39
40 void (*grub_crypto_autoload_hook) (const char *name) = NULL;
41
42 /* Based on libgcrypt-1.4.4/src/misc.c.  */
43 void
44 grub_burn_stack (grub_size_t size)
45 {
46   char buf[64];
47
48   grub_memset (buf, 0, sizeof (buf));
49   if (size > sizeof (buf))
50     grub_burn_stack (size - sizeof (buf));
51 }
52
53 void
54 _gcry_burn_stack (int size)
55 {
56   grub_burn_stack (size);
57 }
58
59 void __attribute__ ((noreturn))
60 _gcry_assert_failed (const char *expr, const char *file, int line,
61                      const char *func)
62   
63 {
64   grub_fatal ("assertion %s at %s:%d (%s) failed\n", expr, file, line, func);
65 }
66
67
68 void _gcry_log_error (const char *fmt, ...)
69 {
70   va_list args;
71   const char *debug = grub_env_get ("debug");
72
73   if (! debug)
74     return;
75
76   if (grub_strword (debug, "all") || grub_strword (debug, "gcrypt"))
77     {
78       grub_printf ("gcrypt error: ");
79       va_start (args, fmt);
80       grub_vprintf (fmt, args);
81       va_end (args);
82       grub_refresh ();
83     }
84 }
85
86 void 
87 grub_cipher_register (gcry_cipher_spec_t *cipher)
88 {
89   cipher->next = grub_ciphers;
90   grub_ciphers = cipher;
91 }
92
93 void
94 grub_cipher_unregister (gcry_cipher_spec_t *cipher)
95 {
96   gcry_cipher_spec_t **ciph;
97   for (ciph = &grub_ciphers; *ciph; ciph = &((*ciph)->next))
98     if (*ciph == cipher)
99       {
100         *ciph = (*ciph)->next;
101         break;
102       }
103 }
104
105 void 
106 grub_md_register (gcry_md_spec_t *digest)
107 {
108   digest->next = grub_digests;
109   grub_digests = digest;
110 }
111
112 void 
113 grub_md_unregister (gcry_md_spec_t *cipher)
114 {
115   gcry_md_spec_t **ciph;
116   for (ciph = &grub_digests; *ciph; ciph = &((*ciph)->next))
117     if (*ciph == cipher)
118       {
119         *ciph = (*ciph)->next;
120         break;
121       }
122 }
123
124 void
125 grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
126                   grub_size_t inlen)
127 {
128   GRUB_PROPERLY_ALIGNED_ARRAY (ctx, GRUB_CRYPTO_MAX_MD_CONTEXT_SIZE);
129
130   if (hash->contextsize > sizeof (ctx))
131     grub_fatal ("Too large md context");
132   hash->init (&ctx);
133   hash->write (&ctx, in, inlen);
134   hash->final (&ctx);
135   grub_memcpy (out, hash->read (&ctx), hash->mdlen);
136 }
137
138 const gcry_md_spec_t *
139 grub_crypto_lookup_md_by_name (const char *name)
140 {
141   const gcry_md_spec_t *md;
142   int first = 1;
143   while (1)
144     {
145       for (md = grub_digests; md; md = md->next)
146         if (grub_strcasecmp (name, md->name) == 0)
147           return md;
148       if (grub_crypto_autoload_hook && first)
149         grub_crypto_autoload_hook (name);
150       else
151         return NULL;
152       first = 0;
153     }
154 }
155
156 const gcry_cipher_spec_t *
157 grub_crypto_lookup_cipher_by_name (const char *name)
158 {
159   const gcry_cipher_spec_t *ciph;
160   int first = 1;
161   while (1)
162     {
163       for (ciph = grub_ciphers; ciph; ciph = ciph->next)
164         {
165           const char **alias;
166           if (grub_strcasecmp (name, ciph->name) == 0)
167             return ciph;
168           if (!ciph->aliases)
169             continue;
170           for (alias = ciph->aliases; *alias; alias++)
171             if (grub_strcasecmp (name, *alias) == 0)
172               return ciph;
173         }
174       if (grub_crypto_autoload_hook && first)
175         grub_crypto_autoload_hook (name);
176       else
177         return NULL;
178       first = 0;
179     }
180 }
181
182
183 grub_crypto_cipher_handle_t
184 grub_crypto_cipher_open (const struct gcry_cipher_spec *cipher)
185 {
186   grub_crypto_cipher_handle_t ret;
187   ret = grub_malloc (sizeof (*ret) + cipher->contextsize);
188   if (!ret)
189     return NULL;
190   ret->cipher = cipher;
191   return ret;
192 }
193
194 gcry_err_code_t
195 grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher,
196                             const unsigned char *key,
197                             unsigned keylen)
198 {
199   return cipher->cipher->setkey (cipher->ctx, key, keylen);
200 }
201
202 gcry_err_code_t
203 grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher,
204                          void *out, const void *in, grub_size_t size)
205 {
206   const grub_uint8_t *inptr, *end;
207   grub_uint8_t *outptr;
208   grub_size_t blocksize;
209   if (!cipher->cipher->decrypt)
210     return GPG_ERR_NOT_SUPPORTED;
211   blocksize = cipher->cipher->blocksize;
212   if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
213       || ((size & (blocksize - 1)) != 0))
214     return GPG_ERR_INV_ARG;
215   end = (const grub_uint8_t *) in + size;
216   for (inptr = in, outptr = out; inptr < end;
217        inptr += blocksize, outptr += blocksize)
218     cipher->cipher->decrypt (cipher->ctx, outptr, inptr);
219   return GPG_ERR_NO_ERROR;
220 }
221
222 gcry_err_code_t
223 grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher,
224                          void *out, const void *in, grub_size_t size)
225 {
226   const grub_uint8_t *inptr, *end;
227   grub_uint8_t *outptr;
228   grub_size_t blocksize;
229   if (!cipher->cipher->encrypt)
230     return GPG_ERR_NOT_SUPPORTED;
231   blocksize = cipher->cipher->blocksize;
232   if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
233       || ((size & (blocksize - 1)) != 0))
234     return GPG_ERR_INV_ARG;
235   end = (const grub_uint8_t *) in + size;
236   for (inptr = in, outptr = out; inptr < end;
237        inptr += blocksize, outptr += blocksize)
238     cipher->cipher->encrypt (cipher->ctx, outptr, inptr);
239   return GPG_ERR_NO_ERROR;
240 }
241
242 gcry_err_code_t
243 grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher,
244                          void *out, const void *in, grub_size_t size,
245                          void *iv_in)
246 {
247   grub_uint8_t *outptr;
248   const grub_uint8_t *inptr, *end;
249   void *iv;
250   grub_size_t blocksize;
251   if (!cipher->cipher->encrypt)
252     return GPG_ERR_NOT_SUPPORTED;
253   blocksize = cipher->cipher->blocksize;
254   if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
255       || ((size & (blocksize - 1)) != 0))
256     return GPG_ERR_INV_ARG;
257   end = (const grub_uint8_t *) in + size;
258   iv = iv_in;
259   for (inptr = in, outptr = out; inptr < end;
260        inptr += blocksize, outptr += blocksize)
261     {
262       grub_crypto_xor (outptr, inptr, iv, blocksize);
263       cipher->cipher->encrypt (cipher->ctx, outptr, outptr);
264       iv = outptr;
265     }
266   grub_memcpy (iv_in, iv, blocksize);
267   return GPG_ERR_NO_ERROR;
268 }
269
270 gcry_err_code_t
271 grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher,
272                          void *out, const void *in, grub_size_t size,
273                          void *iv)
274 {
275   const grub_uint8_t *inptr, *end;
276   grub_uint8_t *outptr;
277   grub_uint8_t ivt[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE];
278   grub_size_t blocksize;
279   if (!cipher->cipher->decrypt)
280     return GPG_ERR_NOT_SUPPORTED;
281   blocksize = cipher->cipher->blocksize;
282   if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
283       || ((size & (blocksize - 1)) != 0))
284     return GPG_ERR_INV_ARG;
285   if (blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
286     return GPG_ERR_INV_ARG;
287   end = (const grub_uint8_t *) in + size;
288   for (inptr = in, outptr = out; inptr < end;
289        inptr += blocksize, outptr += blocksize)
290     {
291       grub_memcpy (ivt, inptr, blocksize);
292       cipher->cipher->decrypt (cipher->ctx, outptr, inptr);
293       grub_crypto_xor (outptr, outptr, iv, blocksize);
294       grub_memcpy (iv, ivt, blocksize);
295     }
296   return GPG_ERR_NO_ERROR;
297 }
298
299 /* Based on gcry/cipher/md.c.  */
300 struct grub_crypto_hmac_handle *
301 grub_crypto_hmac_init (const struct gcry_md_spec *md,
302                        const void *key, grub_size_t keylen)
303 {
304   grub_uint8_t *helpkey = NULL;
305   grub_uint8_t *ipad = NULL, *opad = NULL;
306   void *ctx = NULL;
307   struct grub_crypto_hmac_handle *ret = NULL;
308   unsigned i;
309
310   if (md->mdlen > md->blocksize)
311     return NULL;
312
313   ctx = grub_malloc (md->contextsize);
314   if (!ctx)
315     goto err;
316
317   if ( keylen > md->blocksize ) 
318     {
319       helpkey = grub_malloc (md->mdlen);
320       if (!helpkey)
321         goto err;
322       grub_crypto_hash (md, helpkey, key, keylen);
323
324       key = helpkey;
325       keylen = md->mdlen;
326     }
327
328   ipad = grub_zalloc (md->blocksize);
329   if (!ipad)
330     goto err;
331
332   opad = grub_zalloc (md->blocksize);
333   if (!opad)
334     goto err;
335
336   grub_memcpy ( ipad, key, keylen );
337   grub_memcpy ( opad, key, keylen );
338   for (i=0; i < md->blocksize; i++ ) 
339     {
340       ipad[i] ^= 0x36;
341       opad[i] ^= 0x5c;
342     }
343   grub_free (helpkey);
344   helpkey = NULL;
345
346   md->init (ctx);
347
348   md->write (ctx, ipad, md->blocksize); /* inner pad */
349   grub_memset (ipad, 0, md->blocksize);
350   grub_free (ipad);
351   ipad = NULL;
352
353   ret = grub_malloc (sizeof (*ret));
354   if (!ret)
355     goto err;
356
357   ret->md = md;
358   ret->ctx = ctx;
359   ret->opad = opad;
360
361   return ret;
362
363  err:
364   grub_free (helpkey);
365   grub_free (ctx);
366   grub_free (ipad);
367   grub_free (opad);
368   return NULL;
369 }
370
371 void
372 grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd,
373                         const void *data,
374                         grub_size_t datalen)
375 {
376   hnd->md->write (hnd->ctx, data, datalen);
377 }
378
379 gcry_err_code_t
380 grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out)
381 {
382   grub_uint8_t *p;
383   grub_uint8_t *ctx2;
384
385   ctx2 = grub_malloc (hnd->md->contextsize);
386   if (!ctx2)
387     return GPG_ERR_OUT_OF_MEMORY;
388
389   hnd->md->final (hnd->ctx);
390   hnd->md->read (hnd->ctx);
391   p = hnd->md->read (hnd->ctx);
392
393   hnd->md->init (ctx2);
394   hnd->md->write (ctx2, hnd->opad, hnd->md->blocksize);
395   hnd->md->write (ctx2, p, hnd->md->mdlen);
396   hnd->md->final (ctx2);
397   grub_memset (hnd->opad, 0, hnd->md->blocksize);
398   grub_free (hnd->opad);
399   grub_memset (hnd->ctx, 0, hnd->md->contextsize);
400   grub_free (hnd->ctx);
401
402   grub_memcpy (out, hnd->md->read (ctx2), hnd->md->mdlen);
403   grub_memset (ctx2, 0, hnd->md->contextsize);
404   grub_free (ctx2);
405
406   grub_memset (hnd, 0, sizeof (*hnd));
407   grub_free (hnd);
408
409   return GPG_ERR_NO_ERROR;
410 }
411
412 gcry_err_code_t
413 grub_crypto_hmac_buffer (const struct gcry_md_spec *md,
414                          const void *key, grub_size_t keylen,
415                          const void *data, grub_size_t datalen, void *out)
416 {
417   struct grub_crypto_hmac_handle *hnd;
418
419   hnd = grub_crypto_hmac_init (md, key, keylen);
420   if (!hnd)
421     return GPG_ERR_OUT_OF_MEMORY;
422
423   grub_crypto_hmac_write (hnd, data, datalen);
424   return grub_crypto_hmac_fini (hnd, out);
425 }
426
427
428 grub_err_t
429 grub_crypto_gcry_error (gcry_err_code_t in)
430 {
431   if (in == GPG_ERR_NO_ERROR)
432     return GRUB_ERR_NONE;
433   return GRUB_ACCESS_DENIED;
434 }
435
436 int
437 grub_crypto_memcmp (const void *a, const void *b, grub_size_t n)
438 {
439   register grub_size_t counter = 0;
440   const grub_uint8_t *pa, *pb;
441
442   for (pa = a, pb = b; n; pa++, pb++, n--)
443     {
444       if (*pa != *pb)
445         counter++;
446     }
447
448   return !!counter;
449 }
450
451 #ifndef GRUB_UTIL
452
453 int
454 grub_password_get (char buf[], unsigned buf_size)
455 {
456   unsigned cur_len = 0;
457   int key;
458
459   while (1)
460     {
461       key = grub_getkey (); 
462       if (key == '\n' || key == '\r')
463         break;
464
465       if (key == GRUB_TERM_ESC)
466         {
467           cur_len = 0;
468           break;
469         }
470
471       if (key == '\b')
472         {
473           if (cur_len)
474             cur_len--;
475           continue;
476         }
477
478       if (!grub_isprint (key))
479         continue;
480
481       if (cur_len + 2 < buf_size)
482         buf[cur_len++] = key;
483     }
484
485   grub_memset (buf + cur_len, 0, buf_size - cur_len);
486
487   grub_xputs ("\n");
488   grub_refresh ();
489
490   return (key != GRUB_TERM_ESC);
491 }
492 #endif
493