From 414f919237bd02e53a11066fcdc0c08e9adc8e2e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 12 Nov 2009 18:08:44 +0100 Subject: [PATCH] Various cleanups and wrapper functions. Allocate disk id for LUKS. --- commands/xnu_uuid.c | 14 ++- import_gcry.py | 28 ++++++ include/grub/crypto.h | 202 +++++++++++++++++++++++++++++++++++------- include/grub/disk.h | 1 + 4 files changed, 206 insertions(+), 39 deletions(-) diff --git a/commands/xnu_uuid.c b/commands/xnu_uuid.c index d7f86276b..48c67d18e 100644 --- a/commands/xnu_uuid.c +++ b/commands/xnu_uuid.c @@ -33,8 +33,6 @@ #include #include -extern gcry_md_spec_t _gcry_digest_spec_md5; - /* This prefix is used by xnu and boot-132 to hash together with volume serial. */ static grub_uint8_t hash_prefix[16] @@ -49,18 +47,18 @@ grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)), grub_uint8_t *xnu_uuid; char uuid_string[sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]; char *ptr; - grub_uint8_t ctx[_gcry_digest_spec_md5.contextsize]; + grub_uint8_t ctx[GRUB_MD_MD5->contextsize]; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required"); serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16)); - _gcry_digest_spec_md5.init (&ctx); - _gcry_digest_spec_md5.write (&ctx, hash_prefix, sizeof (hash_prefix)); - _gcry_digest_spec_md5.write (&ctx, &serial, sizeof (serial)); - _gcry_digest_spec_md5.final (&ctx); - xnu_uuid = _gcry_digest_spec_md5.read (&ctx); + GRUB_MD_MD5->init (&ctx); + GRUB_MD_MD5->write (&ctx, hash_prefix, sizeof (hash_prefix)); + GRUB_MD_MD5->write (&ctx, &serial, sizeof (serial)); + GRUB_MD_MD5->final (&ctx); + xnu_uuid = GRUB_MD_MD5->read (&ctx); grub_sprintf (uuid_string, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", diff --git a/import_gcry.py b/import_gcry.py index ca03729af..39542d8c4 100644 --- a/import_gcry.py +++ b/import_gcry.py @@ -26,6 +26,20 @@ conf = open (os.path.join (outdir, "conf", "gcry.rmk"), "w") conf.write ("# -*- makefile -*-\n\n") chlog = "" +mdblocksizes = {"_gcry_digest_spec_crc32" : 1, + "_gcry_digest_spec_crc32_rfc1510" : 1, + "_gcry_digest_spec_crc24_rfc2440" : 1, + "_gcry_digest_spec_md4" : 64, + "_gcry_digest_spec_md5" : 64, + "_gcry_digest_spec_rmd160" : 64, + "_gcry_digest_spec_sha1" : 64, + "_gcry_digest_spec_sha224" : 64, + "_gcry_digest_spec_sha256" : 64, + "_gcry_digest_spec_sha384" : 128, + "_gcry_digest_spec_sha512" : 128, + "_gcry_digest_spec_tiger" : 64, + "_gcry_digest_spec_whirlpool" : 64} + for cipher_file in cipher_files: infile = os.path.join (cipher_dir_in, cipher_file) outfile = os.path.join (cipher_dir_out, cipher_file) @@ -44,6 +58,8 @@ for cipher_file in cipher_files: hold = False skip = False skip2 = False + ismd = False + iscomma = False for line in f: if skip: if line[0] == "}": @@ -53,6 +69,16 @@ for cipher_file in cipher_files: if not re.search (" *};", line) is None: skip2 = False continue + if ismd: + if not re.search (" *};", line) is None: + if not mdblocksizes.has_key (mdname): + print ("ERROR: Unknown digest blocksize: %s\n" % mdname) + exit (1) + if not iscomma: + fw.write (" ,\n") + fw.write (" .blocksize = %s\n" % mdblocksizes [mdname]) + ismd = False + iscomma = not re.search (",$", line) is None if hold: hold = False # We're optimising for size. @@ -85,9 +111,11 @@ for cipher_file in cipher_files: ciphernames.append (ciphername) m = re.match ("gcry_md_spec_t", line) if isc and not m is None: + assert (not ismd) mdname = line [len ("gcry_md_spec_t"):].strip () mdname = re.match("[a-zA-Z0-9_]*",mdname).group () mdnames.append (mdname) + ismd = True m = re.match ("static const char \*selftest.*;$", line) if not m is None: fname = line[len ("static const char \*"):] diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 17f14de86..239b46666 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -25,6 +25,8 @@ #include #include +#include +#include typedef enum { @@ -127,35 +129,6 @@ typedef struct gcry_cipher_spec struct gcry_cipher_spec *next; } gcry_cipher_spec_t; -/* Definition of a function used to report selftest failures. - DOMAIN is a string describing the function block: - "cipher", "digest", "pubkey or "random", - ALGO is the algorithm under test, - WHAT is a string describing what has been tested, - DESC is a string describing the error. */ -typedef void (*selftest_report_func_t)(const char *domain, - int algo, - const char *what, - const char *errdesc); - -/* Definition of the selftest functions. */ -typedef gpg_err_code_t (*selftest_func_t) - (int algo, int extended, selftest_report_func_t report); - -/* The type used to convey additional information to a cipher. */ -typedef gpg_err_code_t (*cipher_set_extra_info_t) - (void *c, int what, const void *buffer, grub_size_t buflen); - - -/* Extra module specification structures. These are used for internal - modules which provide more functions than available through the - public algorithm register APIs. */ -typedef struct cipher_extra_spec -{ - selftest_func_t selftest; - cipher_set_extra_info_t set_extra_info; -} cipher_extra_spec_t; - /* Type for the md_init function. */ typedef void (*gcry_md_init_t) (void *c); @@ -180,12 +153,14 @@ typedef struct gcry_md_spec unsigned char *asnoid; int asnlen; gcry_md_oid_spec_t *oids; - int mdlen; + grub_size_t mdlen; gcry_md_init_t init; gcry_md_write_t write; gcry_md_final_t final; gcry_md_read_t read; grub_size_t contextsize; /* allocate this amount of context */ + /* Block size, needed for HMAC. */ + grub_size_t blocksize; struct gcry_md_spec *next; } gcry_md_spec_t; @@ -199,7 +174,7 @@ grub_cipher_register (gcry_cipher_spec_t *cipher) grub_ciphers = cipher; } -static inline void +static inline void grub_cipher_unregister (gcry_cipher_spec_t *cipher) { gcry_cipher_spec_t **ciph; @@ -224,7 +199,172 @@ grub_md_unregister (gcry_md_spec_t *cipher) *ciph = (*ciph)->next; } +static inline void +grub_crypto_hash (const gcry_md_spec_t *hash, void *out, void *in, + grub_size_t inlen) +{ + grub_uint8_t ctx[hash->contextsize]; + hash->init (&ctx); + hash->write (&ctx, in, inlen); + hash->final (&ctx); + grub_memcpy (out, hash->read (&ctx), hash->mdlen); +} + +static inline const gcry_md_spec_t * +grub_crypto_lookup_md_by_name (const char *name) +{ + const gcry_md_spec_t *md; + for (md = grub_digests; md; md = md->next) + if (grub_strcasecmp (name, md->name) == 0) + return md; + return NULL; +} + +typedef struct grub_crypto_cipher_handle +{ + const struct gcry_cipher_spec *cipher; + char ctx[0]; +} *grub_crypto_cipher_handle_t; + +static inline const gcry_cipher_spec_t * +grub_crypto_lookup_cipher_by_name (const char *name) +{ + const gcry_cipher_spec_t *ciph; + 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; + } + return NULL; +} + + +static inline 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; +} + +static inline 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); +} + + +static inline void +grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher) +{ + grub_free (cipher); +} + + +static inline void +grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size) +{ + const grub_uint8_t *in1ptr = in1, *in2ptr = in2; + grub_uint8_t *outptr = out; + while (size--) + { + *outptr = *in1ptr ^ *in2ptr; + in1ptr++; + in2ptr++; + outptr++; + } +} + +static inline grub_err_t +grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size) +{ + grub_uint8_t *inptr, *outptr, *end; + if (size % cipher->cipher->blocksize != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "This encryption can't decrypt partial blocks"); + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + cipher->cipher->decrypt (cipher->ctx, outptr, inptr); + return GRUB_ERR_NONE; +} + +static inline grub_err_t +grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size) +{ + grub_uint8_t *inptr, *outptr, *end; + if (size % cipher->cipher->blocksize != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "This encryption can't decrypt partial blocks"); + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + cipher->cipher->encrypt (cipher->ctx, outptr, inptr); + return GRUB_ERR_NONE; +} + +static inline grub_err_t +grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv_in) +{ + grub_uint8_t *inptr, *outptr, *end; + void *iv; + if (size % cipher->cipher->blocksize != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "This encryption can't decrypt partial blocks"); + end = (grub_uint8_t *) in + size; + iv = iv_in; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + { + grub_crypto_xor (outptr, inptr, iv, cipher->cipher->blocksize); + cipher->cipher->encrypt (cipher->ctx, outptr, outptr); + iv = outptr; + } + grub_memcpy (iv_in, iv, cipher->cipher->blocksize); + return GRUB_ERR_NONE; +} + +static inline grub_err_t +grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv) +{ + grub_uint8_t *inptr, *outptr, *end; + grub_uint8_t ivt[cipher->cipher->blocksize]; + if (size % cipher->cipher->blocksize != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "This encryption can't decrypt partial blocks"); + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + { + grub_memcpy (ivt, inptr, cipher->cipher->blocksize); + cipher->cipher->decrypt (cipher->ctx, outptr, inptr); + grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize); + grub_memcpy (iv, ivt, cipher->cipher->blocksize); + } + return GRUB_ERR_NONE; +} + void EXPORT_FUNC(grub_burn_stack) (grub_size_t size); +extern gcry_md_spec_t _gcry_digest_spec_md5; +#define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5) + #endif diff --git a/include/grub/disk.h b/include/grub/disk.h index de71bb588..cc801bc67 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -42,6 +42,7 @@ enum grub_disk_dev_id GRUB_DISK_DEVICE_PXE_ID, GRUB_DISK_DEVICE_SCSI_ID, GRUB_DISK_DEVICE_FILE_ID, + GRUB_DISK_DEVICE_LUKS_ID }; struct grub_disk;