2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006
4 * 2007, 2008, 2009 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include <grub/crypto.h>
21 #include <grub/misc.h>
23 #include <grub/term.h>
25 #include <grub/i18n.h>
34 GRUB_MOD_LICENSE ("GPLv3+");
36 struct grub_crypto_hmac_handle
38 const struct gcry_md_spec
*md
;
43 static gcry_cipher_spec_t
*grub_ciphers
= NULL
;
44 static gcry_md_spec_t
*grub_digests
= NULL
;
46 void (*grub_crypto_autoload_hook
) (const char *name
) = NULL
;
48 /* Based on libgcrypt-1.4.4/src/misc.c. */
50 grub_burn_stack (grub_size_t size
)
54 grub_memset (buf
, 0, sizeof (buf
));
55 if (size
> sizeof (buf
))
56 grub_burn_stack (size
- sizeof (buf
));
61 grub_cipher_register (gcry_cipher_spec_t
*cipher
)
63 cipher
->next
= grub_ciphers
;
64 grub_ciphers
= cipher
;
68 grub_cipher_unregister (gcry_cipher_spec_t
*cipher
)
70 gcry_cipher_spec_t
**ciph
;
71 for (ciph
= &grub_ciphers
; *ciph
; ciph
= &((*ciph
)->next
))
74 *ciph
= (*ciph
)->next
;
80 grub_md_register (gcry_md_spec_t
*digest
)
82 digest
->next
= grub_digests
;
83 grub_digests
= digest
;
87 grub_md_unregister (gcry_md_spec_t
*cipher
)
89 gcry_md_spec_t
**ciph
;
90 for (ciph
= &grub_digests
; *ciph
; ciph
= &((*ciph
)->next
))
93 *ciph
= (*ciph
)->next
;
99 grub_crypto_hash (const gcry_md_spec_t
*hash
, void *out
, const void *in
,
102 grub_uint8_t ctx
[hash
->contextsize
];
104 hash
->write (&ctx
, in
, inlen
);
106 grub_memcpy (out
, hash
->read (&ctx
), hash
->mdlen
);
109 const gcry_md_spec_t
*
110 grub_crypto_lookup_md_by_name (const char *name
)
112 const gcry_md_spec_t
*md
;
116 for (md
= grub_digests
; md
; md
= md
->next
)
117 if (grub_strcasecmp (name
, md
->name
) == 0)
119 if (grub_crypto_autoload_hook
&& first
)
120 grub_crypto_autoload_hook (name
);
127 const gcry_cipher_spec_t
*
128 grub_crypto_lookup_cipher_by_name (const char *name
)
130 const gcry_cipher_spec_t
*ciph
;
134 for (ciph
= grub_ciphers
; ciph
; ciph
= ciph
->next
)
137 if (grub_strcasecmp (name
, ciph
->name
) == 0)
141 for (alias
= ciph
->aliases
; *alias
; alias
++)
142 if (grub_strcasecmp (name
, *alias
) == 0)
145 if (grub_crypto_autoload_hook
&& first
)
146 grub_crypto_autoload_hook (name
);
154 grub_crypto_cipher_handle_t
155 grub_crypto_cipher_open (const struct gcry_cipher_spec
*cipher
)
157 grub_crypto_cipher_handle_t ret
;
158 ret
= grub_malloc (sizeof (*ret
) + cipher
->contextsize
);
161 ret
->cipher
= cipher
;
166 grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher
,
167 const unsigned char *key
,
170 return cipher
->cipher
->setkey (cipher
->ctx
, key
, keylen
);
174 grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher
,
175 void *out
, const void *in
, grub_size_t size
)
177 const grub_uint8_t
*inptr
;
178 grub_uint8_t
*outptr
, *end
;
179 if (!cipher
->cipher
->decrypt
)
180 return GPG_ERR_NOT_SUPPORTED
;
181 if (size
% cipher
->cipher
->blocksize
!= 0)
182 return GPG_ERR_INV_ARG
;
183 end
= (grub_uint8_t
*) in
+ size
;
184 for (inptr
= in
, outptr
= out
; inptr
< end
;
185 inptr
+= cipher
->cipher
->blocksize
, outptr
+= cipher
->cipher
->blocksize
)
186 cipher
->cipher
->decrypt (cipher
->ctx
, outptr
, inptr
);
187 return GPG_ERR_NO_ERROR
;
191 grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher
,
192 void *out
, const void *in
, grub_size_t size
)
194 const grub_uint8_t
*inptr
;
195 grub_uint8_t
*outptr
, *end
;
196 if (!cipher
->cipher
->encrypt
)
197 return GPG_ERR_NOT_SUPPORTED
;
198 if (size
% cipher
->cipher
->blocksize
!= 0)
199 return GPG_ERR_INV_ARG
;
200 end
= (grub_uint8_t
*) in
+ size
;
201 for (inptr
= in
, outptr
= out
; inptr
< end
;
202 inptr
+= cipher
->cipher
->blocksize
, outptr
+= cipher
->cipher
->blocksize
)
203 cipher
->cipher
->encrypt (cipher
->ctx
, outptr
, inptr
);
204 return GPG_ERR_NO_ERROR
;
208 grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher
,
209 void *out
, void *in
, grub_size_t size
,
212 grub_uint8_t
*inptr
, *outptr
, *end
;
214 if (!cipher
->cipher
->decrypt
)
215 return GPG_ERR_NOT_SUPPORTED
;
216 if (size
% cipher
->cipher
->blocksize
!= 0)
217 return GPG_ERR_INV_ARG
;
218 end
= (grub_uint8_t
*) in
+ size
;
220 for (inptr
= in
, outptr
= out
; inptr
< end
;
221 inptr
+= cipher
->cipher
->blocksize
, outptr
+= cipher
->cipher
->blocksize
)
223 grub_crypto_xor (outptr
, inptr
, iv
, cipher
->cipher
->blocksize
);
224 cipher
->cipher
->encrypt (cipher
->ctx
, outptr
, outptr
);
227 grub_memcpy (iv_in
, iv
, cipher
->cipher
->blocksize
);
228 return GPG_ERR_NO_ERROR
;
232 grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher
,
233 void *out
, const void *in
, grub_size_t size
,
236 const grub_uint8_t
*inptr
;
237 grub_uint8_t
*outptr
, *end
;
238 grub_uint8_t ivt
[cipher
->cipher
->blocksize
];
239 if (!cipher
->cipher
->decrypt
)
240 return GPG_ERR_NOT_SUPPORTED
;
241 if (size
% cipher
->cipher
->blocksize
!= 0)
242 return GPG_ERR_INV_ARG
;
243 end
= (grub_uint8_t
*) in
+ size
;
244 for (inptr
= in
, outptr
= out
; inptr
< end
;
245 inptr
+= cipher
->cipher
->blocksize
, outptr
+= cipher
->cipher
->blocksize
)
247 grub_memcpy (ivt
, inptr
, cipher
->cipher
->blocksize
);
248 cipher
->cipher
->decrypt (cipher
->ctx
, outptr
, inptr
);
249 grub_crypto_xor (outptr
, outptr
, iv
, cipher
->cipher
->blocksize
);
250 grub_memcpy (iv
, ivt
, cipher
->cipher
->blocksize
);
252 return GPG_ERR_NO_ERROR
;
255 /* Based on gcry/cipher/md.c. */
256 struct grub_crypto_hmac_handle
*
257 grub_crypto_hmac_init (const struct gcry_md_spec
*md
,
258 const void *key
, grub_size_t keylen
)
260 grub_uint8_t
*helpkey
= NULL
;
261 grub_uint8_t
*ipad
= NULL
, *opad
= NULL
;
263 struct grub_crypto_hmac_handle
*ret
= NULL
;
266 if (md
->mdlen
> md
->blocksize
)
269 ctx
= grub_malloc (md
->contextsize
);
273 if ( keylen
> md
->blocksize
)
275 helpkey
= grub_malloc (md
->mdlen
);
278 grub_crypto_hash (md
, helpkey
, key
, keylen
);
284 ipad
= grub_zalloc (md
->blocksize
);
288 opad
= grub_zalloc (md
->blocksize
);
292 grub_memcpy ( ipad
, key
, keylen
);
293 grub_memcpy ( opad
, key
, keylen
);
294 for (i
=0; i
< md
->blocksize
; i
++ )
304 md
->write (ctx
, ipad
, md
->blocksize
); /* inner pad */
305 grub_memset (ipad
, 0, md
->blocksize
);
309 ret
= grub_malloc (sizeof (*ret
));
328 grub_crypto_hmac_write (struct grub_crypto_hmac_handle
*hnd
,
332 hnd
->md
->write (hnd
->ctx
, data
, datalen
);
336 grub_crypto_hmac_fini (struct grub_crypto_hmac_handle
*hnd
, void *out
)
341 ctx2
= grub_malloc (hnd
->md
->contextsize
);
343 return GPG_ERR_OUT_OF_MEMORY
;
345 hnd
->md
->final (hnd
->ctx
);
346 hnd
->md
->read (hnd
->ctx
);
347 p
= hnd
->md
->read (hnd
->ctx
);
349 hnd
->md
->init (ctx2
);
350 hnd
->md
->write (ctx2
, hnd
->opad
, hnd
->md
->blocksize
);
351 hnd
->md
->write (ctx2
, p
, hnd
->md
->mdlen
);
352 hnd
->md
->final (ctx2
);
353 grub_memset (hnd
->opad
, 0, hnd
->md
->blocksize
);
354 grub_free (hnd
->opad
);
355 grub_memset (hnd
->ctx
, 0, hnd
->md
->contextsize
);
356 grub_free (hnd
->ctx
);
358 grub_memcpy (out
, hnd
->md
->read (ctx2
), hnd
->md
->mdlen
);
359 grub_memset (ctx2
, 0, hnd
->md
->contextsize
);
362 grub_memset (hnd
, 0, sizeof (*hnd
));
365 return GPG_ERR_NO_ERROR
;
369 grub_crypto_hmac_buffer (const struct gcry_md_spec
*md
,
370 const void *key
, grub_size_t keylen
,
371 const void *data
, grub_size_t datalen
, void *out
)
373 struct grub_crypto_hmac_handle
*hnd
;
375 hnd
= grub_crypto_hmac_init (md
, key
, keylen
);
377 return GPG_ERR_OUT_OF_MEMORY
;
379 grub_crypto_hmac_write (hnd
, data
, datalen
);
380 return grub_crypto_hmac_fini (hnd
, out
);
385 grub_crypto_gcry_error (gcry_err_code_t in
)
387 if (in
== GPG_ERR_NO_ERROR
)
388 return GRUB_ERR_NONE
;
389 return GRUB_ACCESS_DENIED
;
393 grub_crypto_memcmp (const void *a
, const void *b
, grub_size_t n
)
395 register grub_size_t counter
= 0;
396 const grub_uint8_t
*pa
, *pb
;
398 for (pa
= a
, pb
= b
; n
; pa
++, pb
++, n
--)
408 grub_password_get (char buf
[], unsigned buf_size
)
416 /* Disable echoing. Based on glibc. */
417 in
= fopen ("/dev/tty", "w+c");
421 if (tcgetattr (fileno (in
), &t
) == 0)
423 /* Save the old one. */
425 /* Tricky, tricky. */
426 t
.c_lflag
&= ~(ECHO
|ISIG
);
427 tty_changed
= (tcsetattr (fileno (in
), TCSAFLUSH
, &t
) == 0);
431 fgets (buf
, buf_size
, stdin
);
432 ptr
= buf
+ strlen (buf
) - 1;
433 while (buf
<= ptr
&& (*ptr
== '\n' || *ptr
== '\r'))
435 /* Restore the original setting. */
437 (void) tcsetattr (fileno (in
), TCSAFLUSH
, &s
);
444 unsigned cur_len
= 0;
449 key
= grub_getkey ();
450 if (key
== '\n' || key
== '\r')
465 if (!grub_isprint (key
))
468 if (cur_len
+ 2 < buf_size
)
469 buf
[cur_len
++] = key
;
472 grub_memset (buf
+ cur_len
, 0, buf_size
- cur_len
);
477 return (key
!= '\e');