123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- /*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006
- * 2007, 2008, 2009 Free Software Foundation, Inc.
- *
- * GRUB is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GRUB is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <grub/crypto.h>
- #include <grub/misc.h>
- #include <grub/mm.h>
- #include <grub/term.h>
- #include <grub/dl.h>
- #include <grub/i18n.h>
- #include <grub/env.h>
- GRUB_MOD_LICENSE ("GPLv3+");
- struct grub_crypto_hmac_handle
- {
- const struct gcry_md_spec *md;
- void *ctx;
- void *opad;
- };
- static gcry_cipher_spec_t *grub_ciphers = NULL;
- static gcry_md_spec_t *grub_digests = NULL;
- void (*grub_crypto_autoload_hook) (const char *name) = NULL;
- /* Based on libgcrypt-1.4.4/src/misc.c. */
- void
- grub_burn_stack (grub_size_t size)
- {
- char buf[64];
- grub_memset (buf, 0, sizeof (buf));
- if (size > sizeof (buf))
- grub_burn_stack (size - sizeof (buf));
- }
- void
- _gcry_burn_stack (int size)
- {
- grub_burn_stack (size);
- }
- void __attribute__ ((noreturn))
- _gcry_assert_failed (const char *expr, const char *file, int line,
- const char *func)
- {
- grub_fatal ("assertion %s at %s:%d (%s) failed\n", expr, file, line, func);
- }
- void _gcry_log_error (const char *fmt, ...)
- {
- va_list args;
- const char *debug = grub_env_get ("debug");
- if (! debug)
- return;
- if (grub_strword (debug, "all") || grub_strword (debug, "gcrypt"))
- {
- grub_printf ("gcrypt error: ");
- va_start (args, fmt);
- grub_vprintf (fmt, args);
- va_end (args);
- grub_refresh ();
- }
- }
- void
- grub_cipher_register (gcry_cipher_spec_t *cipher)
- {
- cipher->next = grub_ciphers;
- grub_ciphers = cipher;
- }
- void
- grub_cipher_unregister (gcry_cipher_spec_t *cipher)
- {
- gcry_cipher_spec_t **ciph;
- for (ciph = &grub_ciphers; *ciph; ciph = &((*ciph)->next))
- if (*ciph == cipher)
- {
- *ciph = (*ciph)->next;
- break;
- }
- }
- void
- grub_md_register (gcry_md_spec_t *digest)
- {
- digest->next = grub_digests;
- grub_digests = digest;
- }
- void
- grub_md_unregister (gcry_md_spec_t *cipher)
- {
- gcry_md_spec_t **ciph;
- for (ciph = &grub_digests; *ciph; ciph = &((*ciph)->next))
- if (*ciph == cipher)
- {
- *ciph = (*ciph)->next;
- break;
- }
- }
- void
- grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
- grub_size_t inlen)
- {
- GRUB_PROPERLY_ALIGNED_ARRAY (ctx, GRUB_CRYPTO_MAX_MD_CONTEXT_SIZE);
- if (hash->contextsize > sizeof (ctx))
- grub_fatal ("Too large md context");
- hash->init (&ctx);
- hash->write (&ctx, in, inlen);
- hash->final (&ctx);
- grub_memcpy (out, hash->read (&ctx), hash->mdlen);
- }
- const gcry_md_spec_t *
- grub_crypto_lookup_md_by_name (const char *name)
- {
- const gcry_md_spec_t *md;
- int first = 1;
- while (1)
- {
- for (md = grub_digests; md; md = md->next)
- if (grub_strcasecmp (name, md->name) == 0)
- return md;
- if (grub_crypto_autoload_hook && first)
- grub_crypto_autoload_hook (name);
- else
- return NULL;
- first = 0;
- }
- }
- const gcry_cipher_spec_t *
- grub_crypto_lookup_cipher_by_name (const char *name)
- {
- const gcry_cipher_spec_t *ciph;
- int first = 1;
- while (1)
- {
- for (ciph = grub_ciphers; ciph; ciph = ciph->next)
- {
- const char **alias;
- if (grub_strcasecmp (name, ciph->name) == 0)
- return ciph;
- if (!ciph->aliases)
- continue;
- for (alias = ciph->aliases; *alias; alias++)
- if (grub_strcasecmp (name, *alias) == 0)
- return ciph;
- }
- if (grub_crypto_autoload_hook && first)
- grub_crypto_autoload_hook (name);
- else
- return NULL;
- first = 0;
- }
- }
- grub_crypto_cipher_handle_t
- grub_crypto_cipher_open (const struct gcry_cipher_spec *cipher)
- {
- grub_crypto_cipher_handle_t ret;
- ret = grub_malloc (sizeof (*ret) + cipher->contextsize);
- if (!ret)
- return NULL;
- ret->cipher = cipher;
- return ret;
- }
- gcry_err_code_t
- grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher,
- const unsigned char *key,
- unsigned keylen)
- {
- return cipher->cipher->setkey (cipher->ctx, key, keylen);
- }
- gcry_err_code_t
- grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher,
- void *out, const void *in, grub_size_t size)
- {
- const grub_uint8_t *inptr, *end;
- grub_uint8_t *outptr;
- grub_size_t blocksize;
- if (!cipher->cipher->decrypt)
- return GPG_ERR_NOT_SUPPORTED;
- blocksize = cipher->cipher->blocksize;
- if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
- || ((size & (blocksize - 1)) != 0))
- return GPG_ERR_INV_ARG;
- end = (const grub_uint8_t *) in + size;
- for (inptr = in, outptr = out; inptr < end;
- inptr += blocksize, outptr += blocksize)
- cipher->cipher->decrypt (cipher->ctx, outptr, inptr);
- return GPG_ERR_NO_ERROR;
- }
- gcry_err_code_t
- grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher,
- void *out, const void *in, grub_size_t size)
- {
- const grub_uint8_t *inptr, *end;
- grub_uint8_t *outptr;
- grub_size_t blocksize;
- if (!cipher->cipher->encrypt)
- return GPG_ERR_NOT_SUPPORTED;
- blocksize = cipher->cipher->blocksize;
- if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
- || ((size & (blocksize - 1)) != 0))
- return GPG_ERR_INV_ARG;
- end = (const grub_uint8_t *) in + size;
- for (inptr = in, outptr = out; inptr < end;
- inptr += blocksize, outptr += blocksize)
- cipher->cipher->encrypt (cipher->ctx, outptr, inptr);
- return GPG_ERR_NO_ERROR;
- }
- gcry_err_code_t
- grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher,
- void *out, const void *in, grub_size_t size,
- void *iv_in)
- {
- grub_uint8_t *outptr;
- const grub_uint8_t *inptr, *end;
- void *iv;
- grub_size_t blocksize;
- if (!cipher->cipher->encrypt)
- return GPG_ERR_NOT_SUPPORTED;
- blocksize = cipher->cipher->blocksize;
- if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
- || ((size & (blocksize - 1)) != 0))
- return GPG_ERR_INV_ARG;
- end = (const grub_uint8_t *) in + size;
- iv = iv_in;
- for (inptr = in, outptr = out; inptr < end;
- inptr += blocksize, outptr += blocksize)
- {
- grub_crypto_xor (outptr, inptr, iv, blocksize);
- cipher->cipher->encrypt (cipher->ctx, outptr, outptr);
- iv = outptr;
- }
- grub_memcpy (iv_in, iv, blocksize);
- return GPG_ERR_NO_ERROR;
- }
- gcry_err_code_t
- grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher,
- void *out, const void *in, grub_size_t size,
- void *iv)
- {
- const grub_uint8_t *inptr, *end;
- grub_uint8_t *outptr;
- grub_uint8_t ivt[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE];
- grub_size_t blocksize;
- if (!cipher->cipher->decrypt)
- return GPG_ERR_NOT_SUPPORTED;
- blocksize = cipher->cipher->blocksize;
- if (blocksize == 0 || (((blocksize - 1) & blocksize) != 0)
- || ((size & (blocksize - 1)) != 0))
- return GPG_ERR_INV_ARG;
- if (blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
- return GPG_ERR_INV_ARG;
- end = (const grub_uint8_t *) in + size;
- for (inptr = in, outptr = out; inptr < end;
- inptr += blocksize, outptr += blocksize)
- {
- grub_memcpy (ivt, inptr, blocksize);
- cipher->cipher->decrypt (cipher->ctx, outptr, inptr);
- grub_crypto_xor (outptr, outptr, iv, blocksize);
- grub_memcpy (iv, ivt, blocksize);
- }
- return GPG_ERR_NO_ERROR;
- }
- /* Based on gcry/cipher/md.c. */
- struct grub_crypto_hmac_handle *
- grub_crypto_hmac_init (const struct gcry_md_spec *md,
- const void *key, grub_size_t keylen)
- {
- grub_uint8_t *helpkey = NULL;
- grub_uint8_t *ipad = NULL, *opad = NULL;
- void *ctx = NULL;
- struct grub_crypto_hmac_handle *ret = NULL;
- unsigned i;
- if (md->mdlen > md->blocksize)
- return NULL;
- ctx = grub_malloc (md->contextsize);
- if (!ctx)
- goto err;
- if ( keylen > md->blocksize )
- {
- helpkey = grub_malloc (md->mdlen);
- if (!helpkey)
- goto err;
- grub_crypto_hash (md, helpkey, key, keylen);
- key = helpkey;
- keylen = md->mdlen;
- }
- ipad = grub_zalloc (md->blocksize);
- if (!ipad)
- goto err;
- opad = grub_zalloc (md->blocksize);
- if (!opad)
- goto err;
- grub_memcpy ( ipad, key, keylen );
- grub_memcpy ( opad, key, keylen );
- for (i=0; i < md->blocksize; i++ )
- {
- ipad[i] ^= 0x36;
- opad[i] ^= 0x5c;
- }
- grub_free (helpkey);
- helpkey = NULL;
- md->init (ctx);
- md->write (ctx, ipad, md->blocksize); /* inner pad */
- grub_memset (ipad, 0, md->blocksize);
- grub_free (ipad);
- ipad = NULL;
- ret = grub_malloc (sizeof (*ret));
- if (!ret)
- goto err;
- ret->md = md;
- ret->ctx = ctx;
- ret->opad = opad;
- return ret;
- err:
- grub_free (helpkey);
- grub_free (ctx);
- grub_free (ipad);
- grub_free (opad);
- return NULL;
- }
- void
- grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd,
- const void *data,
- grub_size_t datalen)
- {
- hnd->md->write (hnd->ctx, data, datalen);
- }
- gcry_err_code_t
- grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out)
- {
- grub_uint8_t *p;
- grub_uint8_t *ctx2;
- ctx2 = grub_malloc (hnd->md->contextsize);
- if (!ctx2)
- return GPG_ERR_OUT_OF_MEMORY;
- hnd->md->final (hnd->ctx);
- hnd->md->read (hnd->ctx);
- p = hnd->md->read (hnd->ctx);
- hnd->md->init (ctx2);
- hnd->md->write (ctx2, hnd->opad, hnd->md->blocksize);
- hnd->md->write (ctx2, p, hnd->md->mdlen);
- hnd->md->final (ctx2);
- grub_memset (hnd->opad, 0, hnd->md->blocksize);
- grub_free (hnd->opad);
- grub_memset (hnd->ctx, 0, hnd->md->contextsize);
- grub_free (hnd->ctx);
- grub_memcpy (out, hnd->md->read (ctx2), hnd->md->mdlen);
- grub_memset (ctx2, 0, hnd->md->contextsize);
- grub_free (ctx2);
- grub_memset (hnd, 0, sizeof (*hnd));
- grub_free (hnd);
- return GPG_ERR_NO_ERROR;
- }
- gcry_err_code_t
- grub_crypto_hmac_buffer (const struct gcry_md_spec *md,
- const void *key, grub_size_t keylen,
- const void *data, grub_size_t datalen, void *out)
- {
- struct grub_crypto_hmac_handle *hnd;
- hnd = grub_crypto_hmac_init (md, key, keylen);
- if (!hnd)
- return GPG_ERR_OUT_OF_MEMORY;
- grub_crypto_hmac_write (hnd, data, datalen);
- return grub_crypto_hmac_fini (hnd, out);
- }
- grub_err_t
- grub_crypto_gcry_error (gcry_err_code_t in)
- {
- if (in == GPG_ERR_NO_ERROR)
- return GRUB_ERR_NONE;
- return GRUB_ACCESS_DENIED;
- }
- int
- grub_crypto_memcmp (const void *a, const void *b, grub_size_t n)
- {
- register grub_size_t counter = 0;
- const grub_uint8_t *pa, *pb;
- for (pa = a, pb = b; n; pa++, pb++, n--)
- {
- if (*pa != *pb)
- counter++;
- }
- return !!counter;
- }
- #ifndef GRUB_UTIL
- int
- grub_password_get (char buf[], unsigned buf_size)
- {
- unsigned cur_len = 0;
- int key;
- while (1)
- {
- key = grub_getkey ();
- if (key == '\n' || key == '\r')
- break;
- if (key == GRUB_TERM_ESC)
- {
- cur_len = 0;
- break;
- }
- if (key == '\b')
- {
- if (cur_len)
- cur_len--;
- continue;
- }
- if (!grub_isprint (key))
- continue;
- if (cur_len + 2 < buf_size)
- buf[cur_len++] = key;
- }
- grub_memset (buf + cur_len, 0, buf_size - cur_len);
- grub_xputs ("\n");
- grub_refresh ();
- return (key != GRUB_TERM_ESC);
- }
- #endif
|