/* * VasEBoot -- GRand Unified Bootloader * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 * 2007, 2008, 2009 Free Software Foundation, Inc. * * VasEBoot 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. * * VasEBoot 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 VasEBoot. If not, see . */ #include #include #include #include #include #include #include VasEBoot_MOD_LICENSE ("GPLv3+"); struct VasEBoot_crypto_hmac_handle { const struct gcry_md_spec *md; void *ctx; void *opad; }; static gcry_cipher_spec_t *VasEBoot_ciphers = NULL; static gcry_md_spec_t *VasEBoot_digests = NULL; void (*VasEBoot_crypto_autoload_hook) (const char *name) = NULL; /* Based on libgcrypt-1.4.4/src/misc.c. */ void VasEBoot_burn_stack (VasEBoot_size_t size) { char buf[64]; VasEBoot_memset (buf, 0, sizeof (buf)); if (size > sizeof (buf)) VasEBoot_burn_stack (size - sizeof (buf)); } void _gcry_burn_stack (int size) { VasEBoot_burn_stack (size); } void __attribute__ ((noreturn)) _gcry_assert_failed (const char *expr, const char *file, int line, const char *func) { VasEBoot_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 = VasEBoot_env_get ("debug"); if (! debug) return; if (VasEBoot_strword (debug, "all") || VasEBoot_strword (debug, "gcrypt")) { VasEBoot_printf ("gcrypt error: "); va_start (args, fmt); VasEBoot_vprintf (fmt, args); va_end (args); VasEBoot_refresh (); } } void VasEBoot_cipher_register (gcry_cipher_spec_t *cipher) { cipher->next = VasEBoot_ciphers; VasEBoot_ciphers = cipher; } void VasEBoot_cipher_unregister (gcry_cipher_spec_t *cipher) { gcry_cipher_spec_t **ciph; for (ciph = &VasEBoot_ciphers; *ciph; ciph = &((*ciph)->next)) if (*ciph == cipher) { *ciph = (*ciph)->next; break; } } void VasEBoot_md_register (gcry_md_spec_t *digest) { digest->next = VasEBoot_digests; VasEBoot_digests = digest; } void VasEBoot_md_unregister (gcry_md_spec_t *cipher) { gcry_md_spec_t **ciph; for (ciph = &VasEBoot_digests; *ciph; ciph = &((*ciph)->next)) if (*ciph == cipher) { *ciph = (*ciph)->next; break; } } void VasEBoot_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in, VasEBoot_size_t inlen) { VasEBoot_PROPERLY_ALIGNED_ARRAY (ctx, VasEBoot_CRYPTO_MAX_MD_CONTEXT_SIZE); if (hash->contextsize > sizeof (ctx)) VasEBoot_fatal ("Too large md context"); hash->init (&ctx); hash->write (&ctx, in, inlen); hash->final (&ctx); VasEBoot_memcpy (out, hash->read (&ctx), hash->mdlen); } const gcry_md_spec_t * VasEBoot_crypto_lookup_md_by_name (const char *name) { const gcry_md_spec_t *md; int first = 1; while (1) { for (md = VasEBoot_digests; md; md = md->next) if (VasEBoot_strcasecmp (name, md->name) == 0) return md; if (VasEBoot_crypto_autoload_hook && first) VasEBoot_crypto_autoload_hook (name); else return NULL; first = 0; } } const gcry_cipher_spec_t * VasEBoot_crypto_lookup_cipher_by_name (const char *name) { const gcry_cipher_spec_t *ciph; int first = 1; while (1) { for (ciph = VasEBoot_ciphers; ciph; ciph = ciph->next) { const char **alias; if (VasEBoot_strcasecmp (name, ciph->name) == 0) return ciph; if (!ciph->aliases) continue; for (alias = ciph->aliases; *alias; alias++) if (VasEBoot_strcasecmp (name, *alias) == 0) return ciph; } if (VasEBoot_crypto_autoload_hook && first) VasEBoot_crypto_autoload_hook (name); else return NULL; first = 0; } } VasEBoot_crypto_cipher_handle_t VasEBoot_crypto_cipher_open (const struct gcry_cipher_spec *cipher) { VasEBoot_crypto_cipher_handle_t ret; ret = VasEBoot_malloc (sizeof (*ret) + cipher->contextsize); if (!ret) return NULL; ret->cipher = cipher; return ret; } gcry_err_code_t VasEBoot_crypto_cipher_set_key (VasEBoot_crypto_cipher_handle_t cipher, const unsigned char *key, unsigned keylen) { return cipher->cipher->setkey (cipher->ctx, key, keylen); } gcry_err_code_t VasEBoot_crypto_ecb_decrypt (VasEBoot_crypto_cipher_handle_t cipher, void *out, const void *in, VasEBoot_size_t size) { const VasEBoot_uint8_t *inptr, *end; VasEBoot_uint8_t *outptr; VasEBoot_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 VasEBoot_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 VasEBoot_crypto_ecb_encrypt (VasEBoot_crypto_cipher_handle_t cipher, void *out, const void *in, VasEBoot_size_t size) { const VasEBoot_uint8_t *inptr, *end; VasEBoot_uint8_t *outptr; VasEBoot_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 VasEBoot_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 VasEBoot_crypto_cbc_encrypt (VasEBoot_crypto_cipher_handle_t cipher, void *out, const void *in, VasEBoot_size_t size, void *iv_in) { VasEBoot_uint8_t *outptr; const VasEBoot_uint8_t *inptr, *end; void *iv; VasEBoot_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 VasEBoot_uint8_t *) in + size; iv = iv_in; for (inptr = in, outptr = out; inptr < end; inptr += blocksize, outptr += blocksize) { VasEBoot_crypto_xor (outptr, inptr, iv, blocksize); cipher->cipher->encrypt (cipher->ctx, outptr, outptr); iv = outptr; } VasEBoot_memcpy (iv_in, iv, blocksize); return GPG_ERR_NO_ERROR; } gcry_err_code_t VasEBoot_crypto_cbc_decrypt (VasEBoot_crypto_cipher_handle_t cipher, void *out, const void *in, VasEBoot_size_t size, void *iv) { const VasEBoot_uint8_t *inptr, *end; VasEBoot_uint8_t *outptr; VasEBoot_uint8_t ivt[VasEBoot_CRYPTO_MAX_CIPHER_BLOCKSIZE]; VasEBoot_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 > VasEBoot_CRYPTO_MAX_CIPHER_BLOCKSIZE) return GPG_ERR_INV_ARG; end = (const VasEBoot_uint8_t *) in + size; for (inptr = in, outptr = out; inptr < end; inptr += blocksize, outptr += blocksize) { VasEBoot_memcpy (ivt, inptr, blocksize); cipher->cipher->decrypt (cipher->ctx, outptr, inptr); VasEBoot_crypto_xor (outptr, outptr, iv, blocksize); VasEBoot_memcpy (iv, ivt, blocksize); } return GPG_ERR_NO_ERROR; } /* Based on gcry/cipher/md.c. */ struct VasEBoot_crypto_hmac_handle * VasEBoot_crypto_hmac_init (const struct gcry_md_spec *md, const void *key, VasEBoot_size_t keylen) { VasEBoot_uint8_t *helpkey = NULL; VasEBoot_uint8_t *ipad = NULL, *opad = NULL; void *ctx = NULL; struct VasEBoot_crypto_hmac_handle *ret = NULL; unsigned i; if (md->mdlen > md->blocksize) return NULL; ctx = VasEBoot_malloc (md->contextsize); if (!ctx) goto err; if ( keylen > md->blocksize ) { helpkey = VasEBoot_malloc (md->mdlen); if (!helpkey) goto err; VasEBoot_crypto_hash (md, helpkey, key, keylen); key = helpkey; keylen = md->mdlen; } ipad = VasEBoot_zalloc (md->blocksize); if (!ipad) goto err; opad = VasEBoot_zalloc (md->blocksize); if (!opad) goto err; VasEBoot_memcpy ( ipad, key, keylen ); VasEBoot_memcpy ( opad, key, keylen ); for (i=0; i < md->blocksize; i++ ) { ipad[i] ^= 0x36; opad[i] ^= 0x5c; } VasEBoot_free (helpkey); helpkey = NULL; md->init (ctx); md->write (ctx, ipad, md->blocksize); /* inner pad */ VasEBoot_memset (ipad, 0, md->blocksize); VasEBoot_free (ipad); ipad = NULL; ret = VasEBoot_malloc (sizeof (*ret)); if (!ret) goto err; ret->md = md; ret->ctx = ctx; ret->opad = opad; return ret; err: VasEBoot_free (helpkey); VasEBoot_free (ctx); VasEBoot_free (ipad); VasEBoot_free (opad); return NULL; } void VasEBoot_crypto_hmac_write (struct VasEBoot_crypto_hmac_handle *hnd, const void *data, VasEBoot_size_t datalen) { hnd->md->write (hnd->ctx, data, datalen); } gcry_err_code_t VasEBoot_crypto_hmac_fini (struct VasEBoot_crypto_hmac_handle *hnd, void *out) { VasEBoot_uint8_t *p; VasEBoot_uint8_t *ctx2; ctx2 = VasEBoot_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); VasEBoot_memset (hnd->opad, 0, hnd->md->blocksize); VasEBoot_free (hnd->opad); VasEBoot_memset (hnd->ctx, 0, hnd->md->contextsize); VasEBoot_free (hnd->ctx); VasEBoot_memcpy (out, hnd->md->read (ctx2), hnd->md->mdlen); VasEBoot_memset (ctx2, 0, hnd->md->contextsize); VasEBoot_free (ctx2); VasEBoot_memset (hnd, 0, sizeof (*hnd)); VasEBoot_free (hnd); return GPG_ERR_NO_ERROR; } gcry_err_code_t VasEBoot_crypto_hmac_buffer (const struct gcry_md_spec *md, const void *key, VasEBoot_size_t keylen, const void *data, VasEBoot_size_t datalen, void *out) { struct VasEBoot_crypto_hmac_handle *hnd; hnd = VasEBoot_crypto_hmac_init (md, key, keylen); if (!hnd) return GPG_ERR_OUT_OF_MEMORY; VasEBoot_crypto_hmac_write (hnd, data, datalen); return VasEBoot_crypto_hmac_fini (hnd, out); } VasEBoot_err_t VasEBoot_crypto_gcry_error (gcry_err_code_t in) { if (in == GPG_ERR_NO_ERROR) return VasEBoot_ERR_NONE; return VasEBoot_ACCESS_DENIED; } int VasEBoot_crypto_memcmp (const void *a, const void *b, VasEBoot_size_t n) { register VasEBoot_size_t counter = 0; const VasEBoot_uint8_t *pa, *pb; for (pa = a, pb = b; n; pa++, pb++, n--) { if (*pa != *pb) counter++; } return !!counter; } #ifndef VasEBoot_UTIL int VasEBoot_password_get (char buf[], unsigned buf_size) { unsigned cur_len = 0; int key; while (1) { key = VasEBoot_getkey (); if (key == '\n' || key == '\r') break; if (key == '\e') { cur_len = 0; break; } if (key == '\b') { if (cur_len) cur_len--; continue; } if (!VasEBoot_isprint (key)) continue; if (cur_len + 2 < buf_size) buf[cur_len++] = key; } VasEBoot_memset (buf + cur_len, 0, buf_size - cur_len); VasEBoot_xputs ("\n"); VasEBoot_refresh (); return (key != '\e'); } #endif