From 13988df650ab3b6f4909161d1f7cedac4f393a0f Mon Sep 17 00:00:00 2001 From: Nvinside Date: Tue, 28 Sep 2010 21:16:09 +0000 Subject: This is part 2 of 4, this also fixes some x64 errors, warnings and allow you to build a full debug unicode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit huuuuuge tipo fixes warning fixed (not all but many for this time) Prepare for a gpg-error change Support of ia32 AES instructions gpg error change Msvc compiler fixes Allow transient-key for ecdsa (würg-grund :D ) spelling fixes added new trigger events add a entropy gatherer for W32CE and some other stuff gcc fixes boooooooooooooost performance of SHA-512 and SHA-256 ... unfortunately that is all ;( ..... some work i'll be add maybe later this week git-svn-id: http://mirotr.googlecode.com/svn/trunk@38 eced67a3-f377-a0ae-92ae-d6de1850b05a --- libgcrypt-1.4.6/cipher/cipher.c | 4304 +++++++++++++++-------------- libgcrypt-1.4.6/cipher/ecc.c | 23 +- libgcrypt-1.4.6/cipher/md.c | 2764 +++++++++---------- libgcrypt-1.4.6/cipher/primegen.c | 3724 ++++++++++++------------- libgcrypt-1.4.6/cipher/pubkey.c | 5498 ++++++++++++++++++------------------- libgcrypt-1.4.6/cipher/rijndael.c | 2506 ++++++++--------- libgcrypt-1.4.6/cipher/serpent.c | 1956 ++++++------- libgcrypt-1.4.6/cipher/sha512.c | 1258 ++++----- 8 files changed, 11042 insertions(+), 10991 deletions(-) (limited to 'libgcrypt-1.4.6/cipher') diff --git a/libgcrypt-1.4.6/cipher/cipher.c b/libgcrypt-1.4.6/cipher/cipher.c index 8cfe54f..1948b91 100644 --- a/libgcrypt-1.4.6/cipher/cipher.c +++ b/libgcrypt-1.4.6/cipher/cipher.c @@ -1,2133 +1,2171 @@ -/* cipher.c - cipher dispatcher - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 - * 2005, 2007, 2008, 2010 Free Software Foundation, Inc. - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser general Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see . - */ - -#include -#include -#include -#include -#include - -#include "g10lib.h" -#include "cipher.h" -#include "ath.h" - -#define MAX_BLOCKSIZE 16 -#define TABLE_SIZE 14 -#define CTX_MAGIC_NORMAL 0x24091964 -#define CTX_MAGIC_SECURE 0x46919042 - -#undef NEED_16BYTE_ALIGNED_CONTEXT -#if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__) -#define NEED_16BYTE_ALIGNED_CONTEXT 1 -#endif - -/* A dummy extraspec so that we do not need to tests the extraspec - field from the module specification against NULL and instead - directly test the respective fields of extraspecs. */ -static cipher_extra_spec_t dummy_extra_spec; - -/* This is the list of the default ciphers, which are included in - libgcrypt. */ -static struct cipher_table_entry -{ - gcry_cipher_spec_t *cipher; - cipher_extra_spec_t *extraspec; - unsigned int algorithm; - int fips_allowed; -} cipher_table[] = - { -#if USE_BLOWFISH - { &_gcry_cipher_spec_blowfish, - &dummy_extra_spec, GCRY_CIPHER_BLOWFISH }, -#endif -#if USE_DES - { &_gcry_cipher_spec_des, - &dummy_extra_spec, GCRY_CIPHER_DES }, - { &_gcry_cipher_spec_tripledes, - &_gcry_cipher_extraspec_tripledes, GCRY_CIPHER_3DES, 1 }, -#endif -#if USE_ARCFOUR - { &_gcry_cipher_spec_arcfour, - &dummy_extra_spec, GCRY_CIPHER_ARCFOUR }, -#endif -#if USE_CAST5 - { &_gcry_cipher_spec_cast5, - &dummy_extra_spec, GCRY_CIPHER_CAST5 }, -#endif -#if USE_AES - { &_gcry_cipher_spec_aes, - &_gcry_cipher_extraspec_aes, GCRY_CIPHER_AES, 1 }, - { &_gcry_cipher_spec_aes192, - &_gcry_cipher_extraspec_aes192, GCRY_CIPHER_AES192, 1 }, - { &_gcry_cipher_spec_aes256, - &_gcry_cipher_extraspec_aes256, GCRY_CIPHER_AES256, 1 }, -#endif -#if USE_TWOFISH - { &_gcry_cipher_spec_twofish, - &dummy_extra_spec, GCRY_CIPHER_TWOFISH }, - { &_gcry_cipher_spec_twofish128, - &dummy_extra_spec, GCRY_CIPHER_TWOFISH128 }, -#endif -#if USE_SERPENT - { &_gcry_cipher_spec_serpent128, - &dummy_extra_spec, GCRY_CIPHER_SERPENT128 }, - { &_gcry_cipher_spec_serpent192, - &dummy_extra_spec, GCRY_CIPHER_SERPENT192 }, - { &_gcry_cipher_spec_serpent256, - &dummy_extra_spec, GCRY_CIPHER_SERPENT256 }, -#endif -#if USE_RFC2268 - { &_gcry_cipher_spec_rfc2268_40, - &dummy_extra_spec, GCRY_CIPHER_RFC2268_40 }, -#endif -#if USE_SEED - { &_gcry_cipher_spec_seed, - &dummy_extra_spec, GCRY_CIPHER_SEED }, -#endif -#if USE_CAMELLIA - { &_gcry_cipher_spec_camellia128, - &dummy_extra_spec, GCRY_CIPHER_CAMELLIA128 }, - { &_gcry_cipher_spec_camellia192, - &dummy_extra_spec, GCRY_CIPHER_CAMELLIA192 }, - { &_gcry_cipher_spec_camellia256, - &dummy_extra_spec, GCRY_CIPHER_CAMELLIA256 }, -#endif - { NULL } - }; - -/* List of registered ciphers. */ -static gcry_module_t ciphers_registered; - -/* This is the lock protecting CIPHERS_REGISTERED. */ -static ath_mutex_t ciphers_registered_lock = ATH_MUTEX_INITIALIZER; - -/* Flag to check wether the default ciphers have already been - registered. */ -static int default_ciphers_registered; - -/* Convenient macro for registering the default ciphers. */ -#define REGISTER_DEFAULT_CIPHERS \ - do \ - { \ - ath_mutex_lock (&ciphers_registered_lock); \ - if (! default_ciphers_registered) \ - { \ - cipher_register_default (); \ - default_ciphers_registered = 1; \ - } \ - ath_mutex_unlock (&ciphers_registered_lock); \ - } \ - while (0) - - -/* A VIA processor with the Padlock engine requires an alignment of - most data on a 16 byte boundary. Because we trick out the compiler - while allocating the context, the align attribute as used in - rijndael.c does not work on its own. Thus we need to make sure - that the entire context structure is a aligned on that boundary. - We achieve this by defining a new type and use that instead of our - usual alignment type. */ -typedef union -{ - PROPERLY_ALIGNED_TYPE foo; -#ifdef NEED_16BYTE_ALIGNED_CONTEXT - char bar[16] __attribute__ ((aligned (16))); -#endif - char c[1]; -} cipher_context_alignment_t; - - -/* The handle structure. */ -struct gcry_cipher_handle -{ - int magic; - size_t actual_handle_size; /* Allocated size of this handle. */ - size_t handle_offset; /* Offset to the malloced block. */ - gcry_cipher_spec_t *cipher; - cipher_extra_spec_t *extraspec; - gcry_module_t module; - - /* The algorithm id. This is a hack required because the module - interface does not easily allow to retrieve this value. */ - int algo; - - /* A structure with function pointers for bulk operations. Due to - limitations of the module system (we don't want to change the - API) we need to keep these function pointers here. The cipher - open function intializes them and the actual encryption routines - use them if they are not NULL. */ - struct { - void (*cfb_enc)(void *context, unsigned char *iv, - void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks); - void (*cfb_dec)(void *context, unsigned char *iv, - void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks); - void (*cbc_enc)(void *context, unsigned char *iv, - void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks, int cbc_mac); - void (*cbc_dec)(void *context, unsigned char *iv, - void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks); - } bulk; - - - int mode; - unsigned int flags; - - struct { - unsigned int key:1; /* Set to 1 if a key has been set. */ - unsigned int iv:1; /* Set to 1 if a IV has been set. */ - } marks; - - /* The initialization vector. To help code optimization we make - sure that it is aligned on an unsigned long and u32 boundary. */ - union { - unsigned long dummy_iv; - u32 dummy_u32_iv; - unsigned char iv[MAX_BLOCKSIZE]; - } u_iv; - - unsigned char lastiv[MAX_BLOCKSIZE]; - int unused; /* Number of unused bytes in the IV. */ - - unsigned char ctr[MAX_BLOCKSIZE]; /* For Counter (CTR) mode. */ - - - /* What follows are two contexts of the cipher in use. The first - one needs to be aligned well enough for the cipher operation - whereas the second one is a copy created by cipher_setkey and - used by cipher_reset. That second copy has no need for proper - aligment because it is only accessed by memcpy. */ - cipher_context_alignment_t context; -}; - - - -/* These dummy functions are used in case a cipher implementation - refuses to provide it's own functions. */ - -static gcry_err_code_t -dummy_setkey (void *c, const unsigned char *key, unsigned int keylen) -{ - (void)c; - (void)key; - (void)keylen; - return GPG_ERR_NO_ERROR; -} - -static void -dummy_encrypt_block (void *c, - unsigned char *outbuf, const unsigned char *inbuf) -{ - (void)c; - (void)outbuf; - (void)inbuf; - BUG(); -} - -static void -dummy_decrypt_block (void *c, - unsigned char *outbuf, const unsigned char *inbuf) -{ - (void)c; - (void)outbuf; - (void)inbuf; - BUG(); -} - -static void -dummy_encrypt_stream (void *c, - unsigned char *outbuf, const unsigned char *inbuf, - unsigned int n) -{ - (void)c; - (void)outbuf; - (void)inbuf; - (void)n; - BUG(); -} - -static void -dummy_decrypt_stream (void *c, - unsigned char *outbuf, const unsigned char *inbuf, - unsigned int n) -{ - (void)c; - (void)outbuf; - (void)inbuf; - (void)n; - BUG(); -} - - -/* Internal function. Register all the ciphers included in - CIPHER_TABLE. Note, that this function gets only used by the macro - REGISTER_DEFAULT_CIPHERS which protects it using a mutex. */ -static void -cipher_register_default (void) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - int i; - - for (i = 0; !err && cipher_table[i].cipher; i++) - { - if (! cipher_table[i].cipher->setkey) - cipher_table[i].cipher->setkey = dummy_setkey; - if (! cipher_table[i].cipher->encrypt) - cipher_table[i].cipher->encrypt = dummy_encrypt_block; - if (! cipher_table[i].cipher->decrypt) - cipher_table[i].cipher->decrypt = dummy_decrypt_block; - if (! cipher_table[i].cipher->stencrypt) - cipher_table[i].cipher->stencrypt = dummy_encrypt_stream; - if (! cipher_table[i].cipher->stdecrypt) - cipher_table[i].cipher->stdecrypt = dummy_decrypt_stream; - - if ( fips_mode () && !cipher_table[i].fips_allowed ) - continue; - - err = _gcry_module_add (&ciphers_registered, - cipher_table[i].algorithm, - (void *) cipher_table[i].cipher, - (void *) cipher_table[i].extraspec, - NULL); - } - - if (err) - BUG (); -} - -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_cipher_lookup_func_name (void *spec, void *data) -{ - gcry_cipher_spec_t *cipher = (gcry_cipher_spec_t *) spec; - char *name = (char *) data; - const char **aliases = cipher->aliases; - int i, ret = ! stricmp (name, cipher->name); - - if (aliases) - for (i = 0; aliases[i] && (! ret); i++) - ret = ! stricmp (name, aliases[i]); - - return ret; -} - -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_cipher_lookup_func_oid (void *spec, void *data) -{ - gcry_cipher_spec_t *cipher = (gcry_cipher_spec_t *) spec; - char *oid = (char *) data; - gcry_cipher_oid_spec_t *oid_specs = cipher->oids; - int ret = 0, i; - - if (oid_specs) - for (i = 0; oid_specs[i].oid && (! ret); i++) - if (! stricmp (oid, oid_specs[i].oid)) - ret = 1; - - return ret; -} - -/* Internal function. Lookup a cipher entry by it's name. */ -static gcry_module_t -gcry_cipher_lookup_name (const char *name) -{ - gcry_module_t cipher; - - cipher = _gcry_module_lookup (ciphers_registered, (void *) name, - gcry_cipher_lookup_func_name); - - return cipher; -} - -/* Internal function. Lookup a cipher entry by it's oid. */ -static gcry_module_t -gcry_cipher_lookup_oid (const char *oid) -{ - gcry_module_t cipher; - - cipher = _gcry_module_lookup (ciphers_registered, (void *) oid, - gcry_cipher_lookup_func_oid); - - return cipher; -} - -/* Register a new cipher module whose specification can be found in - CIPHER. On success, a new algorithm ID is stored in ALGORITHM_ID - and a pointer representhing this module is stored in MODULE. */ -gcry_error_t -_gcry_cipher_register (gcry_cipher_spec_t *cipher, - cipher_extra_spec_t *extraspec, - int *algorithm_id, - gcry_module_t *module) -{ - gcry_err_code_t err = 0; - gcry_module_t mod; - - /* We do not support module loading in fips mode. */ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - ath_mutex_lock (&ciphers_registered_lock); - err = _gcry_module_add (&ciphers_registered, 0, - (void *)cipher, - (void *)(extraspec? extraspec : &dummy_extra_spec), - &mod); - ath_mutex_unlock (&ciphers_registered_lock); - - if (! err) - { - *module = mod; - *algorithm_id = mod->mod_id; - } - - return gcry_error (err); -} - -/* Unregister the cipher identified by MODULE, which must have been - registered with gcry_cipher_register. */ -void -gcry_cipher_unregister (gcry_module_t module) -{ - ath_mutex_lock (&ciphers_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&ciphers_registered_lock); -} - -/* Locate the OID in the oid table and return the index or -1 when not - found. An opitonal "oid." or "OID." prefix in OID is ignored, the - OID is expected to be in standard IETF dotted notation. The - internal algorithm number is returned in ALGORITHM unless it - ispassed as NULL. A pointer to the specification of the module - implementing this algorithm is return in OID_SPEC unless passed as - NULL.*/ -static int -search_oid (const char *oid, int *algorithm, gcry_cipher_oid_spec_t *oid_spec) -{ - gcry_module_t module; - int ret = 0; - - if (oid && ((! strncmp (oid, "oid.", 4)) - || (! strncmp (oid, "OID.", 4)))) - oid += 4; - - module = gcry_cipher_lookup_oid (oid); - if (module) - { - gcry_cipher_spec_t *cipher = module->spec; - int i; - - for (i = 0; cipher->oids[i].oid && !ret; i++) - if (! stricmp (oid, cipher->oids[i].oid)) - { - if (algorithm) - *algorithm = module->mod_id; - if (oid_spec) - *oid_spec = cipher->oids[i]; - ret = 1; - } - _gcry_module_release (module); - } - - return ret; -} - -/* Map STRING to the cipher algorithm identifier. Returns the - algorithm ID of the cipher for the given name or 0 if the name is - not known. It is valid to pass NULL for STRING which results in a - return value of 0. */ -int -gcry_cipher_map_name (const char *string) -{ - gcry_module_t cipher; - int ret, algorithm = 0; - - if (! string) - return 0; - - REGISTER_DEFAULT_CIPHERS; - - /* If the string starts with a digit (optionally prefixed with - either "OID." or "oid."), we first look into our table of ASN.1 - object identifiers to figure out the algorithm */ - - ath_mutex_lock (&ciphers_registered_lock); - - ret = search_oid (string, &algorithm, NULL); - if (! ret) - { - cipher = gcry_cipher_lookup_name (string); - if (cipher) - { - algorithm = cipher->mod_id; - _gcry_module_release (cipher); - } - } - - ath_mutex_unlock (&ciphers_registered_lock); - - return algorithm; -} - - -/* Given a STRING with an OID in dotted decimal notation, this - function returns the cipher mode (GCRY_CIPHER_MODE_*) associated - with that OID or 0 if no mode is known. Passing NULL for string - yields a return value of 0. */ -int -gcry_cipher_mode_from_oid (const char *string) -{ - gcry_cipher_oid_spec_t oid_spec; - int ret = 0, mode = 0; - - if (!string) - return 0; - - ath_mutex_lock (&ciphers_registered_lock); - ret = search_oid (string, NULL, &oid_spec); - if (ret) - mode = oid_spec.mode; - ath_mutex_unlock (&ciphers_registered_lock); - - return mode; -} - - -/* Map the cipher algorithm whose ID is contained in ALGORITHM to a - string representation of the algorithm name. For unknown algorithm - IDs this function returns "?". */ -static const char * -cipher_algo_to_string (int algorithm) -{ - gcry_module_t cipher; - const char *name; - - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) - { - name = ((gcry_cipher_spec_t *) cipher->spec)->name; - _gcry_module_release (cipher); - } - else - name = "?"; - ath_mutex_unlock (&ciphers_registered_lock); - - return name; -} - -/* Map the cipher algorithm identifier ALGORITHM to a string - representing this algorithm. This string is the default name as - used by Libgcrypt. An pointer to an empty string is returned for - an unknown algorithm. NULL is never returned. */ -const char * -gcry_cipher_algo_name (int algorithm) -{ - return cipher_algo_to_string (algorithm); -} - - -/* Flag the cipher algorithm with the identifier ALGORITHM as - disabled. There is no error return, the function does nothing for - unknown algorithms. Disabled algorithms are vitually not available - in Libgcrypt. */ -static void -disable_cipher_algo (int algorithm) -{ - gcry_module_t cipher; - - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) - { - if (! (cipher->flags & FLAG_MODULE_DISABLED)) - cipher->flags |= FLAG_MODULE_DISABLED; - _gcry_module_release (cipher); - } - ath_mutex_unlock (&ciphers_registered_lock); -} - - -/* Return 0 if the cipher algorithm with identifier ALGORITHM is - available. Returns a basic error code value if it is not - available. */ -static gcry_err_code_t -check_cipher_algo (int algorithm) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_module_t cipher; - - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) - { - if (cipher->flags & FLAG_MODULE_DISABLED) - err = GPG_ERR_CIPHER_ALGO; - _gcry_module_release (cipher); - } - else - err = GPG_ERR_CIPHER_ALGO; - ath_mutex_unlock (&ciphers_registered_lock); - - return err; -} - - -/* Return the standard length of the key for the cipher algorithm with - the identifier ALGORITHM. This function expects a valid algorithm - and will abort if the algorithm is not available or the length of - the key is not known. */ -static unsigned int -cipher_get_keylen (int algorithm) -{ - gcry_module_t cipher; - unsigned len = 0; - - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) - { - len = ((gcry_cipher_spec_t *) cipher->spec)->keylen; - if (!len) - log_bug ("cipher %d w/o key length\n", algorithm); - _gcry_module_release (cipher); - } - else - log_bug ("cipher %d not found\n", algorithm); - ath_mutex_unlock (&ciphers_registered_lock); - - return len; -} - -/* Return the block length of the cipher algorithm with the identifier - ALGORITHM. This function expects a valid algorithm and will abort - if the algorithm is not available or the length of the key is not - known. */ -static unsigned int -cipher_get_blocksize (int algorithm) -{ - gcry_module_t cipher; - unsigned len = 0; - - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) - { - len = ((gcry_cipher_spec_t *) cipher->spec)->blocksize; - if (! len) - log_bug ("cipher %d w/o blocksize\n", algorithm); - _gcry_module_release (cipher); - } - else - log_bug ("cipher %d not found\n", algorithm); - ath_mutex_unlock (&ciphers_registered_lock); - - return len; -} - - -/* - Open a cipher handle for use with cipher algorithm ALGORITHM, using - the cipher mode MODE (one of the GCRY_CIPHER_MODE_*) and return a - handle in HANDLE. Put NULL into HANDLE and return an error code if - something goes wrong. FLAGS may be used to modify the - operation. The defined flags are: - - GCRY_CIPHER_SECURE: allocate all internal buffers in secure memory. - GCRY_CIPHER_ENABLE_SYNC: Enable the sync operation as used in OpenPGP. - GCRY_CIPHER_CBC_CTS: Enable CTS mode. - GCRY_CIPHER_CBC_MAC: Enable MAC mode. - - Values for these flags may be combined using OR. - */ -gcry_error_t -gcry_cipher_open (gcry_cipher_hd_t *handle, - int algo, int mode, unsigned int flags) -{ - int secure = (flags & GCRY_CIPHER_SECURE); - gcry_cipher_spec_t *cipher = NULL; - cipher_extra_spec_t *extraspec = NULL; - gcry_module_t module = NULL; - gcry_cipher_hd_t h = NULL; - gcry_err_code_t err = 0; - - /* If the application missed to call the random poll function, we do - it here to ensure that it is used once in a while. */ - _gcry_fast_random_poll (); - - REGISTER_DEFAULT_CIPHERS; - - /* Fetch the according module and check wether the cipher is marked - available for use. */ - ath_mutex_lock (&ciphers_registered_lock); - module = _gcry_module_lookup_id (ciphers_registered, algo); - if (module) - { - /* Found module. */ - - if (module->flags & FLAG_MODULE_DISABLED) - { - /* Not available for use. */ - err = GPG_ERR_CIPHER_ALGO; - _gcry_module_release (module); - } - else - { - cipher = (gcry_cipher_spec_t *) module->spec; - extraspec = module->extraspec; - } - } - else - err = GPG_ERR_CIPHER_ALGO; - ath_mutex_unlock (&ciphers_registered_lock); - - /* check flags */ - if ((! err) - && ((flags & ~(0 - | GCRY_CIPHER_SECURE - | GCRY_CIPHER_ENABLE_SYNC - | GCRY_CIPHER_CBC_CTS - | GCRY_CIPHER_CBC_MAC)) - || (flags & GCRY_CIPHER_CBC_CTS & GCRY_CIPHER_CBC_MAC))) - err = GPG_ERR_CIPHER_ALGO; - - /* check that a valid mode has been requested */ - if (! err) - switch (mode) - { - case GCRY_CIPHER_MODE_ECB: - case GCRY_CIPHER_MODE_CBC: - case GCRY_CIPHER_MODE_CFB: - case GCRY_CIPHER_MODE_OFB: - case GCRY_CIPHER_MODE_CTR: - case GCRY_CIPHER_MODE_AESWRAP: - if ((cipher->encrypt == dummy_encrypt_block) - || (cipher->decrypt == dummy_decrypt_block)) - err = GPG_ERR_INV_CIPHER_MODE; - break; - - case GCRY_CIPHER_MODE_STREAM: - if ((cipher->stencrypt == dummy_encrypt_stream) - || (cipher->stdecrypt == dummy_decrypt_stream)) - err = GPG_ERR_INV_CIPHER_MODE; - break; - - case GCRY_CIPHER_MODE_NONE: - /* This mode may be used for debugging. It copies the main - text verbatim to the ciphertext. We do not allow this in - fips mode or if no debug flag has been set. */ - if (fips_mode () || !_gcry_get_debug_flag (0)) - err = GPG_ERR_INV_CIPHER_MODE; - break; - - default: - err = GPG_ERR_INV_CIPHER_MODE; - } - - /* Perform selftest here and mark this with a flag in cipher_table? - No, we should not do this as it takes too long. Further it does - not make sense to exclude algorithms with failing selftests at - runtime: If a selftest fails there is something seriously wrong - with the system and thus we better die immediately. */ - - if (! err) - { - size_t size = (sizeof (*h) - + 2 * cipher->contextsize - - sizeof (cipher_context_alignment_t) -#ifdef NEED_16BYTE_ALIGNED_CONTEXT - + 15 /* Space for leading alignment gap. */ -#endif /*NEED_16BYTE_ALIGNED_CONTEXT*/ - ); - - if (secure) - h = gcry_calloc_secure (1, size); - else - h = gcry_calloc (1, size); - - if (! h) - err = gpg_err_code_from_errno (errno); - else - { - size_t off = 0; - -#ifdef NEED_16BYTE_ALIGNED_CONTEXT - if ( ((unsigned long)h & 0x0f) ) - { - /* The malloced block is not aligned on a 16 byte - boundary. Correct for this. */ - off = 16 - ((unsigned long)h & 0x0f); - h = (void*)((char*)h + off); - } -#endif /*NEED_16BYTE_ALIGNED_CONTEXT*/ - - h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; - h->actual_handle_size = size - off; - h->handle_offset = off; - h->cipher = cipher; - h->extraspec = extraspec; - h->module = module; - h->algo = algo; - h->mode = mode; - h->flags = flags; - - /* Setup bulk encryption routines. */ - switch (algo) - { -#ifdef USE_AES - case GCRY_CIPHER_AES128: - case GCRY_CIPHER_AES192: - case GCRY_CIPHER_AES256: - h->bulk.cfb_enc = _gcry_aes_cfb_enc; - h->bulk.cfb_dec = _gcry_aes_cfb_dec; - h->bulk.cbc_enc = _gcry_aes_cbc_enc; - h->bulk.cbc_dec = _gcry_aes_cbc_dec; - break; -#endif /*USE_AES*/ - - default: - break; - } - } - } - - /* Done. */ - - if (err) - { - if (module) - { - /* Release module. */ - ath_mutex_lock (&ciphers_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&ciphers_registered_lock); - } - } - - *handle = err ? NULL : h; - - return gcry_error (err); -} - - -/* Release all resources associated with the cipher handle H. H may be - NULL in which case this is a no-operation. */ -void -gcry_cipher_close (gcry_cipher_hd_t h) -{ - size_t off; - - if (!h) - return; - - if ((h->magic != CTX_MAGIC_SECURE) - && (h->magic != CTX_MAGIC_NORMAL)) - _gcry_fatal_error(GPG_ERR_INTERNAL, - "gcry_cipher_close: already closed/invalid handle"); - else - h->magic = 0; - - /* Release module. */ - ath_mutex_lock (&ciphers_registered_lock); - _gcry_module_release (h->module); - ath_mutex_unlock (&ciphers_registered_lock); - - /* We always want to wipe out the memory even when the context has - been allocated in secure memory. The user might have disabled - secure memory or is using his own implementation which does not - do the wiping. To accomplish this we need to keep track of the - actual size of this structure because we have no way to known - how large the allocated area was when using a standard malloc. */ - off = h->handle_offset; - wipememory (h, h->actual_handle_size); - - gcry_free ((char*)h - off); -} - - -/* Set the key to be used for the encryption context C to KEY with - length KEYLEN. The length should match the required length. */ -static gcry_error_t -cipher_setkey (gcry_cipher_hd_t c, byte *key, unsigned int keylen) -{ - gcry_err_code_t ret; - - ret = (*c->cipher->setkey) (&c->context.c, key, keylen); - if (!ret) - { - /* Duplicate initial context. */ - memcpy ((void *) ((char *) &c->context.c + c->cipher->contextsize), - (void *) &c->context.c, - c->cipher->contextsize); - c->marks.key = 1; - } - else - c->marks.key = 0; - - return gcry_error (ret); -} - - -/* Set the IV to be used for the encryption context C to IV with - length IVLEN. The length should match the required length. */ -static void -cipher_setiv( gcry_cipher_hd_t c, const byte *iv, unsigned ivlen ) -{ - memset (c->u_iv.iv, 0, c->cipher->blocksize); - if (iv) - { - if (ivlen != c->cipher->blocksize) - { - log_info ("WARNING: cipher_setiv: ivlen=%u blklen=%u\n", - ivlen, (unsigned int)c->cipher->blocksize); - fips_signal_error ("IV length does not match blocklength"); - } - if (ivlen > c->cipher->blocksize) - ivlen = c->cipher->blocksize; - memcpy (c->u_iv.iv, iv, ivlen); - c->marks.iv = 1; - } - else - c->marks.iv = 0; - - c->unused = 0; -} - - -/* Reset the cipher context to the initial context. This is basically - the same as an release followed by a new. */ -static void -cipher_reset (gcry_cipher_hd_t c) -{ - memcpy (&c->context.c, - (char *) &c->context.c + c->cipher->contextsize, - c->cipher->contextsize); - memset (&c->marks, 0, sizeof c->marks); - memset (c->u_iv.iv, 0, c->cipher->blocksize); - memset (c->lastiv, 0, c->cipher->blocksize); - memset (c->ctr, 0, c->cipher->blocksize); -} - - -static void -do_ecb_encrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, - unsigned int nblocks ) -{ - unsigned int n; - - for (n=0; n < nblocks; n++ ) - { - c->cipher->encrypt ( &c->context.c, outbuf, (byte*)/*arggg*/inbuf ); - inbuf += c->cipher->blocksize; - outbuf += c->cipher->blocksize; - } -} - -static void -do_ecb_decrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, - unsigned int nblocks ) -{ - unsigned int n; - - for (n=0; n < nblocks; n++ ) - { - c->cipher->decrypt ( &c->context.c, outbuf, (byte*)/*arggg*/inbuf ); - inbuf += c->cipher->blocksize; - outbuf += c->cipher->blocksize; - } -} - - -static void -do_cbc_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf, - const unsigned char *inbuf, unsigned int nbytes ) -{ - unsigned int n; - unsigned char *ivp; - int i; - size_t blocksize = c->cipher->blocksize; - unsigned nblocks = nbytes / blocksize; - - if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) - { - if ((nbytes % blocksize) == 0) - nblocks--; - } - - if (c->bulk.cbc_enc) - { - c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks, - (c->flags & GCRY_CIPHER_CBC_MAC)); - inbuf += nblocks * blocksize; - if (!(c->flags & GCRY_CIPHER_CBC_MAC)) - outbuf += nblocks * blocksize; - } - else - { - for (n=0; n < nblocks; n++ ) - { - for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - outbuf[i] = inbuf[i] ^ *ivp++; - c->cipher->encrypt ( &c->context.c, outbuf, outbuf ); - memcpy (c->u_iv.iv, outbuf, blocksize ); - inbuf += blocksize; - if (!(c->flags & GCRY_CIPHER_CBC_MAC)) - outbuf += blocksize; - } - } - - if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) - { - /* We have to be careful here, since outbuf might be equal to - inbuf. */ - int restbytes; - unsigned char b; - - if ((nbytes % blocksize) == 0) - restbytes = blocksize; - else - restbytes = nbytes % blocksize; - - outbuf -= blocksize; - for (ivp = c->u_iv.iv, i = 0; i < restbytes; i++) - { - b = inbuf[i]; - outbuf[blocksize + i] = outbuf[i]; - outbuf[i] = b ^ *ivp++; - } - for (; i < blocksize; i++) - outbuf[i] = 0 ^ *ivp++; - - c->cipher->encrypt (&c->context.c, outbuf, outbuf); - memcpy (c->u_iv.iv, outbuf, blocksize); - } -} - - -static void -do_cbc_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, - const unsigned char *inbuf, unsigned int nbytes) -{ - unsigned int n; - unsigned char *ivp; - int i; - size_t blocksize = c->cipher->blocksize; - unsigned int nblocks = nbytes / blocksize; - - if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) - { - nblocks--; - if ((nbytes % blocksize) == 0) - nblocks--; - memcpy (c->lastiv, c->u_iv.iv, blocksize); - } - - if (c->bulk.cbc_dec) - { - c->bulk.cbc_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); - inbuf += nblocks * blocksize; - outbuf += nblocks * blocksize; - } - else - { - for (n=0; n < nblocks; n++ ) - { - /* Because outbuf and inbuf might be the same, we have to - * save the original ciphertext block. We use LASTIV for - * this here because it is not used otherwise. */ - memcpy (c->lastiv, inbuf, blocksize); - c->cipher->decrypt ( &c->context.c, outbuf, inbuf ); - for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - outbuf[i] ^= *ivp++; - memcpy(c->u_iv.iv, c->lastiv, blocksize ); - inbuf += c->cipher->blocksize; - outbuf += c->cipher->blocksize; - } - } - - if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) - { - int restbytes; - - if ((nbytes % blocksize) == 0) - restbytes = blocksize; - else - restbytes = nbytes % blocksize; - - memcpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */ - memcpy (c->u_iv.iv, inbuf + blocksize, restbytes ); /* Save Cn. */ - - c->cipher->decrypt ( &c->context.c, outbuf, inbuf ); - for (ivp=c->u_iv.iv,i=0; i < restbytes; i++ ) - outbuf[i] ^= *ivp++; - - memcpy(outbuf + blocksize, outbuf, restbytes); - for(i=restbytes; i < blocksize; i++) - c->u_iv.iv[i] = outbuf[i]; - c->cipher->decrypt (&c->context.c, outbuf, c->u_iv.iv); - for(ivp=c->lastiv,i=0; i < blocksize; i++ ) - outbuf[i] ^= *ivp++; - /* c->lastiv is now really lastlastiv, does this matter? */ - } -} - - -static void -do_cfb_encrypt( gcry_cipher_hd_t c, unsigned char *outbuf, - const unsigned char *inbuf, unsigned int nbytes ) -{ - unsigned char *ivp; - size_t blocksize = c->cipher->blocksize; - size_t blocksize_x_2 = blocksize + blocksize; - - if ( nbytes <= c->unused ) - { - /* Short enough to be encoded by the remaining XOR mask. */ - /* XOR the input with the IV and store input into IV. */ - for (ivp=c->u_iv.iv+c->cipher->blocksize - c->unused; - nbytes; - nbytes--, c->unused-- ) - *outbuf++ = (*ivp++ ^= *inbuf++); - return; - } - - if ( c->unused ) - { - /* XOR the input with the IV and store input into IV */ - nbytes -= c->unused; - for(ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) - *outbuf++ = (*ivp++ ^= *inbuf++); - } - - /* Now we can process complete blocks. We use a loop as long as we - have at least 2 blocks and use conditions for the rest. This - also allows to use a bulk encryption function if available. */ - if (nbytes >= blocksize_x_2 && c->bulk.cfb_enc) - { - unsigned int nblocks = nbytes / blocksize; - c->bulk.cfb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); - outbuf += nblocks * blocksize; - inbuf += nblocks * blocksize; - nbytes -= nblocks * blocksize; - } - else - { - while ( nbytes >= blocksize_x_2 ) - { - int i; - /* Encrypt the IV. */ - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - /* XOR the input with the IV and store input into IV. */ - for(ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - *outbuf++ = (*ivp++ ^= *inbuf++); - nbytes -= blocksize; - } - } - - if ( nbytes >= blocksize ) - { - int i; - /* Save the current IV and then encrypt the IV. */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - /* XOR the input with the IV and store input into IV */ - for(ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - *outbuf++ = (*ivp++ ^= *inbuf++); - nbytes -= blocksize; - } - if ( nbytes ) - { - /* Save the current IV and then encrypt the IV. */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - c->unused = blocksize; - /* Apply the XOR. */ - c->unused -= nbytes; - for(ivp=c->u_iv.iv; nbytes; nbytes-- ) - *outbuf++ = (*ivp++ ^= *inbuf++); - } -} - - -static void -do_cfb_decrypt( gcry_cipher_hd_t c, unsigned char *outbuf, - const unsigned char *inbuf, unsigned int nbytes ) -{ - unsigned char *ivp; - unsigned long temp; - int i; - size_t blocksize = c->cipher->blocksize; - size_t blocksize_x_2 = blocksize + blocksize; - - if (nbytes <= c->unused) - { - /* Short enough to be encoded by the remaining XOR mask. */ - /* XOR the input with the IV and store input into IV. */ - for (ivp=c->u_iv.iv+blocksize - c->unused; - nbytes; - nbytes--, c->unused--) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } - return; - } - - if (c->unused) - { - /* XOR the input with the IV and store input into IV. */ - nbytes -= c->unused; - for (ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } - } - - /* Now we can process complete blocks. We use a loop as long as we - have at least 2 blocks and use conditions for the rest. This - also allows to use a bulk encryption function if available. */ - if (nbytes >= blocksize_x_2 && c->bulk.cfb_dec) - { - unsigned int nblocks = nbytes / blocksize; - c->bulk.cfb_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); - outbuf += nblocks * blocksize; - inbuf += nblocks * blocksize; - nbytes -= nblocks * blocksize; - } - else - { - while (nbytes >= blocksize_x_2 ) - { - /* Encrypt the IV. */ - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - /* XOR the input with the IV and store input into IV. */ - for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } - nbytes -= blocksize; - } - } - - if (nbytes >= blocksize ) - { - /* Save the current IV and then encrypt the IV. */ - memcpy ( c->lastiv, c->u_iv.iv, blocksize); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - /* XOR the input with the IV and store input into IV */ - for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } - nbytes -= blocksize; - } - - if (nbytes) - { - /* Save the current IV and then encrypt the IV. */ - memcpy ( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - c->unused = blocksize; - /* Apply the XOR. */ - c->unused -= nbytes; - for (ivp=c->u_iv.iv; nbytes; nbytes-- ) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } - } -} - - -static void -do_ofb_encrypt( gcry_cipher_hd_t c, - byte *outbuf, const byte *inbuf, unsigned nbytes ) -{ - byte *ivp; - size_t blocksize = c->cipher->blocksize; - - if ( nbytes <= c->unused ) - { - /* Short enough to be encoded by the remaining XOR mask. */ - /* XOR the input with the IV */ - for (ivp=c->u_iv.iv+c->cipher->blocksize - c->unused; - nbytes; - nbytes--, c->unused-- ) - *outbuf++ = (*ivp++ ^ *inbuf++); - return; - } - - if( c->unused ) - { - nbytes -= c->unused; - for(ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) - *outbuf++ = (*ivp++ ^ *inbuf++); - } - - /* Now we can process complete blocks. */ - while ( nbytes >= blocksize ) - { - int i; - /* Encrypt the IV (and save the current one). */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - - for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - *outbuf++ = (*ivp++ ^ *inbuf++); - nbytes -= blocksize; - } - if ( nbytes ) - { /* process the remaining bytes */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - c->unused = blocksize; - c->unused -= nbytes; - for(ivp=c->u_iv.iv; nbytes; nbytes-- ) - *outbuf++ = (*ivp++ ^ *inbuf++); - } -} - -static void -do_ofb_decrypt( gcry_cipher_hd_t c, - byte *outbuf, const byte *inbuf, unsigned int nbytes ) -{ - byte *ivp; - size_t blocksize = c->cipher->blocksize; - - if( nbytes <= c->unused ) - { - /* Short enough to be encoded by the remaining XOR mask. */ - for (ivp=c->u_iv.iv+blocksize - c->unused; nbytes; nbytes--,c->unused--) - *outbuf++ = *ivp++ ^ *inbuf++; - return; - } - - if ( c->unused ) - { - nbytes -= c->unused; - for (ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) - *outbuf++ = *ivp++ ^ *inbuf++; - } - - /* Now we can process complete blocks. */ - while ( nbytes >= blocksize ) - { - int i; - /* Encrypt the IV (and save the current one). */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - *outbuf++ = *ivp++ ^ *inbuf++; - nbytes -= blocksize; - } - if ( nbytes ) - { /* Process the remaining bytes. */ - /* Encrypt the IV (and save the current one). */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - c->unused = blocksize; - c->unused -= nbytes; - for (ivp=c->u_iv.iv; nbytes; nbytes-- ) - *outbuf++ = *ivp++ ^ *inbuf++; - } -} - - -static void -do_ctr_encrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, - unsigned int nbytes ) -{ - unsigned int n; - byte tmp[MAX_BLOCKSIZE]; - int i; - - for(n=0; n < nbytes; n++) - { - if ((n % c->cipher->blocksize) == 0) - { - c->cipher->encrypt (&c->context.c, tmp, c->ctr); - - for (i = c->cipher->blocksize; i > 0; i--) - { - c->ctr[i-1]++; - if (c->ctr[i-1] != 0) - break; - } - } - - /* XOR input with encrypted counter and store in output. */ - outbuf[n] = inbuf[n] ^ tmp[n % c->cipher->blocksize]; - } -} - -static void -do_ctr_decrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, - unsigned int nbytes ) -{ - do_ctr_encrypt (c, outbuf, inbuf, nbytes); -} - - -/* Perform the AES-Wrap algorithm as specified by RFC3394. We - implement this as a mode usable with any cipher algorithm of - blocksize 128. */ -static gcry_err_code_t -do_aeswrap_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, - const byte *inbuf, unsigned int inbuflen ) -{ - int j, x; - unsigned int n, i; - unsigned char *r, *a, *b; - unsigned char t[8]; - -#if MAX_BLOCKSIZE < 8 -#error Invalid block size -#endif - /* We require a cipher with a 128 bit block length. */ - if (c->cipher->blocksize != 16) - return GPG_ERR_INV_LENGTH; - - /* The output buffer must be able to hold the input data plus one - additional block. */ - if (outbuflen < inbuflen + 8) - return GPG_ERR_BUFFER_TOO_SHORT; - /* Input data must be multiple of 64 bits. */ - if (inbuflen % 8) - return GPG_ERR_INV_ARG; - - n = inbuflen / 8; - - /* We need at least two 64 bit blocks. */ - if (n < 2) - return GPG_ERR_INV_ARG; - - r = outbuf; - a = outbuf; /* We store A directly in OUTBUF. */ - b = c->ctr; /* B is also used to concatenate stuff. */ - - /* If an IV has been set we use that IV as the Alternative Initial - Value; if it has not been set we use the standard value. */ - if (c->marks.iv) - memcpy (a, c->u_iv.iv, 8); - else - memset (a, 0xa6, 8); - - /* Copy the inbuf to the outbuf. */ - memmove (r+8, inbuf, inbuflen); - - memset (t, 0, sizeof t); /* t := 0. */ - - for (j = 0; j <= 5; j++) - { - for (i = 1; i <= n; i++) - { - /* B := AES_k( A | R[i] ) */ - memcpy (b, a, 8); - memcpy (b+8, r+i*8, 8); - c->cipher->encrypt (&c->context.c, b, b); - /* t := t + 1 */ - for (x = 7; x >= 0; x--) - { - t[x]++; - if (t[x]) - break; - } - /* A := MSB_64(B) ^ t */ - for (x=0; x < 8; x++) - a[x] = b[x] ^ t[x]; - /* R[i] := LSB_64(B) */ - memcpy (r+i*8, b+8, 8); - } - } - - return 0; -} - -/* Perform the AES-Unwrap algorithm as specified by RFC3394. We - implement this as a mode usable with any cipher algorithm of - blocksize 128. */ -static gcry_err_code_t -do_aeswrap_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, - const byte *inbuf, unsigned int inbuflen) -{ - int j, x; - unsigned int n, i; - unsigned char *r, *a, *b; - unsigned char t[8]; - -#if MAX_BLOCKSIZE < 8 -#error Invalid block size -#endif - /* We require a cipher with a 128 bit block length. */ - if (c->cipher->blocksize != 16) - return GPG_ERR_INV_LENGTH; - - /* The output buffer must be able to hold the input data minus one - additional block. Fixme: The caller has more restrictive checks - - we may want to fix them for this mode. */ - if (outbuflen + 8 < inbuflen) - return GPG_ERR_BUFFER_TOO_SHORT; - /* Input data must be multiple of 64 bits. */ - if (inbuflen % 8) - return GPG_ERR_INV_ARG; - - n = inbuflen / 8; - - /* We need at least three 64 bit blocks. */ - if (n < 3) - return GPG_ERR_INV_ARG; - - r = outbuf; - a = c->lastiv; /* We use c->LASTIV as buffer for A. */ - b = c->ctr; /* B is also used to concatenate stuff. */ - - /* Copy the inbuf to the outbuf and save A. */ - memcpy (a, inbuf, 8); - memmove (r, inbuf+8, inbuflen-8); - n--; /* Reduce to actual number of data blocks. */ - - /* t := 6 * n */ - i = n * 6; /* The range is valid because: n = inbuflen / 8 - 1. */ - for (x=0; x < 8 && x < sizeof (i); x++) - t[7-x] = i >> (8*x); - for (; x < 8; x++) - t[7-x] = 0; - - for (j = 5; j >= 0; j--) - { - for (i = n; i >= 1; i--) - { - /* B := AES_k^1( (A ^ t)| R[i] ) */ - for (x = 0; x < 8; x++) - b[x] = a[x] ^ t[x]; - memcpy (b+8, r+(i-1)*8, 8); - c->cipher->decrypt (&c->context.c, b, b); - /* t := t - 1 */ - for (x = 7; x >= 0; x--) - { - t[x]--; - if (t[x] != 0xff) - break; - } - /* A := MSB_64(B) */ - memcpy (a, b, 8); - /* R[i] := LSB_64(B) */ - memcpy (r+(i-1)*8, b+8, 8); - } - } - - /* If an IV has been set we compare against this Alternative Initial - Value; if it has not been set we compare against the standard IV. */ - if (c->marks.iv) - j = memcmp (a, c->u_iv.iv, 8); - else - { - for (j=0, x=0; x < 8; x++) - if (a[x] != 0xa6) - { - j=1; - break; - } - } - return j? GPG_ERR_CHECKSUM : 0; -} - - -/**************** - * Encrypt INBUF to OUTBUF with the mode selected at open. - * inbuf and outbuf may overlap or be the same. - * Depending on the mode some contraints apply to NBYTES. - */ -static gcry_err_code_t -cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, - const byte *inbuf, unsigned int nbytes) -{ - gcry_err_code_t rc = GPG_ERR_NO_ERROR; - - switch( c->mode ) { - case GCRY_CIPHER_MODE_ECB: - if (!(nbytes%c->cipher->blocksize)) - do_ecb_encrypt(c, outbuf, inbuf, nbytes/c->cipher->blocksize ); - else - rc = GPG_ERR_INV_ARG; - break; - case GCRY_CIPHER_MODE_CBC: - if (!(nbytes%c->cipher->blocksize) - || (nbytes > c->cipher->blocksize - && (c->flags & GCRY_CIPHER_CBC_CTS))) - do_cbc_encrypt(c, outbuf, inbuf, nbytes ); - else - rc = GPG_ERR_INV_ARG; - break; - case GCRY_CIPHER_MODE_CFB: - do_cfb_encrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_OFB: - do_ofb_encrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_CTR: - do_ctr_encrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_STREAM: - c->cipher->stencrypt ( &c->context.c, - outbuf, (byte*)/*arggg*/inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_NONE: - if (fips_mode () || !_gcry_get_debug_flag (0)) - { - fips_signal_error ("cipher mode NONE used"); - rc = GPG_ERR_INV_CIPHER_MODE; - } - else - { - if ( inbuf != outbuf ) - memmove (outbuf, inbuf, nbytes); - } - break; - default: - log_fatal("cipher_encrypt: invalid mode %d\n", c->mode ); - rc = GPG_ERR_INV_CIPHER_MODE; - break; - } - return rc; -} - - -/**************** - * Encrypt IN and write it to OUT. If IN is NULL, in-place encryption has - * been requested. - */ -gcry_error_t -gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize, - const void *in, size_t inlen) -{ - gcry_err_code_t err; - - if (h->mode == GCRY_CIPHER_MODE_AESWRAP) - { - /* Hack to implement AESWRAP without touching the other modes. - The actual function has been taken from the current - development version which does all error checking in each - mode function. */ - if (!in) - err = do_aeswrap_encrypt (h, out, outsize, out, outsize); - else - err = do_aeswrap_encrypt (h, out, outsize, in, inlen); - } - else if (!in) - { - /* Caller requested in-place encryption. */ - /* Actually cipher_encrypt() does not need to know about it, but - * we may change it in the future to get better performance. */ - err = cipher_encrypt (h, out, out, outsize); - } - else if (outsize < ((h->flags & GCRY_CIPHER_CBC_MAC) ? - h->cipher->blocksize : inlen)) - err = GPG_ERR_TOO_SHORT; - else if ((h->mode == GCRY_CIPHER_MODE_ECB - || (h->mode == GCRY_CIPHER_MODE_CBC - && (! ((h->flags & GCRY_CIPHER_CBC_CTS) - && (inlen > h->cipher->blocksize))))) - && (inlen % h->cipher->blocksize)) - err = GPG_ERR_INV_ARG; - else - err = cipher_encrypt (h, out, in, inlen); - - if (err && out) - memset (out, 0x42, outsize); /* Failsafe: Make sure that the - plaintext will never make it into - OUT. */ - - return gcry_error (err); -} - - - -/**************** - * Decrypt INBUF to OUTBUF with the mode selected at open. - * inbuf and outbuf may overlap or be the same. - * Depending on the mode some some contraints apply to NBYTES. - */ -static gcry_err_code_t -cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, - unsigned int nbytes) -{ - gcry_err_code_t rc = GPG_ERR_NO_ERROR; - - switch( c->mode ) { - case GCRY_CIPHER_MODE_ECB: - if (!(nbytes%c->cipher->blocksize)) - do_ecb_decrypt(c, outbuf, inbuf, nbytes/c->cipher->blocksize ); - else - rc = GPG_ERR_INV_ARG; - break; - case GCRY_CIPHER_MODE_CBC: - if (!(nbytes%c->cipher->blocksize) - || (nbytes > c->cipher->blocksize - && (c->flags & GCRY_CIPHER_CBC_CTS))) - do_cbc_decrypt(c, outbuf, inbuf, nbytes ); - else - rc = GPG_ERR_INV_ARG; - break; - case GCRY_CIPHER_MODE_CFB: - do_cfb_decrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_OFB: - do_ofb_decrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_CTR: - do_ctr_decrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_STREAM: - c->cipher->stdecrypt ( &c->context.c, - outbuf, (byte*)/*arggg*/inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_NONE: - if (fips_mode () || !_gcry_get_debug_flag (0)) - { - fips_signal_error ("cipher mode NONE used"); - rc = GPG_ERR_INV_CIPHER_MODE; - } - else - { - if (inbuf != outbuf) - memmove (outbuf, inbuf, nbytes); - } - break; - default: - log_fatal ("cipher_decrypt: invalid mode %d\n", c->mode ); - rc = GPG_ERR_INV_CIPHER_MODE; - break; - } - return rc; -} - - -gcry_error_t -gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize, - const void *in, size_t inlen) -{ - gcry_err_code_t err = 0; - - if (h->mode == GCRY_CIPHER_MODE_AESWRAP) - { - /* Hack to implement AESWRAP without touching the other modes. - The actual function has been taken from the current - development version which does all error checking in each - mode function. */ - if (!in) - err = do_aeswrap_decrypt (h, out, outsize, out, outsize); - else - err = do_aeswrap_decrypt (h, out, outsize, in, inlen); - } - else if (!in) - { - /* Caller requested in-place encryption. */ - /* Actually cipher_encrypt() does not need to know about it, but - * we may change it in the future to get better performance. */ - err = cipher_decrypt (h, out, out, outsize); - } - else if (outsize < inlen) - err = GPG_ERR_TOO_SHORT; - else if (((h->mode == GCRY_CIPHER_MODE_ECB) - || ((h->mode == GCRY_CIPHER_MODE_CBC) - && (! ((h->flags & GCRY_CIPHER_CBC_CTS) - && (inlen > h->cipher->blocksize))))) - && (inlen % h->cipher->blocksize) != 0) - err = GPG_ERR_INV_ARG; - else - err = cipher_decrypt (h, out, in, inlen); - - return gcry_error (err); -} - - - -/**************** - * Used for PGP's somewhat strange CFB mode. Only works if - * the corresponding flag is set. - */ -static void -cipher_sync (gcry_cipher_hd_t c) -{ - if ((c->flags & GCRY_CIPHER_ENABLE_SYNC) && c->unused) - { - memmove (c->u_iv.iv + c->unused, - c->u_iv.iv, c->cipher->blocksize - c->unused); - memcpy (c->u_iv.iv, - c->lastiv + c->cipher->blocksize - c->unused, c->unused); - c->unused = 0; - } -} - - -gcry_error_t -_gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen) -{ - return cipher_setkey (hd, (void*)key, keylen); -} - - -gcry_error_t -_gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) -{ - cipher_setiv (hd, iv, ivlen); - return 0; -} - -/* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of - block size length, or (NULL,0) to set the CTR to the all-zero - block. */ -gpg_error_t -_gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) -{ - if (ctr && ctrlen == hd->cipher->blocksize) - memcpy (hd->ctr, ctr, hd->cipher->blocksize); - else if (!ctr || !ctrlen) - memset (hd->ctr, 0, hd->cipher->blocksize); - else - return gpg_error (GPG_ERR_INV_ARG); - return 0; -} - - -gcry_error_t -gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) -{ - gcry_err_code_t rc = GPG_ERR_NO_ERROR; - - switch (cmd) - { - case GCRYCTL_SET_KEY: /* Deprecated; use gcry_cipher_setkey. */ - rc = cipher_setkey( h, buffer, buflen ); - break; - - case GCRYCTL_SET_IV: /* Deprecated; use gcry_cipher_setiv. */ - cipher_setiv( h, buffer, buflen ); - break; - - case GCRYCTL_RESET: - cipher_reset (h); - break; - - case GCRYCTL_CFB_SYNC: - cipher_sync( h ); - break; - - case GCRYCTL_SET_CBC_CTS: - if (buflen) - if (h->flags & GCRY_CIPHER_CBC_MAC) - rc = GPG_ERR_INV_FLAG; - else - h->flags |= GCRY_CIPHER_CBC_CTS; - else - h->flags &= ~GCRY_CIPHER_CBC_CTS; - break; - - case GCRYCTL_SET_CBC_MAC: - if (buflen) - if (h->flags & GCRY_CIPHER_CBC_CTS) - rc = GPG_ERR_INV_FLAG; - else - h->flags |= GCRY_CIPHER_CBC_MAC; - else - h->flags &= ~GCRY_CIPHER_CBC_MAC; - break; - - case GCRYCTL_DISABLE_ALGO: - /* This command expects NULL for H and BUFFER to point to an - integer with the algo number. */ - if( h || !buffer || buflen != sizeof(int) ) - return gcry_error (GPG_ERR_CIPHER_ALGO); - disable_cipher_algo( *(int*)buffer ); - break; - - case GCRYCTL_SET_CTR: /* Deprecated; use gcry_cipher_setctr. */ - if (buffer && buflen == h->cipher->blocksize) - memcpy (h->ctr, buffer, h->cipher->blocksize); - else if (buffer == NULL || buflen == 0) - memset (h->ctr, 0, h->cipher->blocksize); - else - rc = GPG_ERR_INV_ARG; - break; - - case 61: /* Disable weak key detection (private). */ - if (h->extraspec->set_extra_info) - rc = h->extraspec->set_extra_info - (&h->context.c, CIPHER_INFO_NO_WEAK_KEY, NULL, 0); - else - rc = GPG_ERR_NOT_SUPPORTED; - break; - - case 62: /* Return current input vector (private). */ - /* This is the input block as used in CFB and OFB mode which has - initially been set as IV. The returned format is: - 1 byte Actual length of the block in bytes. - n byte The block. - If the provided buffer is too short, an error is returned. */ - if (buflen < (1 + h->cipher->blocksize)) - rc = GPG_ERR_TOO_SHORT; - else - { - unsigned char *ivp; - unsigned char *dst = buffer; - int n = h->unused; - - if (!n) - n = h->cipher->blocksize; - gcry_assert (n <= h->cipher->blocksize); - *dst++ = n; - ivp = h->u_iv.iv + h->cipher->blocksize - n; - while (n--) - *dst++ = *ivp++; - } - break; - - default: - rc = GPG_ERR_INV_OP; - } - - return gcry_error (rc); -} - - -/* Return information about the cipher handle H. CMD is the kind of - information requested. BUFFER and NBYTES are reserved for now. - - There are no values for CMD yet defined. - - The fucntion always returns GPG_ERR_INV_OP. - - */ -gcry_error_t -gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - (void)h; - (void)buffer; - (void)nbytes; - - switch (cmd) - { - default: - err = GPG_ERR_INV_OP; - } - - return gcry_error (err); -} - -/* Return information about the given cipher algorithm ALGO. - - WHAT select the kind of information returned: - - GCRYCTL_GET_KEYLEN: - Return the length of the key. If the algorithm ALGO - supports multiple key lengths, the maximum supported key length - is returned. The key length is returned as number of octets. - BUFFER and NBYTES must be zero. - - GCRYCTL_GET_BLKLEN: - Return the blocklength of the algorithm ALGO counted in octets. - BUFFER and NBYTES must be zero. - - GCRYCTL_TEST_ALGO: - Returns 0 if the specified algorithm ALGO is available for use. - BUFFER and NBYTES must be zero. - - Note: Because this function is in most cases used to return an - integer value, we can make it easier for the caller to just look at - the return value. The caller will in all cases consult the value - and thereby detecting whether a error occured or not (i.e. while - checking the block size) - */ -gcry_error_t -gcry_cipher_algo_info (int algo, int what, void *buffer, size_t *nbytes) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - unsigned int ui; - - switch (what) - { - case GCRYCTL_GET_KEYLEN: - if (buffer || (! nbytes)) - err = GPG_ERR_CIPHER_ALGO; - else - { - ui = cipher_get_keylen (algo); - if ((ui > 0) && (ui <= 512)) - *nbytes = (size_t) ui / 8; - else - /* The only reason is an invalid algo or a strange - blocksize. */ - err = GPG_ERR_CIPHER_ALGO; - } - break; - - case GCRYCTL_GET_BLKLEN: - if (buffer || (! nbytes)) - err = GPG_ERR_CIPHER_ALGO; - else - { - ui = cipher_get_blocksize (algo); - if ((ui > 0) && (ui < 10000)) - *nbytes = ui; - else - /* The only reason is an invalid algo or a strange - blocksize. */ - err = GPG_ERR_CIPHER_ALGO; - } - break; - - case GCRYCTL_TEST_ALGO: - if (buffer || nbytes) - err = GPG_ERR_INV_ARG; - else - err = check_cipher_algo (algo); - break; - - default: - err = GPG_ERR_INV_OP; - } - - return gcry_error (err); -} - - -/* This function returns length of the key for algorithm ALGO. If the - algorithm supports multiple key lengths, the maximum supported key - length is returned. On error 0 is returned. The key length is - returned as number of octets. - - This is a convenience functions which should be preferred over - gcry_cipher_algo_info because it allows for proper type - checking. */ -size_t -gcry_cipher_get_algo_keylen (int algo) -{ - size_t n; - - if (gcry_cipher_algo_info (algo, GCRYCTL_GET_KEYLEN, NULL, &n)) - n = 0; - return n; -} - -/* This functions returns the blocklength of the algorithm ALGO - counted in octets. On error 0 is returned. - - This is a convenience functions which should be preferred over - gcry_cipher_algo_info because it allows for proper type - checking. */ -size_t -gcry_cipher_get_algo_blklen (int algo) -{ - size_t n; - - if (gcry_cipher_algo_info( algo, GCRYCTL_GET_BLKLEN, NULL, &n)) - n = 0; - return n; -} - -/* Explicitly initialize this module. */ -gcry_err_code_t -_gcry_cipher_init (void) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - REGISTER_DEFAULT_CIPHERS; - - return err; -} - -/* Get a list consisting of the IDs of the loaded cipher modules. If - LIST is zero, write the number of loaded cipher modules to - LIST_LENGTH and return. If LIST is non-zero, the first - *LIST_LENGTH algorithm IDs are stored in LIST, which must be of - according size. In case there are less cipher modules than - *LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */ -gcry_error_t -gcry_cipher_list (int *list, int *list_length) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - ath_mutex_lock (&ciphers_registered_lock); - err = _gcry_module_list (ciphers_registered, list, list_length); - ath_mutex_unlock (&ciphers_registered_lock); - - return err; -} - - -/* Run the selftests for cipher algorithm ALGO with optional reporting - function REPORT. */ -gpg_error_t -_gcry_cipher_selftest (int algo, int extended, selftest_report_func_t report) -{ - gcry_module_t module = NULL; - cipher_extra_spec_t *extraspec = NULL; - gcry_err_code_t ec = 0; - - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - module = _gcry_module_lookup_id (ciphers_registered, algo); - if (module && !(module->flags & FLAG_MODULE_DISABLED)) - extraspec = module->extraspec; - ath_mutex_unlock (&ciphers_registered_lock); - if (extraspec && extraspec->selftest) - ec = extraspec->selftest (algo, extended, report); - else - { - ec = GPG_ERR_CIPHER_ALGO; - if (report) - report ("cipher", algo, "module", - module && !(module->flags & FLAG_MODULE_DISABLED)? - "no selftest available" : - module? "algorithm disabled" : "algorithm not found"); - } - - if (module) - { - ath_mutex_lock (&ciphers_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&ciphers_registered_lock); - } - return gpg_error (ec); -} +/* cipher.c - cipher dispatcher + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 + * 2005, 2007, 2008, 2009 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" + +#define MAX_BLOCKSIZE 16 +#define TABLE_SIZE 14 +#define CTX_MAGIC_NORMAL 0x24091964 +#define CTX_MAGIC_SECURE 0x46919042 + +#undef NEED_16BYTE_ALIGNED_CONTEXT +#if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__) +#define NEED_16BYTE_ALIGNED_CONTEXT 1 +#endif + +/* A dummy extraspec so that we do not need to tests the extraspec + field from the module specification against NULL and instead + directly test the respective fields of extraspecs. */ +static cipher_extra_spec_t dummy_extra_spec; + +/* This is the list of the default ciphers, which are included in + libgcrypt. */ +static struct cipher_table_entry +{ + gcry_cipher_spec_t *cipher; + cipher_extra_spec_t *extraspec; + unsigned int algorithm; + int fips_allowed; +} cipher_table[] = + { +#if USE_BLOWFISH + { &_gcry_cipher_spec_blowfish, + &dummy_extra_spec, GCRY_CIPHER_BLOWFISH }, +#endif +#if USE_DES + { &_gcry_cipher_spec_des, + &dummy_extra_spec, GCRY_CIPHER_DES }, + { &_gcry_cipher_spec_tripledes, + &_gcry_cipher_extraspec_tripledes, GCRY_CIPHER_3DES, 1 }, +#endif +#if USE_ARCFOUR + { &_gcry_cipher_spec_arcfour, + &dummy_extra_spec, GCRY_CIPHER_ARCFOUR }, +#endif +#if USE_CAST5 + { &_gcry_cipher_spec_cast5, + &dummy_extra_spec, GCRY_CIPHER_CAST5 }, +#endif +#if USE_AES + { &_gcry_cipher_spec_aes, + &_gcry_cipher_extraspec_aes, GCRY_CIPHER_AES, 1 }, + { &_gcry_cipher_spec_aes192, + &_gcry_cipher_extraspec_aes192, GCRY_CIPHER_AES192, 1 }, + { &_gcry_cipher_spec_aes256, + &_gcry_cipher_extraspec_aes256, GCRY_CIPHER_AES256, 1 }, +#endif +#if USE_TWOFISH + { &_gcry_cipher_spec_twofish, + &dummy_extra_spec, GCRY_CIPHER_TWOFISH }, + { &_gcry_cipher_spec_twofish128, + &dummy_extra_spec, GCRY_CIPHER_TWOFISH128 }, +#endif +#if USE_SERPENT + { &_gcry_cipher_spec_serpent128, + &dummy_extra_spec, GCRY_CIPHER_SERPENT128 }, + { &_gcry_cipher_spec_serpent192, + &dummy_extra_spec, GCRY_CIPHER_SERPENT192 }, + { &_gcry_cipher_spec_serpent256, + &dummy_extra_spec, GCRY_CIPHER_SERPENT256 }, +#endif +#if USE_RFC2268 + { &_gcry_cipher_spec_rfc2268_40, + &dummy_extra_spec, GCRY_CIPHER_RFC2268_40 }, +#endif +#if USE_SEED + { &_gcry_cipher_spec_seed, + &dummy_extra_spec, GCRY_CIPHER_SEED }, +#endif +#if USE_CAMELLIA + { &_gcry_cipher_spec_camellia128, + &dummy_extra_spec, GCRY_CIPHER_CAMELLIA128 }, + { &_gcry_cipher_spec_camellia192, + &dummy_extra_spec, GCRY_CIPHER_CAMELLIA192 }, + { &_gcry_cipher_spec_camellia256, + &dummy_extra_spec, GCRY_CIPHER_CAMELLIA256 }, +#endif + { NULL } + }; + +/* List of registered ciphers. */ +static gcry_module_t ciphers_registered; + +/* This is the lock protecting CIPHERS_REGISTERED. */ +static ath_mutex_t ciphers_registered_lock = ATH_MUTEX_INITIALIZER; + +/* Flag to check whether the default ciphers have already been + registered. */ +static int default_ciphers_registered; + +/* Convenient macro for registering the default ciphers. */ +#define REGISTER_DEFAULT_CIPHERS \ + do \ + { \ + ath_mutex_lock (&ciphers_registered_lock); \ + if (! default_ciphers_registered) \ + { \ + cipher_register_default (); \ + default_ciphers_registered = 1; \ + } \ + ath_mutex_unlock (&ciphers_registered_lock); \ + } \ + while (0) + + +/* A VIA processor with the Padlock engine requires an alignment of + most data on a 16 byte boundary. Because we trick out the compiler + while allocating the context, the align attribute as used in + rijndael.c does not work on its own. Thus we need to make sure + that the entire context structure is a aligned on that boundary. + We achieve this by defining a new type and use that instead of our + usual alignment type. */ +typedef union +{ + PROPERLY_ALIGNED_TYPE foo; +#ifdef NEED_16BYTE_ALIGNED_CONTEXT + char bar[16] __attribute__ ((aligned (16))); +#endif + char c[1]; +} cipher_context_alignment_t; + + +/* The handle structure. */ +struct gcry_cipher_handle +{ + int magic; + size_t actual_handle_size; /* Allocated size of this handle. */ + size_t handle_offset; /* Offset to the malloced block. */ + gcry_cipher_spec_t *cipher; + cipher_extra_spec_t *extraspec; + gcry_module_t module; + + /* The algorithm id. This is a hack required because the module + interface does not easily allow to retrieve this value. */ + int algo; + + /* A structure with function pointers for bulk operations. Due to + limitations of the module system (we don't want to change the + API) we need to keep these function pointers here. The cipher + open function intializes them and the actual encryption routines + use them if they are not NULL. */ + struct { + void (*cfb_enc)(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + unsigned int nblocks); + void (*cfb_dec)(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + unsigned int nblocks); + void (*cbc_enc)(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + unsigned int nblocks, int cbc_mac); + void (*cbc_dec)(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + unsigned int nblocks); + } bulk; + + + int mode; + unsigned int flags; + + struct { + unsigned int key:1; /* Set to 1 if a key has been set. */ + unsigned int iv:1; /* Set to 1 if a IV has been set. */ + } marks; + + /* The initialization vector. To help code optimization we make + sure that it is aligned on an unsigned long and u32 boundary. */ + union { + unsigned long dummy_iv; + u32 dummy_u32_iv; + unsigned char iv[MAX_BLOCKSIZE]; + } u_iv; + + unsigned char lastiv[MAX_BLOCKSIZE]; + int unused; /* Number of unused bytes in the IV. */ + + unsigned char ctr[MAX_BLOCKSIZE]; /* For Counter (CTR) mode. */ + + + /* What follows are two contexts of the cipher in use. The first + one needs to be aligned well enough for the cipher operation + whereas the second one is a copy created by cipher_setkey and + used by cipher_reset. That second copy has no need for proper + aligment because it is only accessed by memcpy. */ + cipher_context_alignment_t context; +}; + + + +/* These dummy functions are used in case a cipher implementation + refuses to provide it's own functions. */ + +static gcry_err_code_t +dummy_setkey (void *c, const unsigned char *key, unsigned int keylen) +{ + (void)c; + (void)key; + (void)keylen; + return GPG_ERR_NO_ERROR; +} + +static void +dummy_encrypt_block (void *c, + unsigned char *outbuf, const unsigned char *inbuf) +{ + (void)c; + (void)outbuf; + (void)inbuf; + BUG(); +} + +static void +dummy_decrypt_block (void *c, + unsigned char *outbuf, const unsigned char *inbuf) +{ + (void)c; + (void)outbuf; + (void)inbuf; + BUG(); +} + +static void +dummy_encrypt_stream (void *c, + unsigned char *outbuf, const unsigned char *inbuf, + unsigned int n) +{ + (void)c; + (void)outbuf; + (void)inbuf; + (void)n; + BUG(); +} + +static void +dummy_decrypt_stream (void *c, + unsigned char *outbuf, const unsigned char *inbuf, + unsigned int n) +{ + (void)c; + (void)outbuf; + (void)inbuf; + (void)n; + BUG(); +} + + +/* Internal function. Register all the ciphers included in + CIPHER_TABLE. Note, that this function gets only used by the macro + REGISTER_DEFAULT_CIPHERS which protects it using a mutex. */ +static void +cipher_register_default (void) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + int i; + + for (i = 0; !err && cipher_table[i].cipher; i++) + { + if (! cipher_table[i].cipher->setkey) + cipher_table[i].cipher->setkey = dummy_setkey; + if (! cipher_table[i].cipher->encrypt) + cipher_table[i].cipher->encrypt = dummy_encrypt_block; + if (! cipher_table[i].cipher->decrypt) + cipher_table[i].cipher->decrypt = dummy_decrypt_block; + if (! cipher_table[i].cipher->stencrypt) + cipher_table[i].cipher->stencrypt = dummy_encrypt_stream; + if (! cipher_table[i].cipher->stdecrypt) + cipher_table[i].cipher->stdecrypt = dummy_decrypt_stream; + + if ( fips_mode () && !cipher_table[i].fips_allowed ) + continue; + + err = _gcry_module_add (&ciphers_registered, + cipher_table[i].algorithm, + (void *) cipher_table[i].cipher, + (void *) cipher_table[i].extraspec, + NULL); + } + + if (err) + BUG (); +} + +/* Internal callback function. Used via _gcry_module_lookup. */ +static int +gcry_cipher_lookup_func_name (void *spec, void *data) +{ + gcry_cipher_spec_t *cipher = (gcry_cipher_spec_t *) spec; + char *name = (char *) data; + const char **aliases = cipher->aliases; + int i, ret = ! stricmp (name, cipher->name); + + if (aliases) + for (i = 0; aliases[i] && (! ret); i++) + ret = ! stricmp (name, aliases[i]); + + return ret; +} + +/* Internal callback function. Used via _gcry_module_lookup. */ +static int +gcry_cipher_lookup_func_oid (void *spec, void *data) +{ + gcry_cipher_spec_t *cipher = (gcry_cipher_spec_t *) spec; + char *oid = (char *) data; + gcry_cipher_oid_spec_t *oid_specs = cipher->oids; + int ret = 0, i; + + if (oid_specs) + for (i = 0; oid_specs[i].oid && (! ret); i++) + if (! stricmp (oid, oid_specs[i].oid)) + ret = 1; + + return ret; +} + +/* Internal function. Lookup a cipher entry by it's name. */ +static gcry_module_t +gcry_cipher_lookup_name (const char *name) +{ + gcry_module_t cipher; + + cipher = _gcry_module_lookup (ciphers_registered, (void *) name, + gcry_cipher_lookup_func_name); + + return cipher; +} + +/* Internal function. Lookup a cipher entry by it's oid. */ +static gcry_module_t +gcry_cipher_lookup_oid (const char *oid) +{ + gcry_module_t cipher; + + cipher = _gcry_module_lookup (ciphers_registered, (void *) oid, + gcry_cipher_lookup_func_oid); + + return cipher; +} + +/* Register a new cipher module whose specification can be found in + CIPHER. On success, a new algorithm ID is stored in ALGORITHM_ID + and a pointer representhing this module is stored in MODULE. */ +gcry_error_t +_gcry_cipher_register (gcry_cipher_spec_t *cipher, + cipher_extra_spec_t *extraspec, + int *algorithm_id, + gcry_module_t *module) +{ + gcry_err_code_t err = 0; + gcry_module_t mod; + + /* We do not support module loading in fips mode. */ + if (fips_mode ()) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + + ath_mutex_lock (&ciphers_registered_lock); + err = _gcry_module_add (&ciphers_registered, 0, + (void *)cipher, + (void *)(extraspec? extraspec : &dummy_extra_spec), + &mod); + ath_mutex_unlock (&ciphers_registered_lock); + + if (! err) + { + *module = mod; + *algorithm_id = mod->mod_id; + } + + return gcry_error (err); +} + +/* Unregister the cipher identified by MODULE, which must have been + registered with gcry_cipher_register. */ +void +gcry_cipher_unregister (gcry_module_t module) +{ + ath_mutex_lock (&ciphers_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&ciphers_registered_lock); +} + +/* Locate the OID in the oid table and return the index or -1 when not + found. An opitonal "oid." or "OID." prefix in OID is ignored, the + OID is expected to be in standard IETF dotted notation. The + internal algorithm number is returned in ALGORITHM unless it + ispassed as NULL. A pointer to the specification of the module + implementing this algorithm is return in OID_SPEC unless passed as + NULL.*/ +static int +search_oid (const char *oid, int *algorithm, gcry_cipher_oid_spec_t *oid_spec) +{ + gcry_module_t module; + int ret = 0; + + if (oid && ((! strncmp (oid, "oid.", 4)) + || (! strncmp (oid, "OID.", 4)))) + oid += 4; + + module = gcry_cipher_lookup_oid (oid); + if (module) + { + gcry_cipher_spec_t *cipher = module->spec; + int i; + + for (i = 0; cipher->oids[i].oid && !ret; i++) + if (! stricmp (oid, cipher->oids[i].oid)) + { + if (algorithm) + *algorithm = module->mod_id; + if (oid_spec) + *oid_spec = cipher->oids[i]; + ret = 1; + } + _gcry_module_release (module); + } + + return ret; +} + +/* Map STRING to the cipher algorithm identifier. Returns the + algorithm ID of the cipher for the given name or 0 if the name is + not known. It is valid to pass NULL for STRING which results in a + return value of 0. */ +int +gcry_cipher_map_name (const char *string) +{ + gcry_module_t cipher; + int ret, algorithm = 0; + + if (! string) + return 0; + + REGISTER_DEFAULT_CIPHERS; + + /* If the string starts with a digit (optionally prefixed with + either "OID." or "oid."), we first look into our table of ASN.1 + object identifiers to figure out the algorithm */ + + ath_mutex_lock (&ciphers_registered_lock); + + ret = search_oid (string, &algorithm, NULL); + if (! ret) + { + cipher = gcry_cipher_lookup_name (string); + if (cipher) + { + algorithm = cipher->mod_id; + _gcry_module_release (cipher); + } + } + + ath_mutex_unlock (&ciphers_registered_lock); + + return algorithm; +} + + +/* Given a STRING with an OID in dotted decimal notation, this + function returns the cipher mode (GCRY_CIPHER_MODE_*) associated + with that OID or 0 if no mode is known. Passing NULL for string + yields a return value of 0. */ +int +gcry_cipher_mode_from_oid (const char *string) +{ + gcry_cipher_oid_spec_t oid_spec; + int ret = 0, mode = 0; + + if (!string) + return 0; + + ath_mutex_lock (&ciphers_registered_lock); + ret = search_oid (string, NULL, &oid_spec); + if (ret) + mode = oid_spec.mode; + ath_mutex_unlock (&ciphers_registered_lock); + + return mode; +} + + +/* Map the cipher algorithm whose ID is contained in ALGORITHM to a + string representation of the algorithm name. For unknown algorithm + IDs this function returns "?". */ +static const char * +cipher_algo_to_string (int algorithm) +{ + gcry_module_t cipher; + const char *name; + + REGISTER_DEFAULT_CIPHERS; + + ath_mutex_lock (&ciphers_registered_lock); + cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); + if (cipher) + { + name = ((gcry_cipher_spec_t *) cipher->spec)->name; + _gcry_module_release (cipher); + } + else + name = "?"; + ath_mutex_unlock (&ciphers_registered_lock); + + return name; +} + +/* Map the cipher algorithm identifier ALGORITHM to a string + representing this algorithm. This string is the default name as + used by Libgcrypt. An pointer to an empty string is returned for + an unknown algorithm. NULL is never returned. */ +const char * +gcry_cipher_algo_name (int algorithm) +{ + return cipher_algo_to_string (algorithm); +} + + +/* Flag the cipher algorithm with the identifier ALGORITHM as + disabled. There is no error return, the function does nothing for + unknown algorithms. Disabled algorithms are vitually not available + in Libgcrypt. */ +static void +disable_cipher_algo (int algorithm) +{ + gcry_module_t cipher; + + REGISTER_DEFAULT_CIPHERS; + + ath_mutex_lock (&ciphers_registered_lock); + cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); + if (cipher) + { + if (! (cipher->flags & FLAG_MODULE_DISABLED)) + cipher->flags |= FLAG_MODULE_DISABLED; + _gcry_module_release (cipher); + } + ath_mutex_unlock (&ciphers_registered_lock); +} + + +/* Return 0 if the cipher algorithm with identifier ALGORITHM is + available. Returns a basic error code value if it is not + available. */ +static gcry_err_code_t +check_cipher_algo (int algorithm) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_module_t cipher; + + REGISTER_DEFAULT_CIPHERS; + + ath_mutex_lock (&ciphers_registered_lock); + cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); + if (cipher) + { + if (cipher->flags & FLAG_MODULE_DISABLED) + err = GPG_ERR_CIPHER_ALGO; + _gcry_module_release (cipher); + } + else + err = GPG_ERR_CIPHER_ALGO; + ath_mutex_unlock (&ciphers_registered_lock); + + return err; +} + + +/* Return the standard length of the key for the cipher algorithm with + the identifier ALGORITHM. This function expects a valid algorithm + and will abort if the algorithm is not available or the length of + the key is not known. */ +static unsigned int +cipher_get_keylen (int algorithm) +{ + gcry_module_t cipher; + unsigned len = 0; + + REGISTER_DEFAULT_CIPHERS; + + ath_mutex_lock (&ciphers_registered_lock); + cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); + if (cipher) + { + len = ((gcry_cipher_spec_t *) cipher->spec)->keylen; + if (!len) + log_bug ("cipher %d w/o key length\n", algorithm); + _gcry_module_release (cipher); + } + else + log_bug ("cipher %d not found\n", algorithm); + ath_mutex_unlock (&ciphers_registered_lock); + + return len; +} + +/* Return the block length of the cipher algorithm with the identifier + ALGORITHM. This function expects a valid algorithm and will abort + if the algorithm is not available or the length of the key is not + known. */ +static unsigned int +cipher_get_blocksize (int algorithm) +{ + gcry_module_t cipher; + unsigned len = 0; + + REGISTER_DEFAULT_CIPHERS; + + ath_mutex_lock (&ciphers_registered_lock); + cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); + if (cipher) + { + len = ((gcry_cipher_spec_t *) cipher->spec)->blocksize; + if (! len) + log_bug ("cipher %d w/o blocksize\n", algorithm); + _gcry_module_release (cipher); + } + else + log_bug ("cipher %d not found\n", algorithm); + ath_mutex_unlock (&ciphers_registered_lock); + + return len; +} + + +/* + Open a cipher handle for use with cipher algorithm ALGORITHM, using + the cipher mode MODE (one of the GCRY_CIPHER_MODE_*) and return a + handle in HANDLE. Put NULL into HANDLE and return an error code if + something goes wrong. FLAGS may be used to modify the + operation. The defined flags are: + + GCRY_CIPHER_SECURE: allocate all internal buffers in secure memory. + GCRY_CIPHER_ENABLE_SYNC: Enable the sync operation as used in OpenPGP. + GCRY_CIPHER_CBC_CTS: Enable CTS mode. + GCRY_CIPHER_CBC_MAC: Enable MAC mode. + + Values for these flags may be combined using OR. + */ +gcry_error_t +gcry_cipher_open (gcry_cipher_hd_t *handle, + int algo, int mode, unsigned int flags) +{ + int secure = (flags & GCRY_CIPHER_SECURE); + gcry_cipher_spec_t *cipher = NULL; + cipher_extra_spec_t *extraspec = NULL; + gcry_module_t module = NULL; + gcry_cipher_hd_t h = NULL; + gcry_err_code_t err = 0; + + /* If the application missed to call the random poll function, we do + it here to ensure that it is used once in a while. */ + _gcry_fast_random_poll (); + + REGISTER_DEFAULT_CIPHERS; + + /* Fetch the according module and check whether the cipher is marked + available for use. */ + ath_mutex_lock (&ciphers_registered_lock); + module = _gcry_module_lookup_id (ciphers_registered, algo); + if (module) + { + /* Found module. */ + + if (module->flags & FLAG_MODULE_DISABLED) + { + /* Not available for use. */ + err = GPG_ERR_CIPHER_ALGO; + } + else + { + cipher = (gcry_cipher_spec_t *) module->spec; + extraspec = module->extraspec; + } + } + else + err = GPG_ERR_CIPHER_ALGO; + ath_mutex_unlock (&ciphers_registered_lock); + + /* check flags */ + if ((! err) + && ((flags & ~(0 + | GCRY_CIPHER_SECURE + | GCRY_CIPHER_ENABLE_SYNC + | GCRY_CIPHER_CBC_CTS + | GCRY_CIPHER_CBC_MAC)) + || (flags & GCRY_CIPHER_CBC_CTS & GCRY_CIPHER_CBC_MAC))) + err = GPG_ERR_CIPHER_ALGO; + + /* check that a valid mode has been requested */ + if (! err) + switch (mode) + { + case GCRY_CIPHER_MODE_ECB: + case GCRY_CIPHER_MODE_CBC: + case GCRY_CIPHER_MODE_CFB: + case GCRY_CIPHER_MODE_OFB: + case GCRY_CIPHER_MODE_CTR: + case GCRY_CIPHER_MODE_AESWRAP: + if ((cipher->encrypt == dummy_encrypt_block) + || (cipher->decrypt == dummy_decrypt_block)) + err = GPG_ERR_INV_CIPHER_MODE; + break; + + case GCRY_CIPHER_MODE_STREAM: + if ((cipher->stencrypt == dummy_encrypt_stream) + || (cipher->stdecrypt == dummy_decrypt_stream)) + err = GPG_ERR_INV_CIPHER_MODE; + break; + + case GCRY_CIPHER_MODE_NONE: + /* This mode may be used for debugging. It copies the main + text verbatim to the ciphertext. We do not allow this in + fips mode or if no debug flag has been set. */ + if (fips_mode () || !_gcry_get_debug_flag (0)) + err = GPG_ERR_INV_CIPHER_MODE; + break; + + default: + err = GPG_ERR_INV_CIPHER_MODE; + } + + /* Perform selftest here and mark this with a flag in cipher_table? + No, we should not do this as it takes too long. Further it does + not make sense to exclude algorithms with failing selftests at + runtime: If a selftest fails there is something seriously wrong + with the system and thus we better die immediately. */ + + if (! err) + { + size_t size = (sizeof (*h) + + 2 * cipher->contextsize + - sizeof (cipher_context_alignment_t) +#ifdef NEED_16BYTE_ALIGNED_CONTEXT + + 15 /* Space for leading alignment gap. */ +#endif /*NEED_16BYTE_ALIGNED_CONTEXT*/ + ); + + if (secure) + h = gcry_calloc_secure (1, size); + else + h = gcry_calloc (1, size); + + if (! h) + err = gpg_err_code_from_errno (errno); + else + { + size_t off = 0; + +#ifdef NEED_16BYTE_ALIGNED_CONTEXT + if ( ((unsigned long)h & 0x0f) ) + { + /* The malloced block is not aligned on a 16 byte + boundary. Correct for this. */ + off = 16 - ((unsigned long)h & 0x0f); + h = (void*)((char*)h + off); + } +#endif /*NEED_16BYTE_ALIGNED_CONTEXT*/ + + h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; + h->actual_handle_size = size - off; + h->handle_offset = off; + h->cipher = cipher; + h->extraspec = extraspec; + h->module = module; + h->algo = algo; + h->mode = mode; + h->flags = flags; + + /* Setup bulk encryption routines. */ + switch (algo) + { +#ifdef USE_AES + case GCRY_CIPHER_AES128: + case GCRY_CIPHER_AES192: + case GCRY_CIPHER_AES256: + h->bulk.cfb_enc = _gcry_aes_cfb_enc; + h->bulk.cfb_dec = _gcry_aes_cfb_dec; + h->bulk.cbc_enc = _gcry_aes_cbc_enc; + h->bulk.cbc_dec = _gcry_aes_cbc_dec; + break; +#endif /*USE_AES*/ + + default: + break; + } + } + } + + /* Done. */ + + if (err) + { + if (module) + { + /* Release module. */ + ath_mutex_lock (&ciphers_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&ciphers_registered_lock); + } + } + + *handle = err ? NULL : h; + + return gcry_error (err); +} + + +/* Release all resources associated with the cipher handle H. H may be + NULL in which case this is a no-operation. */ +void +gcry_cipher_close (gcry_cipher_hd_t h) +{ + size_t off; + + if (!h) + return; + + if ((h->magic != CTX_MAGIC_SECURE) + && (h->magic != CTX_MAGIC_NORMAL)) + _gcry_fatal_error(GPG_ERR_INTERNAL, + "gcry_cipher_close: already closed/invalid handle"); + else + h->magic = 0; + + /* Release module. */ + ath_mutex_lock (&ciphers_registered_lock); + _gcry_module_release (h->module); + ath_mutex_unlock (&ciphers_registered_lock); + + /* We always want to wipe out the memory even when the context has + been allocated in secure memory. The user might have disabled + secure memory or is using his own implementation which does not + do the wiping. To accomplish this we need to keep track of the + actual size of this structure because we have no way to known + how large the allocated area was when using a standard malloc. */ + off = h->handle_offset; + wipememory (h, h->actual_handle_size); + + gcry_free ((char*)h - off); +} + + +/* Set the key to be used for the encryption context C to KEY with + length KEYLEN. The length should match the required length. */ +static gcry_error_t +cipher_setkey (gcry_cipher_hd_t c, byte *key, unsigned int keylen) +{ + gcry_err_code_t ret; + + ret = (*c->cipher->setkey) (&c->context.c, key, keylen); + if (!ret) + { + /* Duplicate initial context. */ + memcpy ((void *) ((char *) &c->context.c + c->cipher->contextsize), + (void *) &c->context.c, + c->cipher->contextsize); + c->marks.key = 1; + } + else + c->marks.key = 0; + + return gcry_error (ret); +} + + +/* Set the IV to be used for the encryption context C to IV with + length IVLEN. The length should match the required length. */ +static void +cipher_setiv( gcry_cipher_hd_t c, const byte *iv, unsigned ivlen ) +{ + memset (c->u_iv.iv, 0, c->cipher->blocksize); + if (iv) + { + if (ivlen != c->cipher->blocksize) + { + log_info ("WARNING: cipher_setiv: ivlen=%u blklen=%u\n", + ivlen, (unsigned int)c->cipher->blocksize); + fips_signal_error ("IV length does not match blocklength"); + } + if (ivlen > c->cipher->blocksize) + ivlen = c->cipher->blocksize; + memcpy (c->u_iv.iv, iv, ivlen); + c->marks.iv = 1; + } + else + c->marks.iv = 0; + c->unused = 0; +} + + +/* Reset the cipher context to the initial context. This is basically + the same as an release followed by a new. */ +static void +cipher_reset (gcry_cipher_hd_t c) +{ + memcpy (&c->context.c, + (char *) &c->context.c + c->cipher->contextsize, + c->cipher->contextsize); + memset (&c->marks, 0, sizeof c->marks); + memset (c->u_iv.iv, 0, c->cipher->blocksize); + memset (c->lastiv, 0, c->cipher->blocksize); + memset (c->ctr, 0, c->cipher->blocksize); +} + + + +static gcry_err_code_t +do_ecb_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen) +{ + unsigned int blocksize = c->cipher->blocksize; + unsigned int n, nblocks; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if ((inbuflen % blocksize)) + return GPG_ERR_INV_LENGTH; + + nblocks = inbuflen / c->cipher->blocksize; + + for (n=0; n < nblocks; n++ ) + { + c->cipher->encrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf); + inbuf += blocksize; + outbuf += blocksize; + } + return 0; +} + +static gcry_err_code_t +do_ecb_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen) +{ + unsigned int blocksize = c->cipher->blocksize; + unsigned int n, nblocks; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if ((inbuflen % blocksize)) + return GPG_ERR_INV_LENGTH; + nblocks = inbuflen / c->cipher->blocksize; + + for (n=0; n < nblocks; n++ ) + { + c->cipher->decrypt (&c->context.c, outbuf, (byte*)/*arggg*/inbuf ); + inbuf += blocksize; + outbuf += blocksize; + } + + return 0; +} + + +static gcry_err_code_t +do_cbc_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen) +{ + unsigned int n; + unsigned char *ivp; + int i; + size_t blocksize = c->cipher->blocksize; + unsigned nblocks = inbuflen / blocksize; + + if (outbuflen < ((c->flags & GCRY_CIPHER_CBC_MAC)? blocksize : inbuflen)) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ((inbuflen % c->cipher->blocksize) + && !(inbuflen > c->cipher->blocksize + && (c->flags & GCRY_CIPHER_CBC_CTS))) + return GPG_ERR_INV_LENGTH; + + if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize) + { + if ((inbuflen % blocksize) == 0) + nblocks--; + } + + if (c->bulk.cbc_enc) + { + c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks, + (c->flags & GCRY_CIPHER_CBC_MAC)); + inbuf += nblocks * blocksize; + if (!(c->flags & GCRY_CIPHER_CBC_MAC)) + outbuf += nblocks * blocksize; + } + else + { + for (n=0; n < nblocks; n++ ) + { + for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) + outbuf[i] = inbuf[i] ^ *ivp++; + c->cipher->encrypt ( &c->context.c, outbuf, outbuf ); + memcpy (c->u_iv.iv, outbuf, blocksize ); + inbuf += blocksize; + if (!(c->flags & GCRY_CIPHER_CBC_MAC)) + outbuf += blocksize; + } + } + + if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize) + { + /* We have to be careful here, since outbuf might be equal to + inbuf. */ + int restbytes; + unsigned char b; + + if ((inbuflen % blocksize) == 0) + restbytes = blocksize; + else + restbytes = inbuflen % blocksize; + + outbuf -= blocksize; + for (ivp = c->u_iv.iv, i = 0; i < restbytes; i++) + { + b = inbuf[i]; + outbuf[blocksize + i] = outbuf[i]; + outbuf[i] = b ^ *ivp++; + } + for (; i < blocksize; i++) + outbuf[i] = 0 ^ *ivp++; + + c->cipher->encrypt (&c->context.c, outbuf, outbuf); + memcpy (c->u_iv.iv, outbuf, blocksize); + } + + return 0; +} + + +static gcry_err_code_t +do_cbc_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen) +{ + unsigned int n; + unsigned char *ivp; + int i; + size_t blocksize = c->cipher->blocksize; + unsigned int nblocks = inbuflen / blocksize; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ((inbuflen % c->cipher->blocksize) + && !(inbuflen > c->cipher->blocksize + && (c->flags & GCRY_CIPHER_CBC_CTS))) + return GPG_ERR_INV_LENGTH; + + if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize) + { + nblocks--; + if ((inbuflen % blocksize) == 0) + nblocks--; + memcpy (c->lastiv, c->u_iv.iv, blocksize); + } + + if (c->bulk.cbc_dec) + { + c->bulk.cbc_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); + inbuf += nblocks * blocksize; + outbuf += nblocks * blocksize; + } + else + { + for (n=0; n < nblocks; n++ ) + { + /* Because outbuf and inbuf might be the same, we have to + * save the original ciphertext block. We use LASTIV for + * this here because it is not used otherwise. */ + memcpy (c->lastiv, inbuf, blocksize); + c->cipher->decrypt ( &c->context.c, outbuf, inbuf ); + for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) + outbuf[i] ^= *ivp++; + memcpy(c->u_iv.iv, c->lastiv, blocksize ); + inbuf += c->cipher->blocksize; + outbuf += c->cipher->blocksize; + } + } + + if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize) + { + int restbytes; + + if ((inbuflen % blocksize) == 0) + restbytes = blocksize; + else + restbytes = inbuflen % blocksize; + + memcpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */ + memcpy (c->u_iv.iv, inbuf + blocksize, restbytes ); /* Save Cn. */ + + c->cipher->decrypt ( &c->context.c, outbuf, inbuf ); + for (ivp=c->u_iv.iv,i=0; i < restbytes; i++ ) + outbuf[i] ^= *ivp++; + + memcpy(outbuf + blocksize, outbuf, restbytes); + for(i=restbytes; i < blocksize; i++) + c->u_iv.iv[i] = outbuf[i]; + c->cipher->decrypt (&c->context.c, outbuf, c->u_iv.iv); + for(ivp=c->lastiv,i=0; i < blocksize; i++ ) + outbuf[i] ^= *ivp++; + /* c->lastiv is now really lastlastiv, does this matter? */ + } + + return 0; +} + + +static gcry_err_code_t +do_cfb_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen) +{ + unsigned char *ivp; + size_t blocksize = c->cipher->blocksize; + size_t blocksize_x_2 = blocksize + blocksize; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ( inbuflen <= c->unused ) + { + /* Short enough to be encoded by the remaining XOR mask. */ + /* XOR the input with the IV and store input into IV. */ + for (ivp=c->u_iv.iv+c->cipher->blocksize - c->unused; + inbuflen; + inbuflen--, c->unused-- ) + *outbuf++ = (*ivp++ ^= *inbuf++); + return 0; + } + + if ( c->unused ) + { + /* XOR the input with the IV and store input into IV */ + inbuflen -= c->unused; + for(ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) + *outbuf++ = (*ivp++ ^= *inbuf++); + } + + /* Now we can process complete blocks. We use a loop as long as we + have at least 2 blocks and use conditions for the rest. This + also allows to use a bulk encryption function if available. */ + if (inbuflen >= blocksize_x_2 && c->bulk.cfb_enc) + { + unsigned int nblocks = inbuflen / blocksize; + c->bulk.cfb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); + outbuf += nblocks * blocksize; + inbuf += nblocks * blocksize; + inbuflen -= nblocks * blocksize; + } + else + { + while ( inbuflen >= blocksize_x_2 ) + { + int i; + /* Encrypt the IV. */ + c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + /* XOR the input with the IV and store input into IV. */ + for(ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) + *outbuf++ = (*ivp++ ^= *inbuf++); + inbuflen -= blocksize; + } + } + + if ( inbuflen >= blocksize ) + { + int i; + /* Save the current IV and then encrypt the IV. */ + memcpy( c->lastiv, c->u_iv.iv, blocksize ); + c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + /* XOR the input with the IV and store input into IV */ + for(ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) + *outbuf++ = (*ivp++ ^= *inbuf++); + inbuflen -= blocksize; + } + if ( inbuflen ) + { + /* Save the current IV and then encrypt the IV. */ + memcpy( c->lastiv, c->u_iv.iv, blocksize ); + c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + c->unused = blocksize; + /* Apply the XOR. */ + c->unused -= inbuflen; + for(ivp=c->u_iv.iv; inbuflen; inbuflen-- ) + *outbuf++ = (*ivp++ ^= *inbuf++); + } + return 0; +} + + +static gcry_err_code_t +do_cfb_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen) +{ + unsigned char *ivp; + unsigned long temp; + int i; + size_t blocksize = c->cipher->blocksize; + size_t blocksize_x_2 = blocksize + blocksize; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if (inbuflen <= c->unused) + { + /* Short enough to be encoded by the remaining XOR mask. */ + /* XOR the input with the IV and store input into IV. */ + for (ivp=c->u_iv.iv+blocksize - c->unused; + inbuflen; + inbuflen--, c->unused--) + { + temp = *inbuf++; + *outbuf++ = *ivp ^ temp; + *ivp++ = temp; + } + return 0; + } + + if (c->unused) + { + /* XOR the input with the IV and store input into IV. */ + inbuflen -= c->unused; + for (ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) + { + temp = *inbuf++; + *outbuf++ = *ivp ^ temp; + *ivp++ = temp; + } + } + + /* Now we can process complete blocks. We use a loop as long as we + have at least 2 blocks and use conditions for the rest. This + also allows to use a bulk encryption function if available. */ + if (inbuflen >= blocksize_x_2 && c->bulk.cfb_dec) + { + unsigned int nblocks = inbuflen / blocksize; + c->bulk.cfb_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); + outbuf += nblocks * blocksize; + inbuf += nblocks * blocksize; + inbuflen -= nblocks * blocksize; + } + else + { + while (inbuflen >= blocksize_x_2 ) + { + /* Encrypt the IV. */ + c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + /* XOR the input with the IV and store input into IV. */ + for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) + { + temp = *inbuf++; + *outbuf++ = *ivp ^ temp; + *ivp++ = temp; + } + inbuflen -= blocksize; + } + } + + if (inbuflen >= blocksize ) + { + /* Save the current IV and then encrypt the IV. */ + memcpy ( c->lastiv, c->u_iv.iv, blocksize); + c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + /* XOR the input with the IV and store input into IV */ + for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) + { + temp = *inbuf++; + *outbuf++ = *ivp ^ temp; + *ivp++ = temp; + } + inbuflen -= blocksize; + } + + if (inbuflen) + { + /* Save the current IV and then encrypt the IV. */ + memcpy ( c->lastiv, c->u_iv.iv, blocksize ); + c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + c->unused = blocksize; + /* Apply the XOR. */ + c->unused -= inbuflen; + for (ivp=c->u_iv.iv; inbuflen; inbuflen-- ) + { + temp = *inbuf++; + *outbuf++ = *ivp ^ temp; + *ivp++ = temp; + } + } + return 0; +} + + +static gcry_err_code_t +do_ofb_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen) +{ + unsigned char *ivp; + size_t blocksize = c->cipher->blocksize; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ( inbuflen <= c->unused ) + { + /* Short enough to be encoded by the remaining XOR mask. */ + /* XOR the input with the IV */ + for (ivp=c->u_iv.iv+c->cipher->blocksize - c->unused; + inbuflen; + inbuflen--, c->unused-- ) + *outbuf++ = (*ivp++ ^ *inbuf++); + return 0; + } + + if( c->unused ) + { + inbuflen -= c->unused; + for(ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) + *outbuf++ = (*ivp++ ^ *inbuf++); + } + + /* Now we can process complete blocks. */ + while ( inbuflen >= blocksize ) + { + int i; + /* Encrypt the IV (and save the current one). */ + memcpy( c->lastiv, c->u_iv.iv, blocksize ); + c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + + for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) + *outbuf++ = (*ivp++ ^ *inbuf++); + inbuflen -= blocksize; + } + if ( inbuflen ) + { /* process the remaining bytes */ + memcpy( c->lastiv, c->u_iv.iv, blocksize ); + c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + c->unused = blocksize; + c->unused -= inbuflen; + for(ivp=c->u_iv.iv; inbuflen; inbuflen-- ) + *outbuf++ = (*ivp++ ^ *inbuf++); + } + return 0; +} + +static gcry_err_code_t +do_ofb_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen) +{ + unsigned char *ivp; + size_t blocksize = c->cipher->blocksize; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if( inbuflen <= c->unused ) + { + /* Short enough to be encoded by the remaining XOR mask. */ + for (ivp=c->u_iv.iv+blocksize - c->unused; inbuflen; inbuflen--,c->unused--) + *outbuf++ = *ivp++ ^ *inbuf++; + return 0; + } + + if ( c->unused ) + { + inbuflen -= c->unused; + for (ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) + *outbuf++ = *ivp++ ^ *inbuf++; + } + + /* Now we can process complete blocks. */ + while ( inbuflen >= blocksize ) + { + int i; + /* Encrypt the IV (and save the current one). */ + memcpy( c->lastiv, c->u_iv.iv, blocksize ); + c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) + *outbuf++ = *ivp++ ^ *inbuf++; + inbuflen -= blocksize; + } + if ( inbuflen ) + { /* Process the remaining bytes. */ + /* Encrypt the IV (and save the current one). */ + memcpy( c->lastiv, c->u_iv.iv, blocksize ); + c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + c->unused = blocksize; + c->unused -= inbuflen; + for (ivp=c->u_iv.iv; inbuflen; inbuflen-- ) + *outbuf++ = *ivp++ ^ *inbuf++; + } + return 0; +} + + +static gcry_err_code_t +do_ctr_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen) +{ + unsigned int n; + unsigned char tmp[MAX_BLOCKSIZE]; + int i; + unsigned int blocksize = c->cipher->blocksize; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ((inbuflen % blocksize)) + return GPG_ERR_INV_LENGTH; + + for (n=0; n < inbuflen; n++) + { + if ((n % blocksize) == 0) + { + c->cipher->encrypt (&c->context.c, tmp, c->ctr); + + for (i = blocksize; i > 0; i--) + { + c->ctr[i-1]++; + if (c->ctr[i-1] != 0) + break; + } + } + + /* XOR input with encrypted counter and store in output. */ + outbuf[n] = inbuf[n] ^ tmp[n % blocksize]; + } + + wipememory (tmp, sizeof tmp); + return 0; +} + +static gcry_err_code_t +do_ctr_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen) +{ + return do_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); +} + + +/* Perform the AES-Wrap algorithm as specified by RFC3394. We + implement this as a mode usable with any cipher algorithm of + blocksize 128. */ +static gcry_err_code_t +do_aeswrap_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, + const byte *inbuf, unsigned int inbuflen ) +{ + int j, x; + unsigned int n, i; + unsigned char *r, *a, *b; + unsigned char t[8]; + +#if MAX_BLOCKSIZE < 8 +#error Invalid block size +#endif + /* We require a cipher with a 128 bit block length. */ + if (c->cipher->blocksize != 16) + return GPG_ERR_INV_LENGTH; + + /* The output buffer must be able to hold the input data plus one + additional block. */ + if (outbuflen < inbuflen + 8) + return GPG_ERR_BUFFER_TOO_SHORT; + /* Input data must be multiple of 64 bits. */ + if (inbuflen % 8) + return GPG_ERR_INV_ARG; + + n = inbuflen / 8; + + /* We need at least two 64 bit blocks. */ + if (n < 2) + return GPG_ERR_INV_ARG; + + r = outbuf; + a = outbuf; /* We store A directly in OUTBUF. */ + b = c->ctr; /* B is also used to concatenate stuff. */ + + /* If an IV has been set we use that IV as the Alternative Initial + Value; if it has not been set we use the standard value. */ + if (c->marks.iv) + memcpy (a, c->u_iv.iv, 8); + else + memset (a, 0xa6, 8); + + /* Copy the inbuf to the outbuf. */ + memmove (r+8, inbuf, inbuflen); + + memset (t, 0, sizeof t); /* t := 0. */ + + for (j = 0; j <= 5; j++) + { + for (i = 1; i <= n; i++) + { + /* B := AES_k( A | R[i] ) */ + memcpy (b, a, 8); + memcpy (b+8, r+i*8, 8); + c->cipher->encrypt (&c->context.c, b, b); + /* t := t + 1 */ + for (x = 7; x >= 0; x--) + { + t[x]++; + if (t[x]) + break; + } + /* A := MSB_64(B) ^ t */ + for (x=0; x < 8; x++) + a[x] = b[x] ^ t[x]; + /* R[i] := LSB_64(B) */ + memcpy (r+i*8, b+8, 8); + } + } + + return 0; +} + +/* Perform the AES-Unwrap algorithm as specified by RFC3394. We + implement this as a mode usable with any cipher algorithm of + blocksize 128. */ +static gcry_err_code_t +do_aeswrap_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, + const byte *inbuf, unsigned int inbuflen) +{ + int j, x; + unsigned int n, i; + unsigned char *r, *a, *b; + unsigned char t[8]; + +#if MAX_BLOCKSIZE < 8 +#error Invalid block size +#endif + /* We require a cipher with a 128 bit block length. */ + if (c->cipher->blocksize != 16) + return GPG_ERR_INV_LENGTH; + + /* The output buffer must be able to hold the input data minus one + additional block. Fixme: The caller has more restrictive checks + - we may want to fix them for this mode. */ + if (outbuflen + 8 < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + /* Input data must be multiple of 64 bits. */ + if (inbuflen % 8) + return GPG_ERR_INV_ARG; + + n = inbuflen / 8; + + /* We need at least three 64 bit blocks. */ + if (n < 3) + return GPG_ERR_INV_ARG; + + r = outbuf; + a = c->lastiv; /* We use c->LASTIV as buffer for A. */ + b = c->ctr; /* B is also used to concatenate stuff. */ + + /* Copy the inbuf to the outbuf and save A. */ + memcpy (a, inbuf, 8); + memmove (r, inbuf+8, inbuflen-8); + n--; /* Reduce to actual number of data blocks. */ + + /* t := 6 * n */ + i = n * 6; /* The range is valid because: n = inbuflen / 8 - 1. */ + for (x=0; x < 8 && x < sizeof (i); x++) + t[7-x] = i >> (8*x); + for (; x < 8; x++) + t[7-x] = 0; + + for (j = 5; j >= 0; j--) + { + for (i = n; i >= 1; i--) + { + /* B := AES_k^1( (A ^ t)| R[i] ) */ + for (x = 0; x < 8; x++) + b[x] = a[x] ^ t[x]; + memcpy (b+8, r+(i-1)*8, 8); + c->cipher->decrypt (&c->context.c, b, b); + /* t := t - 1 */ + for (x = 7; x >= 0; x--) + { + t[x]--; + if (t[x] != 0xff) + break; + } + /* A := MSB_64(B) */ + memcpy (a, b, 8); + /* R[i] := LSB_64(B) */ + memcpy (r+(i-1)*8, b+8, 8); + } + } + + /* If an IV has been set we compare against this Alternative Initial + Value; if it has not been set we compare against the standard IV. */ + if (c->marks.iv) + j = memcmp (a, c->u_iv.iv, 8); + else + { + for (j=0, x=0; x < 8; x++) + if (a[x] != 0xa6) + { + j=1; + break; + } + } + return j? GPG_ERR_CHECKSUM : 0; +} + + +/**************** + * Encrypt INBUF to OUTBUF with the mode selected at open. + * inbuf and outbuf may overlap or be the same. + * Depending on the mode some constraints apply to INBUFLEN. + */ +static gcry_err_code_t +cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, + const byte *inbuf, unsigned int inbuflen) +{ + gcry_err_code_t rc; + + switch (c->mode) + { + case GCRY_CIPHER_MODE_ECB: + rc = do_ecb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_CBC: + rc = do_cbc_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_CFB: + rc = do_cfb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_OFB: + rc = do_ofb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_CTR: + rc = do_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_AESWRAP: + rc = do_aeswrap_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_STREAM: + c->cipher->stencrypt (&c->context.c, + outbuf, (byte*)/*arggg*/inbuf, inbuflen); + rc = 0; + break; + + case GCRY_CIPHER_MODE_NONE: + if (fips_mode () || !_gcry_get_debug_flag (0)) + { + fips_signal_error ("cipher mode NONE used"); + rc = GPG_ERR_INV_CIPHER_MODE; + } + else + { + if (inbuf != outbuf) + memmove (outbuf, inbuf, inbuflen); + rc = 0; + } + break; + + default: + log_fatal ("cipher_encrypt: invalid mode %d\n", c->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } + + return rc; +} + + +/**************** + * Encrypt IN and write it to OUT. If IN is NULL, in-place encryption has + * been requested. + */ +gcry_error_t +gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize, + const void *in, size_t inlen) +{ + gcry_err_code_t err; + + if (!in) /* Caller requested in-place encryption. */ + err = cipher_encrypt (h, out, outsize, out, outsize); + else + err = cipher_encrypt (h, out, outsize, in, inlen); + + /* Failsafe: Make sure that the plaintext will never make it into + OUT if the encryption returned an error. */ + if (err && out) + memset (out, 0x42, outsize); + + return gcry_error (err); +} + + + +/**************** + * Decrypt INBUF to OUTBUF with the mode selected at open. + * inbuf and outbuf may overlap or be the same. + * Depending on the mode some some contraints apply to INBUFLEN. + */ +static gcry_err_code_t +cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, + const byte *inbuf, unsigned int inbuflen) +{ + gcry_err_code_t rc; + + switch (c->mode) + { + case GCRY_CIPHER_MODE_ECB: + rc = do_ecb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_CBC: + rc = do_cbc_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_CFB: + rc = do_cfb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_OFB: + rc = do_ofb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_CTR: + rc = do_ctr_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_AESWRAP: + rc = do_aeswrap_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_STREAM: + c->cipher->stdecrypt (&c->context.c, + outbuf, (byte*)/*arggg*/inbuf, inbuflen); + rc = 0; + break; + + case GCRY_CIPHER_MODE_NONE: + if (fips_mode () || !_gcry_get_debug_flag (0)) + { + fips_signal_error ("cipher mode NONE used"); + rc = GPG_ERR_INV_CIPHER_MODE; + } + else + { + if (inbuf != outbuf) + memmove (outbuf, inbuf, inbuflen); + rc = 0; + } + break; + + default: + log_fatal ("cipher_decrypt: invalid mode %d\n", c->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } + + return rc; +} + + +gcry_error_t +gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize, + const void *in, size_t inlen) +{ + gcry_err_code_t err; + + if (!in) /* Caller requested in-place encryption. */ + err = cipher_decrypt (h, out, outsize, out, outsize); + else + err = cipher_decrypt (h, out, outsize, in, inlen); + + return gcry_error (err); +} + + + +/**************** + * Used for PGP's somewhat strange CFB mode. Only works if + * the corresponding flag is set. + */ +static void +cipher_sync (gcry_cipher_hd_t c) +{ + if ((c->flags & GCRY_CIPHER_ENABLE_SYNC) && c->unused) + { + memmove (c->u_iv.iv + c->unused, + c->u_iv.iv, c->cipher->blocksize - c->unused); + memcpy (c->u_iv.iv, + c->lastiv + c->cipher->blocksize - c->unused, c->unused); + c->unused = 0; + } +} + + +gcry_error_t +_gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen) +{ + return cipher_setkey (hd, (void*)key, keylen); +} + + +gcry_error_t +_gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) +{ + cipher_setiv (hd, iv, ivlen); + return 0; +} + +/* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of + block size length, or (NULL,0) to set the CTR to the all-zero + block. */ +gpg_error_t +_gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) +{ + if (ctr && ctrlen == hd->cipher->blocksize) + memcpy (hd->ctr, ctr, hd->cipher->blocksize); + else if (!ctr || !ctrlen) + memset (hd->ctr, 0, hd->cipher->blocksize); + else + return gpg_error (GPG_ERR_INV_ARG); + return 0; +} + + +gcry_error_t +gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) +{ + gcry_err_code_t rc = GPG_ERR_NO_ERROR; + + switch (cmd) + { + case GCRYCTL_SET_KEY: /* Deprecated; use gcry_cipher_setkey. */ + rc = cipher_setkey( h, buffer, buflen ); + break; + + case GCRYCTL_SET_IV: /* Deprecated; use gcry_cipher_setiv. */ + cipher_setiv( h, buffer, buflen ); + break; + + case GCRYCTL_RESET: + cipher_reset (h); + break; + + case GCRYCTL_CFB_SYNC: + cipher_sync( h ); + break; + + case GCRYCTL_SET_CBC_CTS: + if (buflen) + if (h->flags & GCRY_CIPHER_CBC_MAC) + rc = GPG_ERR_INV_FLAG; + else + h->flags |= GCRY_CIPHER_CBC_CTS; + else + h->flags &= ~GCRY_CIPHER_CBC_CTS; + break; + + case GCRYCTL_SET_CBC_MAC: + if (buflen) + if (h->flags & GCRY_CIPHER_CBC_CTS) + rc = GPG_ERR_INV_FLAG; + else + h->flags |= GCRY_CIPHER_CBC_MAC; + else + h->flags &= ~GCRY_CIPHER_CBC_MAC; + break; + + case GCRYCTL_DISABLE_ALGO: + /* This command expects NULL for H and BUFFER to point to an + integer with the algo number. */ + if( h || !buffer || buflen != sizeof(int) ) + return gcry_error (GPG_ERR_CIPHER_ALGO); + disable_cipher_algo( *(int*)buffer ); + break; + + case GCRYCTL_SET_CTR: /* Deprecated; use gcry_cipher_setctr. */ + if (buffer && buflen == h->cipher->blocksize) + memcpy (h->ctr, buffer, h->cipher->blocksize); + else if (buffer == NULL || buflen == 0) + memset (h->ctr, 0, h->cipher->blocksize); + else + rc = GPG_ERR_INV_ARG; + break; + + case 61: /* Disable weak key detection (private). */ + if (h->extraspec->set_extra_info) + rc = h->extraspec->set_extra_info + (&h->context.c, CIPHER_INFO_NO_WEAK_KEY, NULL, 0); + else + rc = GPG_ERR_NOT_SUPPORTED; + break; + + case 62: /* Return current input vector (private). */ + /* This is the input block as used in CFB and OFB mode which has + initially been set as IV. The returned format is: + 1 byte Actual length of the block in bytes. + n byte The block. + If the provided buffer is too short, an error is returned. */ + if (buflen < (1 + h->cipher->blocksize)) + rc = GPG_ERR_TOO_SHORT; + else + { + unsigned char *ivp; + unsigned char *dst = buffer; + int n = h->unused; + + if (!n) + n = h->cipher->blocksize; + gcry_assert (n <= h->cipher->blocksize); + *dst++ = n; + ivp = h->u_iv.iv + h->cipher->blocksize - n; + while (n--) + *dst++ = *ivp++; + } + break; + + default: + rc = GPG_ERR_INV_OP; + } + + return gcry_error (rc); +} + + +/* Return information about the cipher handle H. CMD is the kind of + information requested. BUFFER and NBYTES are reserved for now. + + There are no values for CMD yet defined. + + The function always returns GPG_ERR_INV_OP. + + */ +gcry_error_t +gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + (void)h; + (void)buffer; + (void)nbytes; + + switch (cmd) + { + default: + err = GPG_ERR_INV_OP; + } + + return gcry_error (err); +} + +/* Return information about the given cipher algorithm ALGO. + + WHAT select the kind of information returned: + + GCRYCTL_GET_KEYLEN: + Return the length of the key. If the algorithm ALGO + supports multiple key lengths, the maximum supported key length + is returned. The key length is returned as number of octets. + BUFFER and NBYTES must be zero. + + GCRYCTL_GET_BLKLEN: + Return the blocklength of the algorithm ALGO counted in octets. + BUFFER and NBYTES must be zero. + + GCRYCTL_TEST_ALGO: + Returns 0 if the specified algorithm ALGO is available for use. + BUFFER and NBYTES must be zero. + + Note: Because this function is in most cases used to return an + integer value, we can make it easier for the caller to just look at + the return value. The caller will in all cases consult the value + and thereby detecting whether a error occurred or not (i.e. while + checking the block size) + */ +gcry_error_t +gcry_cipher_algo_info (int algo, int what, void *buffer, size_t *nbytes) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + unsigned int ui; + + switch (what) + { + case GCRYCTL_GET_KEYLEN: + if (buffer || (! nbytes)) + err = GPG_ERR_CIPHER_ALGO; + else + { + ui = cipher_get_keylen (algo); + if ((ui > 0) && (ui <= 512)) + *nbytes = (size_t) ui / 8; + else + /* The only reason is an invalid algo or a strange + blocksize. */ + err = GPG_ERR_CIPHER_ALGO; + } + break; + + case GCRYCTL_GET_BLKLEN: + if (buffer || (! nbytes)) + err = GPG_ERR_CIPHER_ALGO; + else + { + ui = cipher_get_blocksize (algo); + if ((ui > 0) && (ui < 10000)) + *nbytes = ui; + else + /* The only reason is an invalid algo or a strange + blocksize. */ + err = GPG_ERR_CIPHER_ALGO; + } + break; + + case GCRYCTL_TEST_ALGO: + if (buffer || nbytes) + err = GPG_ERR_INV_ARG; + else + err = check_cipher_algo (algo); + break; + + default: + err = GPG_ERR_INV_OP; + } + + return gcry_error (err); +} + + +/* This function returns length of the key for algorithm ALGO. If the + algorithm supports multiple key lengths, the maximum supported key + length is returned. On error 0 is returned. The key length is + returned as number of octets. + + This is a convenience functions which should be preferred over + gcry_cipher_algo_info because it allows for proper type + checking. */ +size_t +gcry_cipher_get_algo_keylen (int algo) +{ + size_t n; + + if (gcry_cipher_algo_info (algo, GCRYCTL_GET_KEYLEN, NULL, &n)) + n = 0; + return n; +} + +/* This functions returns the blocklength of the algorithm ALGO + counted in octets. On error 0 is returned. + + This is a convenience functions which should be preferred over + gcry_cipher_algo_info because it allows for proper type + checking. */ +size_t +gcry_cipher_get_algo_blklen (int algo) +{ + size_t n; + + if (gcry_cipher_algo_info( algo, GCRYCTL_GET_BLKLEN, NULL, &n)) + n = 0; + return n; +} + +/* Explicitly initialize this module. */ +gcry_err_code_t +_gcry_cipher_init (void) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + REGISTER_DEFAULT_CIPHERS; + + return err; +} + +/* Get a list consisting of the IDs of the loaded cipher modules. If + LIST is zero, write the number of loaded cipher modules to + LIST_LENGTH and return. If LIST is non-zero, the first + *LIST_LENGTH algorithm IDs are stored in LIST, which must be of + according size. In case there are less cipher modules than + *LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */ +gcry_error_t +gcry_cipher_list (int *list, int *list_length) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + ath_mutex_lock (&ciphers_registered_lock); + err = _gcry_module_list (ciphers_registered, list, list_length); + ath_mutex_unlock (&ciphers_registered_lock); + + return err; +} + + +/* Run the selftests for cipher algorithm ALGO with optional reporting + function REPORT. */ +gpg_error_t +_gcry_cipher_selftest (int algo, int extended, selftest_report_func_t report) +{ + gcry_module_t module = NULL; + cipher_extra_spec_t *extraspec = NULL; + gcry_err_code_t ec = 0; + + REGISTER_DEFAULT_CIPHERS; + + ath_mutex_lock (&ciphers_registered_lock); + module = _gcry_module_lookup_id (ciphers_registered, algo); + if (module && !(module->flags & FLAG_MODULE_DISABLED)) + extraspec = module->extraspec; + ath_mutex_unlock (&ciphers_registered_lock); + if (extraspec && extraspec->selftest) + ec = extraspec->selftest (algo, extended, report); + else + { + ec = GPG_ERR_CIPHER_ALGO; + if (report) + report ("cipher", algo, "module", + module && !(module->flags & FLAG_MODULE_DISABLED)? + "no selftest available" : + module? "algorithm disabled" : "algorithm not found"); + } + + if (module) + { + ath_mutex_lock (&ciphers_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&ciphers_registered_lock); + } + return gpg_error (ec); +} diff --git a/libgcrypt-1.4.6/cipher/ecc.c b/libgcrypt-1.4.6/cipher/ecc.c index fcbd8e3..bcfab05 100644 --- a/libgcrypt-1.4.6/cipher/ecc.c +++ b/libgcrypt-1.4.6/cipher/ecc.c @@ -1,5 +1,5 @@ /* ecc.c - Elliptic Curve Cryptography - Copyright (C) 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc. This file is part of Libgcrypt. @@ -504,6 +504,7 @@ generate_curve (unsigned int nbits, const char *name, */ static gpg_err_code_t generate_key (ECC_secret_key *sk, unsigned int nbits, const char *name, + int transient_key, gcry_mpi_t g_x, gcry_mpi_t g_y, gcry_mpi_t q_x, gcry_mpi_t q_y) { @@ -512,6 +513,7 @@ generate_key (ECC_secret_key *sk, unsigned int nbits, const char *name, gcry_mpi_t d; mpi_point_t Q; mpi_ec_t ctx; + gcry_random_level_t random_level; err = generate_curve (nbits, name, &E, &nbits); if (err) @@ -528,9 +530,11 @@ generate_key (ECC_secret_key *sk, unsigned int nbits, const char *name, log_mpidump ("ecc generation Gz", E.G.z); } + random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM; if (DBG_CIPHER) - log_debug ("choosing a random x of size %u\n", nbits); - d = gen_k (E.n, GCRY_VERY_STRONG_RANDOM); + log_debug ("choosing a random x of size %u%s\n", nbits, + transient_key? " (transient-key)":""); + d = gen_k (E.n, random_level); /* Compute Q. */ point_init (&Q); @@ -962,6 +966,7 @@ ecc_generate_ext (int algo, unsigned int nbits, unsigned long evalue, gcry_mpi_t g_x, g_y, q_x, q_y; char *curve_name = NULL; gcry_sexp_t l1; + int transient_key = 0; (void)algo; (void)evalue; @@ -978,6 +983,14 @@ ecc_generate_ext (int algo, unsigned int nbits, unsigned long evalue, if (!curve_name) return GPG_ERR_INV_OBJ; /* No curve name or value too large. */ } + + /* Parse the optional transient-key flag. */ + l1 = gcry_sexp_find_token (genparms, "transient-key", 0); + if (l1) + { + transient_key = 1; + gcry_sexp_release (l1); + } } /* NBITS is required if no curve name has been given. */ @@ -988,7 +1001,7 @@ ecc_generate_ext (int algo, unsigned int nbits, unsigned long evalue, g_y = mpi_new (0); q_x = mpi_new (0); q_y = mpi_new (0); - ec = generate_key (&sk, nbits, curve_name, g_x, g_y, q_x, q_y); + ec = generate_key (&sk, nbits, curve_name, transient_key, g_x, g_y, q_x, q_y); gcry_free (curve_name); if (ec) return ec; @@ -1266,7 +1279,7 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam) } /* Check that all parameters are known and normalize all MPIs (that - should not be required but we use an internal fucntion later and + should not be required but we use an internal function later and thus we better make 100% sure that they are normalized). */ for (idx = 0; idx < 6; idx++) if (!values[idx]) diff --git a/libgcrypt-1.4.6/cipher/md.c b/libgcrypt-1.4.6/cipher/md.c index 84c7799..5f9dbc6 100644 --- a/libgcrypt-1.4.6/cipher/md.c +++ b/libgcrypt-1.4.6/cipher/md.c @@ -1,1382 +1,1382 @@ -/* md.c - message digest dispatcher - * Copyright (C) 1998, 1999, 2002, 2003, 2006, - * 2008 Free Software Foundation, Inc. - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser general Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see . - */ - -#include -#include -#include -#include -#include - -#include "g10lib.h" -#include "cipher.h" -#include "ath.h" - -#include "rmd.h" - -/* A dummy extraspec so that we do not need to tests the extraspec - field from the module specification against NULL and instead - directly test the respective fields of extraspecs. */ -static md_extra_spec_t dummy_extra_spec; - - -/* This is the list of the digest implementations included in - libgcrypt. */ -static struct digest_table_entry -{ - gcry_md_spec_t *digest; - md_extra_spec_t *extraspec; - unsigned int algorithm; - int fips_allowed; -} digest_table[] = - { -#if USE_CRC - /* We allow the CRC algorithms even in FIPS mode because they are - actually no cryptographic primitives. */ - { &_gcry_digest_spec_crc32, - &dummy_extra_spec, GCRY_MD_CRC32, 1 }, - { &_gcry_digest_spec_crc32_rfc1510, - &dummy_extra_spec, GCRY_MD_CRC32_RFC1510, 1 }, - { &_gcry_digest_spec_crc24_rfc2440, - &dummy_extra_spec, GCRY_MD_CRC24_RFC2440, 1 }, -#endif -#if USE_MD4 - { &_gcry_digest_spec_md4, - &dummy_extra_spec, GCRY_MD_MD4 }, -#endif -#if USE_MD5 - { &_gcry_digest_spec_md5, - &dummy_extra_spec, GCRY_MD_MD5, 1 }, -#endif -#if USE_RMD160 - { &_gcry_digest_spec_rmd160, - &dummy_extra_spec, GCRY_MD_RMD160 }, -#endif -#if USE_SHA1 - { &_gcry_digest_spec_sha1, - &_gcry_digest_extraspec_sha1, GCRY_MD_SHA1, 1 }, -#endif -#if USE_SHA256 - { &_gcry_digest_spec_sha256, - &_gcry_digest_extraspec_sha256, GCRY_MD_SHA256, 1 }, - { &_gcry_digest_spec_sha224, - &_gcry_digest_extraspec_sha224, GCRY_MD_SHA224, 1 }, -#endif -#if USE_SHA512 - { &_gcry_digest_spec_sha512, - &_gcry_digest_extraspec_sha512, GCRY_MD_SHA512, 1 }, - { &_gcry_digest_spec_sha384, - &_gcry_digest_extraspec_sha384, GCRY_MD_SHA384, 1 }, -#endif -#if USE_TIGER - { &_gcry_digest_spec_tiger, - &dummy_extra_spec, GCRY_MD_TIGER }, - { &_gcry_digest_spec_tiger1, - &dummy_extra_spec, GCRY_MD_TIGER1 }, - { &_gcry_digest_spec_tiger2, - &dummy_extra_spec, GCRY_MD_TIGER2 }, -#endif -#if USE_WHIRLPOOL - { &_gcry_digest_spec_whirlpool, - &dummy_extra_spec, GCRY_MD_WHIRLPOOL }, -#endif - { NULL }, - }; - -/* List of registered digests. */ -static gcry_module_t digests_registered; - -/* This is the lock protecting DIGESTS_REGISTERED. */ -static ath_mutex_t digests_registered_lock = ATH_MUTEX_INITIALIZER; - -/* Flag to check wether the default ciphers have already been - registered. */ -static int default_digests_registered; - -typedef struct gcry_md_list -{ - gcry_md_spec_t *digest; - gcry_module_t module; - struct gcry_md_list *next; - size_t actual_struct_size; /* Allocated size of this structure. */ - PROPERLY_ALIGNED_TYPE context; -} GcryDigestEntry; - -/* this structure is put right after the gcry_md_hd_t buffer, so that - * only one memory block is needed. */ -struct gcry_md_context -{ - int magic; - size_t actual_handle_size; /* Allocated size of this handle. */ - int secure; - FILE *debug; - int finalized; - GcryDigestEntry *list; - byte *macpads; - int macpads_Bsize; /* Blocksize as used for the HMAC pads. */ -}; - - -#define CTX_MAGIC_NORMAL 0x11071961 -#define CTX_MAGIC_SECURE 0x16917011 - -/* Convenient macro for registering the default digests. */ -#define REGISTER_DEFAULT_DIGESTS \ - do \ - { \ - ath_mutex_lock (&digests_registered_lock); \ - if (! default_digests_registered) \ - { \ - md_register_default (); \ - default_digests_registered = 1; \ - } \ - ath_mutex_unlock (&digests_registered_lock); \ - } \ - while (0) - - -static const char * digest_algo_to_string( int algo ); -static gcry_err_code_t check_digest_algo (int algo); -static gcry_err_code_t md_open (gcry_md_hd_t *h, int algo, - int secure, int hmac); -static gcry_err_code_t md_enable (gcry_md_hd_t hd, int algo); -static gcry_err_code_t md_copy (gcry_md_hd_t a, gcry_md_hd_t *b); -static void md_close (gcry_md_hd_t a); -static void md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen); -static void md_final(gcry_md_hd_t a); -static byte *md_read( gcry_md_hd_t a, int algo ); -static int md_get_algo( gcry_md_hd_t a ); -static int md_digest_length( int algo ); -static const byte *md_asn_oid( int algo, size_t *asnlen, size_t *mdlen ); -static void md_start_debug ( gcry_md_hd_t a, const char *suffix ); -static void md_stop_debug ( gcry_md_hd_t a ); - - - - -/* Internal function. Register all the ciphers included in - CIPHER_TABLE. Returns zero on success or an error code. */ -static void -md_register_default (void) -{ - gcry_err_code_t err = 0; - int i; - - for (i = 0; !err && digest_table[i].digest; i++) - { - if ( fips_mode ()) - { - if (!digest_table[i].fips_allowed) - continue; - if (digest_table[i].algorithm == GCRY_MD_MD5 - && _gcry_enforced_fips_mode () ) - continue; /* Do not register in enforced fips mode. */ - } - - err = _gcry_module_add (&digests_registered, - digest_table[i].algorithm, - (void *) digest_table[i].digest, - (void *) digest_table[i].extraspec, - NULL); - } - - if (err) - BUG (); -} - -/* Internal callback function. */ -static int -gcry_md_lookup_func_name (void *spec, void *data) -{ - gcry_md_spec_t *digest = (gcry_md_spec_t *) spec; - char *name = (char *) data; - - return (! stricmp (digest->name, name)); -} - -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_md_lookup_func_oid (void *spec, void *data) -{ - gcry_md_spec_t *digest = (gcry_md_spec_t *) spec; - char *oid = (char *) data; - gcry_md_oid_spec_t *oid_specs = digest->oids; - int ret = 0, i; - - if (oid_specs) - { - for (i = 0; oid_specs[i].oidstring && (! ret); i++) - if (! stricmp (oid, oid_specs[i].oidstring)) - ret = 1; - } - - return ret; -} - -/* Internal function. Lookup a digest entry by it's name. */ -static gcry_module_t -gcry_md_lookup_name (const char *name) -{ - gcry_module_t digest; - - digest = _gcry_module_lookup (digests_registered, (void *) name, - gcry_md_lookup_func_name); - - return digest; -} - -/* Internal function. Lookup a cipher entry by it's oid. */ -static gcry_module_t -gcry_md_lookup_oid (const char *oid) -{ - gcry_module_t digest; - - digest = _gcry_module_lookup (digests_registered, (void *) oid, - gcry_md_lookup_func_oid); - - return digest; -} - -/* Register a new digest module whose specification can be found in - DIGEST. On success, a new algorithm ID is stored in ALGORITHM_ID - and a pointer representhing this module is stored in MODULE. */ -gcry_error_t -_gcry_md_register (gcry_md_spec_t *digest, - md_extra_spec_t *extraspec, - unsigned int *algorithm_id, - gcry_module_t *module) -{ - gcry_err_code_t err = 0; - gcry_module_t mod; - - /* We do not support module loading in fips mode. */ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - ath_mutex_lock (&digests_registered_lock); - err = _gcry_module_add (&digests_registered, 0, - (void *) digest, - (void *)(extraspec? extraspec : &dummy_extra_spec), - &mod); - ath_mutex_unlock (&digests_registered_lock); - - if (! err) - { - *module = mod; - *algorithm_id = mod->mod_id; - } - - return gcry_error (err); -} - -/* Unregister the digest identified by ID, which must have been - registered with gcry_digest_register. */ -void -gcry_md_unregister (gcry_module_t module) -{ - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&digests_registered_lock); -} - - -static int -search_oid (const char *oid, int *algorithm, gcry_md_oid_spec_t *oid_spec) -{ - gcry_module_t module; - int ret = 0; - - if (oid && ((! strncmp (oid, "oid.", 4)) - || (! strncmp (oid, "OID.", 4)))) - oid += 4; - - module = gcry_md_lookup_oid (oid); - if (module) - { - gcry_md_spec_t *digest = module->spec; - int i; - - for (i = 0; digest->oids[i].oidstring && !ret; i++) - if (! stricmp (oid, digest->oids[i].oidstring)) - { - if (algorithm) - *algorithm = module->mod_id; - if (oid_spec) - *oid_spec = digest->oids[i]; - ret = 1; - } - _gcry_module_release (module); - } - - return ret; -} - -/**************** - * Map a string to the digest algo - */ -int -gcry_md_map_name (const char *string) -{ - gcry_module_t digest; - int ret, algorithm = 0; - - if (! string) - return 0; - - REGISTER_DEFAULT_DIGESTS; - - /* If the string starts with a digit (optionally prefixed with - either "OID." or "oid."), we first look into our table of ASN.1 - object identifiers to figure out the algorithm */ - - ath_mutex_lock (&digests_registered_lock); - - ret = search_oid (string, &algorithm, NULL); - if (! ret) - { - /* Not found, search a matching digest name. */ - digest = gcry_md_lookup_name (string); - if (digest) - { - algorithm = digest->mod_id; - _gcry_module_release (digest); - } - } - ath_mutex_unlock (&digests_registered_lock); - - return algorithm; -} - - -/**************** - * Map a digest algo to a string - */ -static const char * -digest_algo_to_string (int algorithm) -{ - const char *name = NULL; - gcry_module_t digest; - - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - { - name = ((gcry_md_spec_t *) digest->spec)->name; - _gcry_module_release (digest); - } - ath_mutex_unlock (&digests_registered_lock); - - return name; -} - -/**************** - * This function simply returns the name of the algorithm or some constant - * string when there is no algo. It will never return NULL. - * Use the macro gcry_md_test_algo() to check whether the algorithm - * is valid. - */ -const char * -gcry_md_algo_name (int algorithm) -{ - const char *s = digest_algo_to_string (algorithm); - return s ? s : "?"; -} - - -static gcry_err_code_t -check_digest_algo (int algorithm) -{ - gcry_err_code_t rc = 0; - gcry_module_t digest; - - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - _gcry_module_release (digest); - else - rc = GPG_ERR_DIGEST_ALGO; - ath_mutex_unlock (&digests_registered_lock); - - return rc; -} - - - -/**************** - * Open a message digest handle for use with algorithm ALGO. - * More algorithms may be added by md_enable(). The initial algorithm - * may be 0. - */ -static gcry_err_code_t -md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - int bufsize = secure ? 512 : 1024; - struct gcry_md_context *ctx; - gcry_md_hd_t hd; - size_t n; - - /* Allocate a memory area to hold the caller visible buffer with it's - * control information and the data required by this module. Set the - * context pointer at the beginning to this area. - * We have to use this strange scheme because we want to hide the - * internal data but have a variable sized buffer. - * - * +---+------+---........------+-------------+ - * !ctx! bctl ! buffer ! private ! - * +---+------+---........------+-------------+ - * ! ^ - * !---------------------------! - * - * We have to make sure that private is well aligned. - */ - n = sizeof (struct gcry_md_handle) + bufsize; - n = ((n + sizeof (PROPERLY_ALIGNED_TYPE) - 1) - / sizeof (PROPERLY_ALIGNED_TYPE)) * sizeof (PROPERLY_ALIGNED_TYPE); - - /* Allocate and set the Context pointer to the private data */ - if (secure) - hd = gcry_malloc_secure (n + sizeof (struct gcry_md_context)); - else - hd = gcry_malloc (n + sizeof (struct gcry_md_context)); - - if (! hd) - err = gpg_err_code_from_errno (errno); - - if (! err) - { - hd->ctx = ctx = (struct gcry_md_context *) ((char *) hd + n); - /* Setup the globally visible data (bctl in the diagram).*/ - hd->bufsize = n - sizeof (struct gcry_md_handle) + 1; - hd->bufpos = 0; - - /* Initialize the private data. */ - memset (hd->ctx, 0, sizeof *hd->ctx); - ctx->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; - ctx->actual_handle_size = n + sizeof (struct gcry_md_context); - ctx->secure = secure; - - if (hmac) - { - switch (algo) - { - case GCRY_MD_SHA384: - case GCRY_MD_SHA512: - ctx->macpads_Bsize = 128; - break; - default: - ctx->macpads_Bsize = 64; - break; - } - ctx->macpads = gcry_malloc_secure (2*(ctx->macpads_Bsize)); - if (!ctx->macpads) - { - err = gpg_err_code_from_errno (errno); - md_close (hd); - } - } - } - - if (! err) - { - /* Hmmm, should we really do that? - yes [-wk] */ - _gcry_fast_random_poll (); - - if (algo) - { - err = md_enable (hd, algo); - if (err) - md_close (hd); - } - } - - if (! err) - *h = hd; - - return err; -} - -/* Create a message digest object for algorithm ALGO. FLAGS may be - given as an bitwise OR of the gcry_md_flags values. ALGO may be - given as 0 if the algorithms to be used are later set using - gcry_md_enable. H is guaranteed to be a valid handle or NULL on - error. */ -gcry_error_t -gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_md_hd_t hd; - - if ((flags & ~(GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC))) - err = GPG_ERR_INV_ARG; - else - { - err = md_open (&hd, algo, (flags & GCRY_MD_FLAG_SECURE), - (flags & GCRY_MD_FLAG_HMAC)); - } - - *h = err? NULL : hd; - return gcry_error (err); -} - - - -static gcry_err_code_t -md_enable (gcry_md_hd_t hd, int algorithm) -{ - struct gcry_md_context *h = hd->ctx; - gcry_md_spec_t *digest = NULL; - GcryDigestEntry *entry; - gcry_module_t module; - gcry_err_code_t err = 0; - - for (entry = h->list; entry; entry = entry->next) - if (entry->module->mod_id == algorithm) - return err; /* already enabled */ - - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - module = _gcry_module_lookup_id (digests_registered, algorithm); - ath_mutex_unlock (&digests_registered_lock); - if (! module) - { - log_debug ("md_enable: algorithm %d not available\n", algorithm); - err = GPG_ERR_DIGEST_ALGO; - } - else - digest = (gcry_md_spec_t *) module->spec; - - - if (!err && algorithm == GCRY_MD_MD5 && fips_mode ()) - { - _gcry_inactivate_fips_mode ("MD5 used"); - if (_gcry_enforced_fips_mode () ) - { - /* We should never get to here because we do not register - MD5 in enforced fips mode. But better throw an error. */ - err = GPG_ERR_DIGEST_ALGO; - } - } - - if (!err) - { - size_t size = (sizeof (*entry) - + digest->contextsize - - sizeof (entry->context)); - - /* And allocate a new list entry. */ - if (h->secure) - entry = gcry_malloc_secure (size); - else - entry = gcry_malloc (size); - - if (! entry) - err = gpg_err_code_from_errno (errno); - else - { - entry->digest = digest; - entry->module = module; - entry->next = h->list; - entry->actual_struct_size = size; - h->list = entry; - - /* And init this instance. */ - entry->digest->init (&entry->context.c); - } - } - - if (err) - { - if (module) - { - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&digests_registered_lock); - } - } - - return err; -} - - -gcry_error_t -gcry_md_enable (gcry_md_hd_t hd, int algorithm) -{ - return gcry_error (md_enable (hd, algorithm)); -} - -static gcry_err_code_t -md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - struct gcry_md_context *a = ahd->ctx; - struct gcry_md_context *b; - GcryDigestEntry *ar, *br; - gcry_md_hd_t bhd; - size_t n; - - if (ahd->bufpos) - md_write (ahd, NULL, 0); - - n = (char *) ahd->ctx - (char *) ahd; - if (a->secure) - bhd = gcry_malloc_secure (n + sizeof (struct gcry_md_context)); - else - bhd = gcry_malloc (n + sizeof (struct gcry_md_context)); - - if (! bhd) - err = gpg_err_code_from_errno (errno); - - if (! err) - { - bhd->ctx = b = (struct gcry_md_context *) ((char *) bhd + n); - /* No need to copy the buffer due to the write above. */ - gcry_assert (ahd->bufsize == (n - sizeof (struct gcry_md_handle) + 1)); - bhd->bufsize = ahd->bufsize; - bhd->bufpos = 0; - gcry_assert (! ahd->bufpos); - memcpy (b, a, sizeof *a); - b->list = NULL; - b->debug = NULL; - if (a->macpads) - { - b->macpads = gcry_malloc_secure (2*(a->macpads_Bsize)); - if (! b->macpads) - { - err = gpg_err_code_from_errno (errno); - md_close (bhd); - } - else - memcpy (b->macpads, a->macpads, (2*(a->macpads_Bsize))); - } - } - - /* Copy the complete list of algorithms. The copied list is - reversed, but that doesn't matter. */ - if (!err) - { - for (ar = a->list; ar; ar = ar->next) - { - if (a->secure) - br = gcry_malloc_secure (sizeof *br - + ar->digest->contextsize - - sizeof(ar->context)); - else - br = gcry_malloc (sizeof *br - + ar->digest->contextsize - - sizeof (ar->context)); - if (!br) - { - err = gpg_err_code_from_errno (errno); - md_close (bhd); - break; - } - - memcpy (br, ar, (sizeof (*br) + ar->digest->contextsize - - sizeof (ar->context))); - br->next = b->list; - b->list = br; - - /* Add a reference to the module. */ - ath_mutex_lock (&digests_registered_lock); - _gcry_module_use (br->module); - ath_mutex_unlock (&digests_registered_lock); - } - } - - if (a->debug && !err) - md_start_debug (bhd, "unknown"); - - if (!err) - *b_hd = bhd; - - return err; -} - -gcry_error_t -gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd) -{ - gcry_err_code_t err; - - err = md_copy (hd, handle); - if (err) - *handle = NULL; - return gcry_error (err); -} - -/* - * Reset all contexts and discard any buffered stuff. This may be used - * instead of a md_close(); md_open(). - */ -void -gcry_md_reset (gcry_md_hd_t a) -{ - GcryDigestEntry *r; - - /* Note: We allow this even in fips non operational mode. */ - - a->bufpos = a->ctx->finalized = 0; - - for (r = a->ctx->list; r; r = r->next) - { - memset (r->context.c, 0, r->digest->contextsize); - (*r->digest->init) (&r->context.c); - } - if (a->ctx->macpads) - md_write (a, a->ctx->macpads, a->ctx->macpads_Bsize); /* inner pad */ -} - -static void -md_close (gcry_md_hd_t a) -{ - GcryDigestEntry *r, *r2; - - if (! a) - return; - if (a->ctx->debug) - md_stop_debug (a); - for (r = a->ctx->list; r; r = r2) - { - r2 = r->next; - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (r->module); - ath_mutex_unlock (&digests_registered_lock); - wipememory (r, r->actual_struct_size); - gcry_free (r); - } - - if (a->ctx->macpads) - { - wipememory (a->ctx->macpads, 2*(a->ctx->macpads_Bsize)); - gcry_free(a->ctx->macpads); - } - - wipememory (a, a->ctx->actual_handle_size); - gcry_free(a); -} - -void -gcry_md_close (gcry_md_hd_t hd) -{ - /* Note: We allow this even in fips non operational mode. */ - md_close (hd); -} - -static void -md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen) -{ - GcryDigestEntry *r; - - if (a->ctx->debug) - { - if (a->bufpos && fwrite (a->buf, a->bufpos, 1, a->ctx->debug) != 1) - BUG(); - if (inlen && fwrite (inbuf, inlen, 1, a->ctx->debug) != 1) - BUG(); - } - - for (r = a->ctx->list; r; r = r->next) - { - if (a->bufpos) - (*r->digest->write) (&r->context.c, a->buf, a->bufpos); - (*r->digest->write) (&r->context.c, inbuf, inlen); - } - a->bufpos = 0; -} - -void -gcry_md_write (gcry_md_hd_t hd, const void *inbuf, size_t inlen) -{ - md_write (hd, inbuf, inlen); -} - -static void -md_final (gcry_md_hd_t a) -{ - GcryDigestEntry *r; - - if (a->ctx->finalized) - return; - - if (a->bufpos) - md_write (a, NULL, 0); - - for (r = a->ctx->list; r; r = r->next) - (*r->digest->final) (&r->context.c); - - a->ctx->finalized = 1; - - if (a->ctx->macpads) - { - /* Finish the hmac. */ - int algo = md_get_algo (a); - byte *p = md_read (a, algo); - size_t dlen = md_digest_length (algo); - gcry_md_hd_t om; - gcry_err_code_t err = md_open (&om, algo, a->ctx->secure, 0); - - if (err) - _gcry_fatal_error (err, NULL); - md_write (om, - (a->ctx->macpads)+(a->ctx->macpads_Bsize), - a->ctx->macpads_Bsize); - md_write (om, p, dlen); - md_final (om); - /* Replace our digest with the mac (they have the same size). */ - memcpy (p, md_read (om, algo), dlen); - md_close (om); - } -} - -static gcry_err_code_t -prepare_macpads (gcry_md_hd_t hd, const unsigned char *key, size_t keylen) -{ - int i; - int algo = md_get_algo (hd); - unsigned char *helpkey = NULL; - unsigned char *ipad, *opad; - - if (!algo) - return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */ - - if ( keylen > hd->ctx->macpads_Bsize ) - { - helpkey = gcry_malloc_secure (md_digest_length (algo)); - if (!helpkey) - return gpg_err_code_from_errno (errno); - gcry_md_hash_buffer (algo, helpkey, key, keylen); - key = helpkey; - keylen = md_digest_length (algo); - gcry_assert ( keylen <= hd->ctx->macpads_Bsize ); - } - - memset ( hd->ctx->macpads, 0, 2*(hd->ctx->macpads_Bsize) ); - ipad = hd->ctx->macpads; - opad = (hd->ctx->macpads)+(hd->ctx->macpads_Bsize); - memcpy ( ipad, key, keylen ); - memcpy ( opad, key, keylen ); - for (i=0; i < hd->ctx->macpads_Bsize; i++ ) - { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - gcry_free (helpkey); - - return GPG_ERR_NO_ERROR; -} - -gcry_error_t -gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) -{ - gcry_err_code_t rc = 0; - - switch (cmd) - { - case GCRYCTL_FINALIZE: - md_final (hd); - break; - case GCRYCTL_SET_KEY: - rc = gcry_err_code (gcry_md_setkey (hd, buffer, buflen)); - break; - case GCRYCTL_START_DUMP: - md_start_debug (hd, buffer); - break; - case GCRYCTL_STOP_DUMP: - md_stop_debug ( hd ); - break; - default: - rc = GPG_ERR_INV_OP; - } - return gcry_error (rc); -} - -gcry_error_t -gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen) -{ - gcry_err_code_t rc = GPG_ERR_NO_ERROR; - - if (!hd->ctx->macpads) - rc = GPG_ERR_CONFLICT; - else - { - rc = prepare_macpads (hd, key, keylen); - if (! rc) - gcry_md_reset (hd); - } - - return gcry_error (rc); -} - -/* The new debug interface. If SUFFIX is a string it creates an debug - file for the context HD. IF suffix is NULL, the file is closed and - debugging is stopped. */ -void -gcry_md_debug (gcry_md_hd_t hd, const char *suffix) -{ - if (suffix) - md_start_debug (hd, suffix); - else - md_stop_debug (hd); -} - - - -/**************** - * if ALGO is null get the digest for the used algo (which should be only one) - */ -static byte * -md_read( gcry_md_hd_t a, int algo ) -{ - GcryDigestEntry *r = a->ctx->list; - - if (! algo) - { - /* Return the first algorithm. */ - if (r) - { - if (r->next) - log_debug ("more than one algorithm in md_read(0)\n"); - return r->digest->read( &r->context.c ); - } - } - else - { - for (r = a->ctx->list; r; r = r->next) - if (r->module->mod_id == algo) - return r->digest->read (&r->context.c); - } - BUG(); - return NULL; -} - -/* - * Read out the complete digest, this function implictly finalizes - * the hash. - */ -byte * -gcry_md_read (gcry_md_hd_t hd, int algo) -{ - /* This function is expected to always return a digest, thus we - can't return an error which we actually should do in - non-operational state. */ - gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); - return md_read (hd, algo); -} - - -/* - * Read out an intermediate digest. Not yet functional. - */ -gcry_err_code_t -gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen) -{ - (void)hd; - (void)algo; - (void)buffer; - (void)buflen; - - /*md_digest ... */ - fips_signal_error ("unimplemented function called"); - return GPG_ERR_INTERNAL; -} - - -/* - * Shortcut function to hash a buffer with a given algo. The only - * guaranteed supported algorithms are RIPE-MD160 and SHA-1. The - * supplied digest buffer must be large enough to store the resulting - * hash. No error is returned, the function will abort on an invalid - * algo. DISABLED_ALGOS are ignored here. */ -void -gcry_md_hash_buffer (int algo, void *digest, - const void *buffer, size_t length) -{ - if (algo == GCRY_MD_SHA1) - _gcry_sha1_hash_buffer (digest, buffer, length); - else if (algo == GCRY_MD_RMD160 && !fips_mode () ) - _gcry_rmd160_hash_buffer (digest, buffer, length); - else - { - /* For the others we do not have a fast function, so we use the - normal functions. */ - gcry_md_hd_t h; - gpg_err_code_t err; - - if (algo == GCRY_MD_MD5 && fips_mode ()) - { - _gcry_inactivate_fips_mode ("MD5 used"); - if (_gcry_enforced_fips_mode () ) - { - /* We should never get to here because we do not register - MD5 in enforced fips mode. */ - _gcry_fips_noreturn (); - } - } - - err = md_open (&h, algo, 0, 0); - if (err) - log_bug ("gcry_md_open failed for algo %d: %s", - algo, gpg_strerror (gcry_error(err))); - md_write (h, (byte *) buffer, length); - md_final (h); - memcpy (digest, md_read (h, algo), md_digest_length (algo)); - md_close (h); - } -} - -static int -md_get_algo (gcry_md_hd_t a) -{ - GcryDigestEntry *r = a->ctx->list; - - if (r && r->next) - { - fips_signal_error ("possible usage error"); - log_error ("WARNING: more than one algorithm in md_get_algo()\n"); - } - return r ? r->module->mod_id : 0; -} - -int -gcry_md_get_algo (gcry_md_hd_t hd) -{ - return md_get_algo (hd); -} - - -/**************** - * Return the length of the digest - */ -static int -md_digest_length (int algorithm) -{ - gcry_module_t digest; - int mdlen = 0; - - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - { - mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen; - _gcry_module_release (digest); - } - ath_mutex_unlock (&digests_registered_lock); - - return mdlen; -} - -/**************** - * Return the length of the digest in bytes. - * This function will return 0 in case of errors. - */ -unsigned int -gcry_md_get_algo_dlen (int algorithm) -{ - return md_digest_length (algorithm); -} - - -/* Hmmm: add a mode to enumerate the OIDs - * to make g10/sig-check.c more portable */ -static const byte * -md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen) -{ - const byte *asnoid = NULL; - gcry_module_t digest; - - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - { - if (asnlen) - *asnlen = ((gcry_md_spec_t *) digest->spec)->asnlen; - if (mdlen) - *mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen; - asnoid = ((gcry_md_spec_t *) digest->spec)->asnoid; - _gcry_module_release (digest); - } - else - log_bug ("no ASN.1 OID for md algo %d\n", algorithm); - ath_mutex_unlock (&digests_registered_lock); - - return asnoid; -} - - - -/**************** - * Return information about the given cipher algorithm - * WHAT select the kind of information returned: - * GCRYCTL_TEST_ALGO: - * Returns 0 when the specified algorithm is available for use. - * buffer and nbytes must be zero. - * GCRYCTL_GET_ASNOID: - * Return the ASNOID of the algorithm in buffer. if buffer is NULL, only - * the required length is returned. - * - * Note: Because this function is in most cases used to return an - * integer value, we can make it easier for the caller to just look at - * the return value. The caller will in all cases consult the value - * and thereby detecting whether a error occured or not (i.e. while checking - * the block size) - */ -gcry_error_t -gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - switch (what) - { - case GCRYCTL_TEST_ALGO: - if (buffer || nbytes) - err = GPG_ERR_INV_ARG; - else - err = check_digest_algo (algo); - break; - - case GCRYCTL_GET_ASNOID: - /* We need to check that the algo is available because - md_asn_oid would otherwise raise an assertion. */ - err = check_digest_algo (algo); - if (!err) - { - const char unsigned *asn; - size_t asnlen; - - asn = md_asn_oid (algo, &asnlen, NULL); - if (buffer && (*nbytes >= asnlen)) - { - memcpy (buffer, asn, asnlen); - *nbytes = asnlen; - } - else if (!buffer && nbytes) - *nbytes = asnlen; - else - { - if (buffer) - err = GPG_ERR_TOO_SHORT; - else - err = GPG_ERR_INV_ARG; - } - } - break; - - default: - err = GPG_ERR_INV_OP; - } - - return gcry_error (err); -} - - -static void -md_start_debug ( gcry_md_hd_t md, const char *suffix ) -{ - static int idx=0; - char buf[50]; - - if (fips_mode ()) - return; - - if ( md->ctx->debug ) - { - log_debug("Oops: md debug already started\n"); - return; - } - idx++; - snprintf (buf, DIM(buf)-1, "dbgmd-%05d.%.10s", idx, suffix ); - md->ctx->debug = fopen(buf, "w"); - if ( !md->ctx->debug ) - log_debug("md debug: can't open %s\n", buf ); -} - -static void -md_stop_debug( gcry_md_hd_t md ) -{ - if ( md->ctx->debug ) - { - if ( md->bufpos ) - md_write ( md, NULL, 0 ); - fclose (md->ctx->debug); - md->ctx->debug = NULL; - } - -#ifdef HAVE_U64_TYPEDEF - { /* a kludge to pull in the __muldi3 for Solaris */ - volatile u32 a = (u32)(ulong)md; - volatile u64 b = 42; - volatile u64 c; - c = a * b; - } -#endif -} - - - -/* - * Return information about the digest handle. - * GCRYCTL_IS_SECURE: - * Returns 1 when the handle works on secured memory - * otherwise 0 is returned. There is no error return. - * GCRYCTL_IS_ALGO_ENABLED: - * Returns 1 if the algo is enabled for that handle. - * The algo must be passed as the address of an int. - */ -gcry_error_t -gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - switch (cmd) - { - case GCRYCTL_IS_SECURE: - *nbytes = h->ctx->secure; - break; - - case GCRYCTL_IS_ALGO_ENABLED: - { - GcryDigestEntry *r; - int algo; - - if ( !buffer || (nbytes && (*nbytes != sizeof (int)))) - err = GPG_ERR_INV_ARG; - else - { - algo = *(int*)buffer; - - *nbytes = 0; - for(r=h->ctx->list; r; r = r->next ) { - if (r->module->mod_id == algo) - { - *nbytes = 1; - break; - } - } - } - break; - } - - default: - err = GPG_ERR_INV_OP; - } - - return gcry_error (err); -} - - -/* Explicitly initialize this module. */ -gcry_err_code_t -_gcry_md_init (void) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - REGISTER_DEFAULT_DIGESTS; - - return err; -} - - -int -gcry_md_is_secure (gcry_md_hd_t a) -{ - size_t value; - - if (gcry_md_info (a, GCRYCTL_IS_SECURE, NULL, &value)) - value = 1; /* It seems to be better to assume secure memory on - error. */ - return value; -} - - -int -gcry_md_is_enabled (gcry_md_hd_t a, int algo) -{ - size_t value; - - value = sizeof algo; - if (gcry_md_info (a, GCRYCTL_IS_ALGO_ENABLED, &algo, &value)) - value = 0; - return value; -} - -/* Get a list consisting of the IDs of the loaded message digest - modules. If LIST is zero, write the number of loaded message - digest modules to LIST_LENGTH and return. If LIST is non-zero, the - first *LIST_LENGTH algorithm IDs are stored in LIST, which must be - of according size. In case there are less message digest modules - than *LIST_LENGTH, *LIST_LENGTH is updated to the correct - number. */ -gcry_error_t -gcry_md_list (int *list, int *list_length) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - ath_mutex_lock (&digests_registered_lock); - err = _gcry_module_list (digests_registered, list, list_length); - ath_mutex_unlock (&digests_registered_lock); - - return err; -} - - -/* Run the selftests for digest algorithm ALGO with optional reporting - function REPORT. */ -gpg_error_t -_gcry_md_selftest (int algo, int extended, selftest_report_func_t report) -{ - gcry_module_t module = NULL; - cipher_extra_spec_t *extraspec = NULL; - gcry_err_code_t ec = 0; - - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - module = _gcry_module_lookup_id (digests_registered, algo); - if (module && !(module->flags & FLAG_MODULE_DISABLED)) - extraspec = module->extraspec; - ath_mutex_unlock (&digests_registered_lock); - if (extraspec && extraspec->selftest) - ec = extraspec->selftest (algo, extended, report); - else - { - ec = GPG_ERR_DIGEST_ALGO; - if (report) - report ("digest", algo, "module", - module && !(module->flags & FLAG_MODULE_DISABLED)? - "no selftest available" : - module? "algorithm disabled" : "algorithm not found"); - } - - if (module) - { - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&digests_registered_lock); - } - return gpg_error (ec); -} +/* md.c - message digest dispatcher + * Copyright (C) 1998, 1999, 2002, 2003, 2006, + * 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" + +#include "rmd.h" + +/* A dummy extraspec so that we do not need to tests the extraspec + field from the module specification against NULL and instead + directly test the respective fields of extraspecs. */ +static md_extra_spec_t dummy_extra_spec; + + +/* This is the list of the digest implementations included in + libgcrypt. */ +static struct digest_table_entry +{ + gcry_md_spec_t *digest; + md_extra_spec_t *extraspec; + unsigned int algorithm; + int fips_allowed; +} digest_table[] = + { +#if USE_CRC + /* We allow the CRC algorithms even in FIPS mode because they are + actually no cryptographic primitives. */ + { &_gcry_digest_spec_crc32, + &dummy_extra_spec, GCRY_MD_CRC32, 1 }, + { &_gcry_digest_spec_crc32_rfc1510, + &dummy_extra_spec, GCRY_MD_CRC32_RFC1510, 1 }, + { &_gcry_digest_spec_crc24_rfc2440, + &dummy_extra_spec, GCRY_MD_CRC24_RFC2440, 1 }, +#endif +#if USE_MD4 + { &_gcry_digest_spec_md4, + &dummy_extra_spec, GCRY_MD_MD4 }, +#endif +#if USE_MD5 + { &_gcry_digest_spec_md5, + &dummy_extra_spec, GCRY_MD_MD5, 1 }, +#endif +#if USE_RMD160 + { &_gcry_digest_spec_rmd160, + &dummy_extra_spec, GCRY_MD_RMD160 }, +#endif +#if USE_SHA1 + { &_gcry_digest_spec_sha1, + &_gcry_digest_extraspec_sha1, GCRY_MD_SHA1, 1 }, +#endif +#if USE_SHA256 + { &_gcry_digest_spec_sha256, + &_gcry_digest_extraspec_sha256, GCRY_MD_SHA256, 1 }, + { &_gcry_digest_spec_sha224, + &_gcry_digest_extraspec_sha224, GCRY_MD_SHA224, 1 }, +#endif +#if USE_SHA512 + { &_gcry_digest_spec_sha512, + &_gcry_digest_extraspec_sha512, GCRY_MD_SHA512, 1 }, + { &_gcry_digest_spec_sha384, + &_gcry_digest_extraspec_sha384, GCRY_MD_SHA384, 1 }, +#endif +#if USE_TIGER + { &_gcry_digest_spec_tiger, + &dummy_extra_spec, GCRY_MD_TIGER }, + { &_gcry_digest_spec_tiger1, + &dummy_extra_spec, GCRY_MD_TIGER1 }, + { &_gcry_digest_spec_tiger2, + &dummy_extra_spec, GCRY_MD_TIGER2 }, +#endif +#if USE_WHIRLPOOL + { &_gcry_digest_spec_whirlpool, + &dummy_extra_spec, GCRY_MD_WHIRLPOOL }, +#endif + { NULL }, + }; + +/* List of registered digests. */ +static gcry_module_t digests_registered; + +/* This is the lock protecting DIGESTS_REGISTERED. */ +static ath_mutex_t digests_registered_lock = ATH_MUTEX_INITIALIZER; + +/* Flag to check whether the default ciphers have already been + registered. */ +static int default_digests_registered; + +typedef struct gcry_md_list +{ + gcry_md_spec_t *digest; + gcry_module_t module; + struct gcry_md_list *next; + size_t actual_struct_size; /* Allocated size of this structure. */ + PROPERLY_ALIGNED_TYPE context; +} GcryDigestEntry; + +/* this structure is put right after the gcry_md_hd_t buffer, so that + * only one memory block is needed. */ +struct gcry_md_context +{ + int magic; + size_t actual_handle_size; /* Allocated size of this handle. */ + int secure; + FILE *debug; + int finalized; + GcryDigestEntry *list; + byte *macpads; + int macpads_Bsize; /* Blocksize as used for the HMAC pads. */ +}; + + +#define CTX_MAGIC_NORMAL 0x11071961 +#define CTX_MAGIC_SECURE 0x16917011 + +/* Convenient macro for registering the default digests. */ +#define REGISTER_DEFAULT_DIGESTS \ + do \ + { \ + ath_mutex_lock (&digests_registered_lock); \ + if (! default_digests_registered) \ + { \ + md_register_default (); \ + default_digests_registered = 1; \ + } \ + ath_mutex_unlock (&digests_registered_lock); \ + } \ + while (0) + + +static const char * digest_algo_to_string( int algo ); +static gcry_err_code_t check_digest_algo (int algo); +static gcry_err_code_t md_open (gcry_md_hd_t *h, int algo, + int secure, int hmac); +static gcry_err_code_t md_enable (gcry_md_hd_t hd, int algo); +static gcry_err_code_t md_copy (gcry_md_hd_t a, gcry_md_hd_t *b); +static void md_close (gcry_md_hd_t a); +static void md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen); +static void md_final(gcry_md_hd_t a); +static byte *md_read( gcry_md_hd_t a, int algo ); +static int md_get_algo( gcry_md_hd_t a ); +static int md_digest_length( int algo ); +static const byte *md_asn_oid( int algo, size_t *asnlen, size_t *mdlen ); +static void md_start_debug ( gcry_md_hd_t a, const char *suffix ); +static void md_stop_debug ( gcry_md_hd_t a ); + + + + +/* Internal function. Register all the ciphers included in + CIPHER_TABLE. Returns zero on success or an error code. */ +static void +md_register_default (void) +{ + gcry_err_code_t err = 0; + int i; + + for (i = 0; !err && digest_table[i].digest; i++) + { + if ( fips_mode ()) + { + if (!digest_table[i].fips_allowed) + continue; + if (digest_table[i].algorithm == GCRY_MD_MD5 + && _gcry_enforced_fips_mode () ) + continue; /* Do not register in enforced fips mode. */ + } + + err = _gcry_module_add (&digests_registered, + digest_table[i].algorithm, + (void *) digest_table[i].digest, + (void *) digest_table[i].extraspec, + NULL); + } + + if (err) + BUG (); +} + +/* Internal callback function. */ +static int +gcry_md_lookup_func_name (void *spec, void *data) +{ + gcry_md_spec_t *digest = (gcry_md_spec_t *) spec; + char *name = (char *) data; + + return (! _stricmp (digest->name, name)); +} + +/* Internal callback function. Used via _gcry_module_lookup. */ +static int +gcry_md_lookup_func_oid (void *spec, void *data) +{ + gcry_md_spec_t *digest = (gcry_md_spec_t *) spec; + char *oid = (char *) data; + gcry_md_oid_spec_t *oid_specs = digest->oids; + int ret = 0, i; + + if (oid_specs) + { + for (i = 0; oid_specs[i].oidstring && (! ret); i++) + if (! _stricmp (oid, oid_specs[i].oidstring)) + ret = 1; + } + + return ret; +} + +/* Internal function. Lookup a digest entry by it's name. */ +static gcry_module_t +gcry_md_lookup_name (const char *name) +{ + gcry_module_t digest; + + digest = _gcry_module_lookup (digests_registered, (void *) name, + gcry_md_lookup_func_name); + + return digest; +} + +/* Internal function. Lookup a cipher entry by it's oid. */ +static gcry_module_t +gcry_md_lookup_oid (const char *oid) +{ + gcry_module_t digest; + + digest = _gcry_module_lookup (digests_registered, (void *) oid, + gcry_md_lookup_func_oid); + + return digest; +} + +/* Register a new digest module whose specification can be found in + DIGEST. On success, a new algorithm ID is stored in ALGORITHM_ID + and a pointer representhing this module is stored in MODULE. */ +gcry_error_t +_gcry_md_register (gcry_md_spec_t *digest, + md_extra_spec_t *extraspec, + unsigned int *algorithm_id, + gcry_module_t *module) +{ + gcry_err_code_t err = 0; + gcry_module_t mod; + + /* We do not support module loading in fips mode. */ + if (fips_mode ()) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + + ath_mutex_lock (&digests_registered_lock); + err = _gcry_module_add (&digests_registered, 0, + (void *) digest, + (void *)(extraspec? extraspec : &dummy_extra_spec), + &mod); + ath_mutex_unlock (&digests_registered_lock); + + if (! err) + { + *module = mod; + *algorithm_id = mod->mod_id; + } + + return gcry_error (err); +} + +/* Unregister the digest identified by ID, which must have been + registered with gcry_digest_register. */ +void +gcry_md_unregister (gcry_module_t module) +{ + ath_mutex_lock (&digests_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&digests_registered_lock); +} + + +static int +search_oid (const char *oid, int *algorithm, gcry_md_oid_spec_t *oid_spec) +{ + gcry_module_t module; + int ret = 0; + + if (oid && ((! strncmp (oid, "oid.", 4)) + || (! strncmp (oid, "OID.", 4)))) + oid += 4; + + module = gcry_md_lookup_oid (oid); + if (module) + { + gcry_md_spec_t *digest = module->spec; + int i; + + for (i = 0; digest->oids[i].oidstring && !ret; i++) + if (! _stricmp (oid, digest->oids[i].oidstring)) + { + if (algorithm) + *algorithm = module->mod_id; + if (oid_spec) + *oid_spec = digest->oids[i]; + ret = 1; + } + _gcry_module_release (module); + } + + return ret; +} + +/**************** + * Map a string to the digest algo + */ +int +gcry_md_map_name (const char *string) +{ + gcry_module_t digest; + int ret, algorithm = 0; + + if (! string) + return 0; + + REGISTER_DEFAULT_DIGESTS; + + /* If the string starts with a digit (optionally prefixed with + either "OID." or "oid."), we first look into our table of ASN.1 + object identifiers to figure out the algorithm */ + + ath_mutex_lock (&digests_registered_lock); + + ret = search_oid (string, &algorithm, NULL); + if (! ret) + { + /* Not found, search a matching digest name. */ + digest = gcry_md_lookup_name (string); + if (digest) + { + algorithm = digest->mod_id; + _gcry_module_release (digest); + } + } + ath_mutex_unlock (&digests_registered_lock); + + return algorithm; +} + + +/**************** + * Map a digest algo to a string + */ +static const char * +digest_algo_to_string (int algorithm) +{ + const char *name = NULL; + gcry_module_t digest; + + REGISTER_DEFAULT_DIGESTS; + + ath_mutex_lock (&digests_registered_lock); + digest = _gcry_module_lookup_id (digests_registered, algorithm); + if (digest) + { + name = ((gcry_md_spec_t *) digest->spec)->name; + _gcry_module_release (digest); + } + ath_mutex_unlock (&digests_registered_lock); + + return name; +} + +/**************** + * This function simply returns the name of the algorithm or some constant + * string when there is no algo. It will never return NULL. + * Use the macro gcry_md_test_algo() to check whether the algorithm + * is valid. + */ +const char * +gcry_md_algo_name (int algorithm) +{ + const char *s = digest_algo_to_string (algorithm); + return s ? s : "?"; +} + + +static gcry_err_code_t +check_digest_algo (int algorithm) +{ + gcry_err_code_t rc = 0; + gcry_module_t digest; + + REGISTER_DEFAULT_DIGESTS; + + ath_mutex_lock (&digests_registered_lock); + digest = _gcry_module_lookup_id (digests_registered, algorithm); + if (digest) + _gcry_module_release (digest); + else + rc = GPG_ERR_DIGEST_ALGO; + ath_mutex_unlock (&digests_registered_lock); + + return rc; +} + + + +/**************** + * Open a message digest handle for use with algorithm ALGO. + * More algorithms may be added by md_enable(). The initial algorithm + * may be 0. + */ +static gcry_err_code_t +md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + int bufsize = secure ? 512 : 1024; + struct gcry_md_context *ctx; + gcry_md_hd_t hd; + size_t n; + + /* Allocate a memory area to hold the caller visible buffer with it's + * control information and the data required by this module. Set the + * context pointer at the beginning to this area. + * We have to use this strange scheme because we want to hide the + * internal data but have a variable sized buffer. + * + * +---+------+---........------+-------------+ + * !ctx! bctl ! buffer ! private ! + * +---+------+---........------+-------------+ + * ! ^ + * !---------------------------! + * + * We have to make sure that private is well aligned. + */ + n = sizeof (struct gcry_md_handle) + bufsize; + n = ((n + sizeof (PROPERLY_ALIGNED_TYPE) - 1) + / sizeof (PROPERLY_ALIGNED_TYPE)) * sizeof (PROPERLY_ALIGNED_TYPE); + + /* Allocate and set the Context pointer to the private data */ + if (secure) + hd = gcry_malloc_secure (n + sizeof (struct gcry_md_context)); + else + hd = gcry_malloc (n + sizeof (struct gcry_md_context)); + + if (! hd) + err = gpg_err_code_from_errno (errno); + + if (! err) + { + hd->ctx = ctx = (struct gcry_md_context *) ((char *) hd + n); + /* Setup the globally visible data (bctl in the diagram).*/ + hd->bufsize = n - sizeof (struct gcry_md_handle) + 1; + hd->bufpos = 0; + + /* Initialize the private data. */ + memset (hd->ctx, 0, sizeof *hd->ctx); + ctx->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; + ctx->actual_handle_size = n + sizeof (struct gcry_md_context); + ctx->secure = secure; + + if (hmac) + { + switch (algo) + { + case GCRY_MD_SHA384: + case GCRY_MD_SHA512: + ctx->macpads_Bsize = 128; + break; + default: + ctx->macpads_Bsize = 64; + break; + } + ctx->macpads = gcry_malloc_secure (2*(ctx->macpads_Bsize)); + if (!ctx->macpads) + { + err = gpg_err_code_from_errno (errno); + md_close (hd); + } + } + } + + if (! err) + { + /* Hmmm, should we really do that? - yes [-wk] */ + _gcry_fast_random_poll (); + + if (algo) + { + err = md_enable (hd, algo); + if (err) + md_close (hd); + } + } + + if (! err) + *h = hd; + + return err; +} + +/* Create a message digest object for algorithm ALGO. FLAGS may be + given as an bitwise OR of the gcry_md_flags values. ALGO may be + given as 0 if the algorithms to be used are later set using + gcry_md_enable. H is guaranteed to be a valid handle or NULL on + error. */ +gcry_error_t +gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_md_hd_t hd; + + if ((flags & ~(GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC))) + err = GPG_ERR_INV_ARG; + else + { + err = md_open (&hd, algo, (flags & GCRY_MD_FLAG_SECURE), + (flags & GCRY_MD_FLAG_HMAC)); + } + + *h = err? NULL : hd; + return gcry_error (err); +} + + + +static gcry_err_code_t +md_enable (gcry_md_hd_t hd, int algorithm) +{ + struct gcry_md_context *h = hd->ctx; + gcry_md_spec_t *digest = NULL; + GcryDigestEntry *entry; + gcry_module_t module; + gcry_err_code_t err = 0; + + for (entry = h->list; entry; entry = entry->next) + if (entry->module->mod_id == algorithm) + return err; /* already enabled */ + + REGISTER_DEFAULT_DIGESTS; + + ath_mutex_lock (&digests_registered_lock); + module = _gcry_module_lookup_id (digests_registered, algorithm); + ath_mutex_unlock (&digests_registered_lock); + if (! module) + { + log_debug ("md_enable: algorithm %d not available\n", algorithm); + err = GPG_ERR_DIGEST_ALGO; + } + else + digest = (gcry_md_spec_t *) module->spec; + + + if (!err && algorithm == GCRY_MD_MD5 && fips_mode ()) + { + _gcry_inactivate_fips_mode ("MD5 used"); + if (_gcry_enforced_fips_mode () ) + { + /* We should never get to here because we do not register + MD5 in enforced fips mode. But better throw an error. */ + err = GPG_ERR_DIGEST_ALGO; + } + } + + if (!err) + { + size_t size = (sizeof (*entry) + + digest->contextsize + - sizeof (entry->context)); + + /* And allocate a new list entry. */ + if (h->secure) + entry = gcry_malloc_secure (size); + else + entry = gcry_malloc (size); + + if (! entry) + err = gpg_err_code_from_errno (errno); + else + { + entry->digest = digest; + entry->module = module; + entry->next = h->list; + entry->actual_struct_size = size; + h->list = entry; + + /* And init this instance. */ + entry->digest->init (&entry->context.c); + } + } + + if (err) + { + if (module) + { + ath_mutex_lock (&digests_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&digests_registered_lock); + } + } + + return err; +} + + +gcry_error_t +gcry_md_enable (gcry_md_hd_t hd, int algorithm) +{ + return gcry_error (md_enable (hd, algorithm)); +} + +static gcry_err_code_t +md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + struct gcry_md_context *a = ahd->ctx; + struct gcry_md_context *b; + GcryDigestEntry *ar, *br; + gcry_md_hd_t bhd; + size_t n; + + if (ahd->bufpos) + md_write (ahd, NULL, 0); + + n = (char *) ahd->ctx - (char *) ahd; + if (a->secure) + bhd = gcry_malloc_secure (n + sizeof (struct gcry_md_context)); + else + bhd = gcry_malloc (n + sizeof (struct gcry_md_context)); + + if (! bhd) + err = gpg_err_code_from_errno (errno); + + if (! err) + { + bhd->ctx = b = (struct gcry_md_context *) ((char *) bhd + n); + /* No need to copy the buffer due to the write above. */ + gcry_assert (ahd->bufsize == (n - sizeof (struct gcry_md_handle) + 1)); + bhd->bufsize = ahd->bufsize; + bhd->bufpos = 0; + gcry_assert (! ahd->bufpos); + memcpy (b, a, sizeof *a); + b->list = NULL; + b->debug = NULL; + if (a->macpads) + { + b->macpads = gcry_malloc_secure (2*(a->macpads_Bsize)); + if (! b->macpads) + { + err = gpg_err_code_from_errno (errno); + md_close (bhd); + } + else + memcpy (b->macpads, a->macpads, (2*(a->macpads_Bsize))); + } + } + + /* Copy the complete list of algorithms. The copied list is + reversed, but that doesn't matter. */ + if (!err) + { + for (ar = a->list; ar; ar = ar->next) + { + if (a->secure) + br = gcry_malloc_secure (sizeof *br + + ar->digest->contextsize + - sizeof(ar->context)); + else + br = gcry_malloc (sizeof *br + + ar->digest->contextsize + - sizeof (ar->context)); + if (!br) + { + err = gpg_err_code_from_errno (errno); + md_close (bhd); + break; + } + + memcpy (br, ar, (sizeof (*br) + ar->digest->contextsize + - sizeof (ar->context))); + br->next = b->list; + b->list = br; + + /* Add a reference to the module. */ + ath_mutex_lock (&digests_registered_lock); + _gcry_module_use (br->module); + ath_mutex_unlock (&digests_registered_lock); + } + } + + if (a->debug && !err) + md_start_debug (bhd, "unknown"); + + if (!err) + *b_hd = bhd; + + return err; +} + +gcry_error_t +gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd) +{ + gcry_err_code_t err; + + err = md_copy (hd, handle); + if (err) + *handle = NULL; + return gcry_error (err); +} + +/* + * Reset all contexts and discard any buffered stuff. This may be used + * instead of a md_close(); md_open(). + */ +void +gcry_md_reset (gcry_md_hd_t a) +{ + GcryDigestEntry *r; + + /* Note: We allow this even in fips non operational mode. */ + + a->bufpos = a->ctx->finalized = 0; + + for (r = a->ctx->list; r; r = r->next) + { + memset (r->context.c, 0, r->digest->contextsize); + (*r->digest->init) (&r->context.c); + } + if (a->ctx->macpads) + md_write (a, a->ctx->macpads, a->ctx->macpads_Bsize); /* inner pad */ +} + +static void +md_close (gcry_md_hd_t a) +{ + GcryDigestEntry *r, *r2; + + if (! a) + return; + if (a->ctx->debug) + md_stop_debug (a); + for (r = a->ctx->list; r; r = r2) + { + r2 = r->next; + ath_mutex_lock (&digests_registered_lock); + _gcry_module_release (r->module); + ath_mutex_unlock (&digests_registered_lock); + wipememory (r, r->actual_struct_size); + gcry_free (r); + } + + if (a->ctx->macpads) + { + wipememory (a->ctx->macpads, 2*(a->ctx->macpads_Bsize)); + gcry_free(a->ctx->macpads); + } + + wipememory (a, a->ctx->actual_handle_size); + gcry_free(a); +} + +void +gcry_md_close (gcry_md_hd_t hd) +{ + /* Note: We allow this even in fips non operational mode. */ + md_close (hd); +} + +static void +md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen) +{ + GcryDigestEntry *r; + + if (a->ctx->debug) + { + if (a->bufpos && fwrite (a->buf, a->bufpos, 1, a->ctx->debug) != 1) + BUG(); + if (inlen && fwrite (inbuf, inlen, 1, a->ctx->debug) != 1) + BUG(); + } + + for (r = a->ctx->list; r; r = r->next) + { + if (a->bufpos) + (*r->digest->write) (&r->context.c, a->buf, a->bufpos); + (*r->digest->write) (&r->context.c, inbuf, inlen); + } + a->bufpos = 0; +} + +void +gcry_md_write (gcry_md_hd_t hd, const void *inbuf, size_t inlen) +{ + md_write (hd, inbuf, inlen); +} + +static void +md_final (gcry_md_hd_t a) +{ + GcryDigestEntry *r; + + if (a->ctx->finalized) + return; + + if (a->bufpos) + md_write (a, NULL, 0); + + for (r = a->ctx->list; r; r = r->next) + (*r->digest->final) (&r->context.c); + + a->ctx->finalized = 1; + + if (a->ctx->macpads) + { + /* Finish the hmac. */ + int algo = md_get_algo (a); + byte *p = md_read (a, algo); + size_t dlen = md_digest_length (algo); + gcry_md_hd_t om; + gcry_err_code_t err = md_open (&om, algo, a->ctx->secure, 0); + + if (err) + _gcry_fatal_error (err, NULL); + md_write (om, + (a->ctx->macpads)+(a->ctx->macpads_Bsize), + a->ctx->macpads_Bsize); + md_write (om, p, dlen); + md_final (om); + /* Replace our digest with the mac (they have the same size). */ + memcpy (p, md_read (om, algo), dlen); + md_close (om); + } +} + +static gcry_err_code_t +prepare_macpads (gcry_md_hd_t hd, const unsigned char *key, size_t keylen) +{ + int i; + int algo = md_get_algo (hd); + unsigned char *helpkey = NULL; + unsigned char *ipad, *opad; + + if (!algo) + return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */ + + if ( keylen > hd->ctx->macpads_Bsize ) + { + helpkey = gcry_malloc_secure (md_digest_length (algo)); + if (!helpkey) + return gpg_err_code_from_errno (errno); + gcry_md_hash_buffer (algo, helpkey, key, keylen); + key = helpkey; + keylen = md_digest_length (algo); + gcry_assert ( keylen <= hd->ctx->macpads_Bsize ); + } + + memset ( hd->ctx->macpads, 0, 2*(hd->ctx->macpads_Bsize) ); + ipad = hd->ctx->macpads; + opad = (hd->ctx->macpads)+(hd->ctx->macpads_Bsize); + memcpy ( ipad, key, keylen ); + memcpy ( opad, key, keylen ); + for (i=0; i < hd->ctx->macpads_Bsize; i++ ) + { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + gcry_free (helpkey); + + return GPG_ERR_NO_ERROR; +} + +gcry_error_t +gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) +{ + gcry_err_code_t rc = 0; + + switch (cmd) + { + case GCRYCTL_FINALIZE: + md_final (hd); + break; + case GCRYCTL_SET_KEY: + rc = gcry_err_code (gcry_md_setkey (hd, buffer, buflen)); + break; + case GCRYCTL_START_DUMP: + md_start_debug (hd, buffer); + break; + case GCRYCTL_STOP_DUMP: + md_stop_debug ( hd ); + break; + default: + rc = GPG_ERR_INV_OP; + } + return gcry_error (rc); +} + +gcry_error_t +gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen) +{ + gcry_err_code_t rc = GPG_ERR_NO_ERROR; + + if (!hd->ctx->macpads) + rc = GPG_ERR_CONFLICT; + else + { + rc = prepare_macpads (hd, key, keylen); + if (! rc) + gcry_md_reset (hd); + } + + return gcry_error (rc); +} + +/* The new debug interface. If SUFFIX is a string it creates an debug + file for the context HD. IF suffix is NULL, the file is closed and + debugging is stopped. */ +void +gcry_md_debug (gcry_md_hd_t hd, const char *suffix) +{ + if (suffix) + md_start_debug (hd, suffix); + else + md_stop_debug (hd); +} + + + +/**************** + * if ALGO is null get the digest for the used algo (which should be only one) + */ +static byte * +md_read( gcry_md_hd_t a, int algo ) +{ + GcryDigestEntry *r = a->ctx->list; + + if (! algo) + { + /* Return the first algorithm */ + if (r) + { + if (r->next) + log_debug ("more than one algorithm in md_read(0)\n"); + return r->digest->read (&r->context.c); + } + } + else + { + for (r = a->ctx->list; r; r = r->next) + if (r->module->mod_id == algo) + return r->digest->read (&r->context.c); + } + BUG(); + return NULL; +} + +/* + * Read out the complete digest, this function implictly finalizes + * the hash. + */ +byte * +gcry_md_read (gcry_md_hd_t hd, int algo) +{ + /* This function is expected to always return a digest, thus we + can't return an error which we actually should do in + non-operational state. */ + gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); + return md_read (hd, algo); +} + + +/* + * Read out an intermediate digest. Not yet functional. + */ +gcry_err_code_t +gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen) +{ + (void)hd; + (void)algo; + (void)buffer; + (void)buflen; + + /*md_digest ... */ + fips_signal_error ("unimplemented function called"); + return GPG_ERR_INTERNAL; +} + + +/* + * Shortcut function to hash a buffer with a given algo. The only + * guaranteed supported algorithms are RIPE-MD160 and SHA-1. The + * supplied digest buffer must be large enough to store the resulting + * hash. No error is returned, the function will abort on an invalid + * algo. DISABLED_ALGOS are ignored here. */ +void +gcry_md_hash_buffer (int algo, void *digest, + const void *buffer, size_t length) +{ + if (algo == GCRY_MD_SHA1) + _gcry_sha1_hash_buffer (digest, buffer, length); + else if (algo == GCRY_MD_RMD160 && !fips_mode () ) + _gcry_rmd160_hash_buffer (digest, buffer, length); + else + { + /* For the others we do not have a fast function, so we use the + normal functions. */ + gcry_md_hd_t h; + gpg_err_code_t err; + + if (algo == GCRY_MD_MD5 && fips_mode ()) + { + _gcry_inactivate_fips_mode ("MD5 used"); + if (_gcry_enforced_fips_mode () ) + { + /* We should never get to here because we do not register + MD5 in enforced fips mode. */ + _gcry_fips_noreturn (); + } + } + + err = md_open (&h, algo, 0, 0); + if (err) + log_bug ("gcry_md_open failed for algo %d: %s", + algo, gpg_strerror (gcry_error(err))); + md_write (h, (byte *) buffer, length); + md_final (h); + memcpy (digest, md_read (h, algo), md_digest_length (algo)); + md_close (h); + } +} + +static int +md_get_algo (gcry_md_hd_t a) +{ + GcryDigestEntry *r = a->ctx->list; + + if (r && r->next) + { + fips_signal_error ("possible usage error"); + log_error ("WARNING: more than one algorithm in md_get_algo()\n"); + } + return r ? r->module->mod_id : 0; +} + +int +gcry_md_get_algo (gcry_md_hd_t hd) +{ + return md_get_algo (hd); +} + + +/**************** + * Return the length of the digest + */ +static int +md_digest_length (int algorithm) +{ + gcry_module_t digest; + int mdlen = 0; + + REGISTER_DEFAULT_DIGESTS; + + ath_mutex_lock (&digests_registered_lock); + digest = _gcry_module_lookup_id (digests_registered, algorithm); + if (digest) + { + mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen; + _gcry_module_release (digest); + } + ath_mutex_unlock (&digests_registered_lock); + + return mdlen; +} + +/**************** + * Return the length of the digest in bytes. + * This function will return 0 in case of errors. + */ +unsigned int +gcry_md_get_algo_dlen (int algorithm) +{ + return md_digest_length (algorithm); +} + + +/* Hmmm: add a mode to enumerate the OIDs + * to make g10/sig-check.c more portable */ +static const byte * +md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen) +{ + const byte *asnoid = NULL; + gcry_module_t digest; + + REGISTER_DEFAULT_DIGESTS; + + ath_mutex_lock (&digests_registered_lock); + digest = _gcry_module_lookup_id (digests_registered, algorithm); + if (digest) + { + if (asnlen) + *asnlen = ((gcry_md_spec_t *) digest->spec)->asnlen; + if (mdlen) + *mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen; + asnoid = ((gcry_md_spec_t *) digest->spec)->asnoid; + _gcry_module_release (digest); + } + else + log_bug ("no ASN.1 OID for md algo %d\n", algorithm); + ath_mutex_unlock (&digests_registered_lock); + + return asnoid; +} + + + +/**************** + * Return information about the given cipher algorithm + * WHAT select the kind of information returned: + * GCRYCTL_TEST_ALGO: + * Returns 0 when the specified algorithm is available for use. + * buffer and nbytes must be zero. + * GCRYCTL_GET_ASNOID: + * Return the ASNOID of the algorithm in buffer. if buffer is NULL, only + * the required length is returned. + * + * Note: Because this function is in most cases used to return an + * integer value, we can make it easier for the caller to just look at + * the return value. The caller will in all cases consult the value + * and thereby detecting whether a error occurred or not (i.e. while checking + * the block size) + */ +gcry_error_t +gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + switch (what) + { + case GCRYCTL_TEST_ALGO: + if (buffer || nbytes) + err = GPG_ERR_INV_ARG; + else + err = check_digest_algo (algo); + break; + + case GCRYCTL_GET_ASNOID: + /* We need to check that the algo is available because + md_asn_oid would otherwise raise an assertion. */ + err = check_digest_algo (algo); + if (!err) + { + const char unsigned *asn; + size_t asnlen; + + asn = md_asn_oid (algo, &asnlen, NULL); + if (buffer && (*nbytes >= asnlen)) + { + memcpy (buffer, asn, asnlen); + *nbytes = asnlen; + } + else if (!buffer && nbytes) + *nbytes = asnlen; + else + { + if (buffer) + err = GPG_ERR_TOO_SHORT; + else + err = GPG_ERR_INV_ARG; + } + } + break; + + default: + err = GPG_ERR_INV_OP; + } + + return gcry_error (err); +} + + +static void +md_start_debug ( gcry_md_hd_t md, const char *suffix ) +{ + static int idx=0; + char buf[50]; + + if (fips_mode ()) + return; + + if ( md->ctx->debug ) + { + log_debug("Oops: md debug already started\n"); + return; + } + idx++; + snprintf (buf, DIM(buf)-1, "dbgmd-%05d.%.10s", idx, suffix ); + md->ctx->debug = fopen(buf, "w"); + if ( !md->ctx->debug ) + log_debug("md debug: can't open %s\n", buf ); +} + +static void +md_stop_debug( gcry_md_hd_t md ) +{ + if ( md->ctx->debug ) + { + if ( md->bufpos ) + md_write ( md, NULL, 0 ); + fclose (md->ctx->debug); + md->ctx->debug = NULL; + } + +#ifdef HAVE_U64_TYPEDEF + { /* a kludge to pull in the __muldi3 for Solaris */ + volatile u32 a = (u32)(ulong)md; + volatile u64 b = 42; + volatile u64 c; + c = a * b; + } +#endif +} + + + +/* + * Return information about the digest handle. + * GCRYCTL_IS_SECURE: + * Returns 1 when the handle works on secured memory + * otherwise 0 is returned. There is no error return. + * GCRYCTL_IS_ALGO_ENABLED: + * Returns 1 if the algo is enabled for that handle. + * The algo must be passed as the address of an int. + */ +gcry_error_t +gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + switch (cmd) + { + case GCRYCTL_IS_SECURE: + *nbytes = h->ctx->secure; + break; + + case GCRYCTL_IS_ALGO_ENABLED: + { + GcryDigestEntry *r; + int algo; + + if ( !buffer || (nbytes && (*nbytes != sizeof (int)))) + err = GPG_ERR_INV_ARG; + else + { + algo = *(int*)buffer; + + *nbytes = 0; + for(r=h->ctx->list; r; r = r->next ) { + if (r->module->mod_id == algo) + { + *nbytes = 1; + break; + } + } + } + break; + } + + default: + err = GPG_ERR_INV_OP; + } + + return gcry_error (err); +} + + +/* Explicitly initialize this module. */ +gcry_err_code_t +_gcry_md_init (void) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + REGISTER_DEFAULT_DIGESTS; + + return err; +} + + +int +gcry_md_is_secure (gcry_md_hd_t a) +{ + size_t value; + + if (gcry_md_info (a, GCRYCTL_IS_SECURE, NULL, &value)) + value = 1; /* It seems to be better to assume secure memory on + error. */ + return value; +} + + +int +gcry_md_is_enabled (gcry_md_hd_t a, int algo) +{ + size_t value; + + value = sizeof algo; + if (gcry_md_info (a, GCRYCTL_IS_ALGO_ENABLED, &algo, &value)) + value = 0; + return value; +} + +/* Get a list consisting of the IDs of the loaded message digest + modules. If LIST is zero, write the number of loaded message + digest modules to LIST_LENGTH and return. If LIST is non-zero, the + first *LIST_LENGTH algorithm IDs are stored in LIST, which must be + of according size. In case there are less message digest modules + than *LIST_LENGTH, *LIST_LENGTH is updated to the correct + number. */ +gcry_error_t +gcry_md_list (int *list, int *list_length) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + ath_mutex_lock (&digests_registered_lock); + err = _gcry_module_list (digests_registered, list, list_length); + ath_mutex_unlock (&digests_registered_lock); + + return err; +} + + +/* Run the selftests for digest algorithm ALGO with optional reporting + function REPORT. */ +gpg_error_t +_gcry_md_selftest (int algo, int extended, selftest_report_func_t report) +{ + gcry_module_t module = NULL; + cipher_extra_spec_t *extraspec = NULL; + gcry_err_code_t ec = 0; + + REGISTER_DEFAULT_DIGESTS; + + ath_mutex_lock (&digests_registered_lock); + module = _gcry_module_lookup_id (digests_registered, algo); + if (module && !(module->flags & FLAG_MODULE_DISABLED)) + extraspec = module->extraspec; + ath_mutex_unlock (&digests_registered_lock); + if (extraspec && extraspec->selftest) + ec = extraspec->selftest (algo, extended, report); + else + { + ec = GPG_ERR_DIGEST_ALGO; + if (report) + report ("digest", algo, "module", + module && !(module->flags & FLAG_MODULE_DISABLED)? + "no selftest available" : + module? "algorithm disabled" : "algorithm not found"); + } + + if (module) + { + ath_mutex_lock (&digests_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&digests_registered_lock); + } + return gpg_error (ec); +} diff --git a/libgcrypt-1.4.6/cipher/primegen.c b/libgcrypt-1.4.6/cipher/primegen.c index b869bee..50dc560 100644 --- a/libgcrypt-1.4.6/cipher/primegen.c +++ b/libgcrypt-1.4.6/cipher/primegen.c @@ -1,1862 +1,1862 @@ -/* primegen.c - prime number generator - * Copyright (C) 1998, 2000, 2001, 2002, 2003 - * 2004, 2008 Free Software Foundation, Inc. - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser general Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include - -#include -#include -#include -#include - -#include "g10lib.h" -#include "mpi.h" -#include "cipher.h" -#include "ath.h" - -static gcry_mpi_t gen_prime (unsigned int nbits, int secret, int randomlevel, - int (*extra_check)(void *, gcry_mpi_t), - void *extra_check_arg); -static int check_prime( gcry_mpi_t prime, gcry_mpi_t val_2, int rm_rounds, - gcry_prime_check_func_t cb_func, void *cb_arg ); -static int is_prime (gcry_mpi_t n, int steps, unsigned int *count); -static void m_out_of_n( char *array, int m, int n ); - -static void (*progress_cb) (void *,const char*,int,int, int ); -static void *progress_cb_data; - -/* Note: 2 is not included because it can be tested more easily by - looking at bit 0. The last entry in this list is marked by a zero */ -static ushort small_prime_numbers[] = { - 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, - 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, - 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, - 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, - 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, - 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, - 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, - 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, - 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, - 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, - 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, - 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, - 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, - 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, - 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, - 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, - 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, - 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, - 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, - 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, - 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, - 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, - 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, - 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, - 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, - 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, - 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, - 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, - 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, - 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, - 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, - 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, - 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, - 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, - 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, - 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, - 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, - 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, - 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, - 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, - 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, - 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, - 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, - 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, - 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, - 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, - 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, - 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, - 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, - 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, - 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, - 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, - 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, - 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, - 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, - 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, - 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, - 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, - 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, - 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, - 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, - 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, - 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, - 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, - 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, - 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, - 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, - 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, - 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, - 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, - 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, - 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, - 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, - 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, - 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, - 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, - 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, - 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, - 4957, 4967, 4969, 4973, 4987, 4993, 4999, - 0 -}; -static int no_of_small_prime_numbers = DIM (small_prime_numbers) - 1; - - - -/* An object and a list to build up a global pool of primes. See - save_pool_prime and get_pool_prime. */ -struct primepool_s -{ - struct primepool_s *next; - gcry_mpi_t prime; /* If this is NULL the entry is not used. */ - unsigned int nbits; - gcry_random_level_t randomlevel; -}; -struct primepool_s *primepool; -/* Mutex used to protect access to the primepool. */ -static ath_mutex_t primepool_lock = ATH_MUTEX_INITIALIZER; - - - -/* Save PRIME which has been generated at RANDOMLEVEL for later - use. Needs to be called while primepool_lock is being hold. Note - that PRIME should be considered released after calling this - function. */ -static void -save_pool_prime (gcry_mpi_t prime, gcry_random_level_t randomlevel) -{ - struct primepool_s *item, *item2; - size_t n; - - for (n=0, item = primepool; item; item = item->next, n++) - if (!item->prime) - break; - if (!item && n > 100) - { - /* Remove some of the entries. Our strategy is removing - the last third from the list. */ - int i; - - for (i=0, item2 = primepool; item2; item2 = item2->next) - { - if (i >= n/3*2) - { - gcry_mpi_release (item2->prime); - item2->prime = NULL; - if (!item) - item = item2; - } - } - } - if (!item) - { - item = gcry_calloc (1, sizeof *item); - if (!item) - { - /* Out of memory. Silently giving up. */ - gcry_mpi_release (prime); - return; - } - item->next = primepool; - primepool = item; - } - item->prime = prime; - item->nbits = mpi_get_nbits (prime); - item->randomlevel = randomlevel; -} - - -/* Return a prime for the prime pool or NULL if none has been found. - The prime needs to match NBITS and randomlevel. This function needs - to be called why the primepool_look is being hold. */ -static gcry_mpi_t -get_pool_prime (unsigned int nbits, gcry_random_level_t randomlevel) -{ - struct primepool_s *item; - - for (item = primepool; item; item = item->next) - if (item->prime - && item->nbits == nbits && item->randomlevel == randomlevel) - { - gcry_mpi_t prime = item->prime; - item->prime = NULL; - gcry_assert (nbits == mpi_get_nbits (prime)); - return prime; - } - return NULL; -} - - - - - - -void -_gcry_register_primegen_progress ( void (*cb)(void *,const char*,int,int,int), - void *cb_data ) -{ - progress_cb = cb; - progress_cb_data = cb_data; -} - - -static void -progress( int c ) -{ - if ( progress_cb ) - progress_cb ( progress_cb_data, "primegen", c, 0, 0 ); -} - - -/**************** - * Generate a prime number (stored in secure memory) - */ -gcry_mpi_t -_gcry_generate_secret_prime (unsigned int nbits, - gcry_random_level_t random_level, - int (*extra_check)(void*, gcry_mpi_t), - void *extra_check_arg) -{ - gcry_mpi_t prime; - - prime = gen_prime (nbits, 1, random_level, extra_check, extra_check_arg); - progress('\n'); - return prime; -} - - -/* Generate a prime number which may be public, i.e. not allocated in - secure memory. */ -gcry_mpi_t -_gcry_generate_public_prime (unsigned int nbits, - gcry_random_level_t random_level, - int (*extra_check)(void*, gcry_mpi_t), - void *extra_check_arg) -{ - gcry_mpi_t prime; - - prime = gen_prime (nbits, 0, random_level, extra_check, extra_check_arg); - progress('\n'); - return prime; -} - - -/* Core prime generation function. The algorithm used to generate - practically save primes is due to Lim and Lee as described in the - CRYPTO '97 proceedings (ISBN3540633847) page 260. - - NEED_Q_FACTOR: If true make sure that at least one factor is of - size qbits. This is for example required for DSA. - PRIME_GENERATED: Adresss of a variable where the resulting prime - number will be stored. - PBITS: Requested size of the prime number. At least 48. - QBITS: One factor of the prime needs to be of this size. Maybe 0 - if this is not required. See also MODE. - G: If not NULL an MPI which will receive a generator for the prime - for use with Elgamal. - RET_FACTORS: if not NULL, an array with all factors are stored at - that address. - ALL_FACTORS: If set to true all factors of prime-1 are returned. - RANDOMLEVEL: How strong should the random numers be. - FLAGS: Prime generation bit flags. Currently supported: - GCRY_PRIME_FLAG_SECRET - The prime needs to be kept secret. - CB_FUNC, CB_ARG: Callback to be used for extra checks. - - */ -static gcry_err_code_t -prime_generate_internal (int need_q_factor, - gcry_mpi_t *prime_generated, unsigned int pbits, - unsigned int qbits, gcry_mpi_t g, - gcry_mpi_t **ret_factors, - gcry_random_level_t randomlevel, unsigned int flags, - int all_factors, - gcry_prime_check_func_t cb_func, void *cb_arg) -{ - gcry_err_code_t err = 0; - gcry_mpi_t *factors_new = NULL; /* Factors to return to the - caller. */ - gcry_mpi_t *factors = NULL; /* Current factors. */ - gcry_random_level_t poolrandomlevel; /* Random level used for pool primes. */ - gcry_mpi_t *pool = NULL; /* Pool of primes. */ - int *pool_in_use = NULL; /* Array with currently used POOL elements. */ - unsigned char *perms = NULL; /* Permutations of POOL. */ - gcry_mpi_t q_factor = NULL; /* Used if QBITS is non-zero. */ - unsigned int fbits = 0; /* Length of prime factors. */ - unsigned int n = 0; /* Number of factors. */ - unsigned int m = 0; /* Number of primes in pool. */ - gcry_mpi_t q = NULL; /* First prime factor. */ - gcry_mpi_t prime = NULL; /* Prime candidate. */ - unsigned int nprime = 0; /* Bits of PRIME. */ - unsigned int req_qbits; /* The original QBITS value. */ - gcry_mpi_t val_2; /* For check_prime(). */ - int is_locked = 0; /* Flag to help unlocking the primepool. */ - unsigned int is_secret = (flags & GCRY_PRIME_FLAG_SECRET); - unsigned int count1 = 0, count2 = 0; - unsigned int i = 0, j = 0; - - if (pbits < 48) - return GPG_ERR_INV_ARG; - - /* We won't use a too strong random elvel for the pooled subprimes. */ - poolrandomlevel = (randomlevel > GCRY_STRONG_RANDOM? - GCRY_STRONG_RANDOM : randomlevel); - - - /* If QBITS is not given, assume a reasonable value. */ - if (!qbits) - qbits = pbits / 3; - - req_qbits = qbits; - - /* Find number of needed prime factors N. */ - for (n = 1; (pbits - qbits - 1) / n >= qbits; n++) - ; - n--; - - val_2 = mpi_alloc_set_ui (2); - - if ((! n) || ((need_q_factor) && (n < 2))) - { - err = GPG_ERR_INV_ARG; - goto leave; - } - - if (need_q_factor) - { - n--; /* Need one factor less because we want a specific Q-FACTOR. */ - fbits = (pbits - 2 * req_qbits -1) / n; - qbits = pbits - req_qbits - n * fbits; - } - else - { - fbits = (pbits - req_qbits -1) / n; - qbits = pbits - n * fbits; - } - - if (DBG_CIPHER) - log_debug ("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n", - pbits, req_qbits, qbits, fbits, n); - - /* Allocate an integer to old the new prime. */ - prime = gcry_mpi_new (pbits); - - /* Generate first prime factor. */ - q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); - - /* Generate a specific Q-Factor if requested. */ - if (need_q_factor) - q_factor = gen_prime (req_qbits, is_secret, randomlevel, NULL, NULL); - - /* Allocate an array to hold all factors + 2 for later usage. */ - factors = gcry_calloc (n + 2, sizeof (*factors)); - if (!factors) - { - err = gpg_err_code_from_errno (errno); - goto leave; - } - - /* Allocate an array to track pool usage. */ - pool_in_use = gcry_malloc (n * sizeof *pool_in_use); - if (!pool_in_use) - { - err = gpg_err_code_from_errno (errno); - goto leave; - } - for (i=0; i < n; i++) - pool_in_use[i] = -1; - - /* Make a pool of 3n+5 primes (this is an arbitrary value). We - require at least 30 primes for are useful selection process. - - Fixme: We need to research the best formula for sizing the pool. - */ - m = n * 3 + 5; - if (need_q_factor) /* Need some more in this case. */ - m += 5; - if (m < 30) - m = 30; - pool = gcry_calloc (m , sizeof (*pool)); - if (! pool) - { - err = gpg_err_code_from_errno (errno); - goto leave; - } - - /* Permutate over the pool of primes until we find a prime of the - requested length. */ - do - { - next_try: - for (i=0; i < n; i++) - pool_in_use[i] = -1; - - if (!perms) - { - /* Allocate new primes. This is done right at the beginning - of the loop and if we have later run out of primes. */ - for (i = 0; i < m; i++) - { - mpi_free (pool[i]); - pool[i] = NULL; - } - - /* Init m_out_of_n(). */ - perms = gcry_calloc (1, m); - if (!perms) - { - err = gpg_err_code_from_errno (errno); - goto leave; - } - - if (ath_mutex_lock (&primepool_lock)) - { - err = GPG_ERR_INTERNAL; - goto leave; - } - is_locked = 1; - for (i = 0; i < n; i++) - { - perms[i] = 1; - /* At a maximum we use strong random for the factors. - This saves us a lot of entropy. Given that Q and - possible Q-factor are also used in the final prime - this should be acceptable. We also don't allocate in - secure memory to save on that scare resource too. If - Q has been allocated in secure memory, the final - prime will be saved there anyway. This is because - our MPI routines take care of that. GnuPG has worked - this way ever since. */ - pool[i] = NULL; - if (is_locked) - { - pool[i] = get_pool_prime (fbits, poolrandomlevel); - if (!pool[i]) - { - if (ath_mutex_unlock (&primepool_lock)) - { - err = GPG_ERR_INTERNAL; - goto leave; - } - is_locked = 0; - } - } - if (!pool[i]) - pool[i] = gen_prime (fbits, 0, poolrandomlevel, NULL, NULL); - pool_in_use[i] = i; - factors[i] = pool[i]; - } - if (is_locked && ath_mutex_unlock (&primepool_lock)) - { - err = GPG_ERR_INTERNAL; - goto leave; - } - is_locked = 0; - } - else - { - /* Get next permutation. */ - m_out_of_n ( (char*)perms, n, m); - if (ath_mutex_lock (&primepool_lock)) - { - err = GPG_ERR_INTERNAL; - goto leave; - } - is_locked = 1; - for (i = j = 0; (i < m) && (j < n); i++) - if (perms[i]) - { - /* If the subprime has not yet beed generated do it now. */ - if (!pool[i] && is_locked) - { - pool[i] = get_pool_prime (fbits, poolrandomlevel); - if (!pool[i]) - { - if (ath_mutex_unlock (&primepool_lock)) - { - err = GPG_ERR_INTERNAL; - goto leave; - } - is_locked = 0; - } - } - if (!pool[i]) - pool[i] = gen_prime (fbits, 0, poolrandomlevel, NULL, NULL); - pool_in_use[j] = i; - factors[j++] = pool[i]; - } - if (is_locked && ath_mutex_unlock (&primepool_lock)) - { - err = GPG_ERR_INTERNAL; - goto leave; - } - is_locked = 0; - if (i == n) - { - /* Ran out of permutations: Allocate new primes. */ - gcry_free (perms); - perms = NULL; - progress ('!'); - goto next_try; - } - } - - /* Generate next prime candidate: - p = 2 * q [ * q_factor] * factor_0 * factor_1 * ... * factor_n + 1. - */ - mpi_set (prime, q); - mpi_mul_ui (prime, prime, 2); - if (need_q_factor) - mpi_mul (prime, prime, q_factor); - for(i = 0; i < n; i++) - mpi_mul (prime, prime, factors[i]); - mpi_add_ui (prime, prime, 1); - nprime = mpi_get_nbits (prime); - - if (nprime < pbits) - { - if (++count1 > 20) - { - count1 = 0; - qbits++; - progress('>'); - mpi_free (q); - q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); - goto next_try; - } - } - else - count1 = 0; - - if (nprime > pbits) - { - if (++count2 > 20) - { - count2 = 0; - qbits--; - progress('<'); - mpi_free (q); - q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); - goto next_try; - } - } - else - count2 = 0; - } - while (! ((nprime == pbits) && check_prime (prime, val_2, 5, - cb_func, cb_arg))); - - if (DBG_CIPHER) - { - progress ('\n'); - log_mpidump ("prime : ", prime); - log_mpidump ("factor q: ", q); - if (need_q_factor) - log_mpidump ("factor q0: ", q_factor); - for (i = 0; i < n; i++) - log_mpidump ("factor pi: ", factors[i]); - log_debug ("bit sizes: prime=%u, q=%u", - mpi_get_nbits (prime), mpi_get_nbits (q)); - if (need_q_factor) - log_debug (", q0=%u", mpi_get_nbits (q_factor)); - for (i = 0; i < n; i++) - log_debug (", p%d=%u", i, mpi_get_nbits (factors[i])); - progress('\n'); - } - - if (ret_factors) - { - /* Caller wants the factors. */ - factors_new = gcry_calloc (n + 4, sizeof (*factors_new)); - if (! factors_new) - { - err = gpg_err_code_from_errno (errno); - goto leave; - } - - if (all_factors) - { - i = 0; - factors_new[i++] = gcry_mpi_set_ui (NULL, 2); - factors_new[i++] = mpi_copy (q); - if (need_q_factor) - factors_new[i++] = mpi_copy (q_factor); - for(j=0; j < n; j++) - factors_new[i++] = mpi_copy (factors[j]); - } - else - { - i = 0; - if (need_q_factor) - { - factors_new[i++] = mpi_copy (q_factor); - for (; i <= n; i++) - factors_new[i] = mpi_copy (factors[i]); - } - else - for (; i < n; i++ ) - factors_new[i] = mpi_copy (factors[i]); - } - } - - if (g) - { - /* Create a generator (start with 3). */ - gcry_mpi_t tmp = mpi_alloc (mpi_get_nlimbs (prime)); - gcry_mpi_t b = mpi_alloc (mpi_get_nlimbs (prime)); - gcry_mpi_t pmin1 = mpi_alloc (mpi_get_nlimbs (prime)); - - if (need_q_factor) - err = GPG_ERR_NOT_IMPLEMENTED; - else - { - factors[n] = q; - factors[n + 1] = mpi_alloc_set_ui (2); - mpi_sub_ui (pmin1, prime, 1); - mpi_set_ui (g, 2); - do - { - mpi_add_ui (g, g, 1); - if (DBG_CIPHER) - { - log_debug ("checking g:"); - gcry_mpi_dump (g); - log_printf ("\n"); - } - else - progress('^'); - for (i = 0; i < n + 2; i++) - { - mpi_fdiv_q (tmp, pmin1, factors[i]); - /* No mpi_pow(), but it is okay to use this with mod - prime. */ - gcry_mpi_powm (b, g, tmp, prime); - if (! mpi_cmp_ui (b, 1)) - break; - } - if (DBG_CIPHER) - progress('\n'); - } - while (i < n + 2); - - mpi_free (factors[n+1]); - mpi_free (tmp); - mpi_free (b); - mpi_free (pmin1); - } - } - - if (! DBG_CIPHER) - progress ('\n'); - - - leave: - if (pool) - { - is_locked = !ath_mutex_lock (&primepool_lock); - for(i = 0; i < m; i++) - { - if (pool[i]) - { - for (j=0; j < n; j++) - if (pool_in_use[j] == i) - break; - if (j == n && is_locked) - { - /* This pooled subprime has not been used. */ - save_pool_prime (pool[i], poolrandomlevel); - } - else - mpi_free (pool[i]); - } - } - if (is_locked && ath_mutex_unlock (&primepool_lock)) - err = GPG_ERR_INTERNAL; - is_locked = 0; - gcry_free (pool); - } - gcry_free (pool_in_use); - if (factors) - gcry_free (factors); /* Factors are shallow copies. */ - if (perms) - gcry_free (perms); - - mpi_free (val_2); - mpi_free (q); - mpi_free (q_factor); - - if (! err) - { - *prime_generated = prime; - if (ret_factors) - *ret_factors = factors_new; - } - else - { - if (factors_new) - { - for (i = 0; factors_new[i]; i++) - mpi_free (factors_new[i]); - gcry_free (factors_new); - } - mpi_free (prime); - } - - return err; -} - - -/* Generate a prime used for discrete logarithm algorithms; i.e. this - prime will be public and no strong random is required. */ -gcry_mpi_t -_gcry_generate_elg_prime (int mode, unsigned pbits, unsigned qbits, - gcry_mpi_t g, gcry_mpi_t **ret_factors) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_mpi_t prime = NULL; - - err = prime_generate_internal ((mode == 1), &prime, pbits, qbits, g, - ret_factors, GCRY_WEAK_RANDOM, 0, 0, - NULL, NULL); - - return prime; -} - - -static gcry_mpi_t -gen_prime (unsigned int nbits, int secret, int randomlevel, - int (*extra_check)(void *, gcry_mpi_t), void *extra_check_arg) -{ - gcry_mpi_t prime, ptest, pminus1, val_2, val_3, result; - int i; - unsigned int x, step; - unsigned int count1, count2; - int *mods; - -/* if ( DBG_CIPHER ) */ -/* log_debug ("generate a prime of %u bits ", nbits ); */ - - if (nbits < 16) - log_fatal ("can't generate a prime with less than %d bits\n", 16); - - mods = gcry_xmalloc( no_of_small_prime_numbers * sizeof *mods ); - /* Make nbits fit into gcry_mpi_t implementation. */ - val_2 = mpi_alloc_set_ui( 2 ); - val_3 = mpi_alloc_set_ui( 3); - prime = secret? gcry_mpi_snew ( nbits ): gcry_mpi_new ( nbits ); - result = mpi_alloc_like( prime ); - pminus1= mpi_alloc_like( prime ); - ptest = mpi_alloc_like( prime ); - count1 = count2 = 0; - for (;;) - { /* try forvever */ - int dotcount=0; - - /* generate a random number */ - gcry_mpi_randomize( prime, nbits, randomlevel ); - - /* Set high order bit to 1, set low order bit to 1. If we are - generating a secret prime we are most probably doing that - for RSA, to make sure that the modulus does have the - requested key size we set the 2 high order bits. */ - mpi_set_highbit (prime, nbits-1); - if (secret) - mpi_set_bit (prime, nbits-2); - mpi_set_bit(prime, 0); - - /* Calculate all remainders. */ - for (i=0; (x = small_prime_numbers[i]); i++ ) - mods[i] = mpi_fdiv_r_ui(NULL, prime, x); - - /* Now try some primes starting with prime. */ - for(step=0; step < 20000; step += 2 ) - { - /* Check against all the small primes we have in mods. */ - count1++; - for (i=0; (x = small_prime_numbers[i]); i++ ) - { - while ( mods[i] + step >= x ) - mods[i] -= x; - if ( !(mods[i] + step) ) - break; - } - if ( x ) - continue; /* Found a multiple of an already known prime. */ - - mpi_add_ui( ptest, prime, step ); - - /* Do a fast Fermat test now. */ - count2++; - mpi_sub_ui( pminus1, ptest, 1); - gcry_mpi_powm( result, val_2, pminus1, ptest ); - if ( !mpi_cmp_ui( result, 1 ) ) - { - /* Not composite, perform stronger tests */ - if (is_prime(ptest, 5, &count2 )) - { - if (!mpi_test_bit( ptest, nbits-1-secret )) - { - progress('\n'); - log_debug ("overflow in prime generation\n"); - break; /* Stop loop, continue with a new prime. */ - } - - if (extra_check && extra_check (extra_check_arg, ptest)) - { - /* The extra check told us that this prime is - not of the caller's taste. */ - progress ('/'); - } - else - { - /* Got it. */ - mpi_free(val_2); - mpi_free(val_3); - mpi_free(result); - mpi_free(pminus1); - mpi_free(prime); - gcry_free(mods); - return ptest; - } - } - } - if (++dotcount == 10 ) - { - progress('.'); - dotcount = 0; - } - } - progress(':'); /* restart with a new random value */ - } -} - -/**************** - * Returns: true if this may be a prime - * RM_ROUNDS gives the number of Rabin-Miller tests to run. - */ -static int -check_prime( gcry_mpi_t prime, gcry_mpi_t val_2, int rm_rounds, - gcry_prime_check_func_t cb_func, void *cb_arg) -{ - int i; - unsigned int x; - unsigned int count=0; - - /* Check against small primes. */ - for (i=0; (x = small_prime_numbers[i]); i++ ) - { - if ( mpi_divisible_ui( prime, x ) ) - return 0; - } - - /* A quick Fermat test. */ - { - gcry_mpi_t result = mpi_alloc_like( prime ); - gcry_mpi_t pminus1 = mpi_alloc_like( prime ); - mpi_sub_ui( pminus1, prime, 1); - gcry_mpi_powm( result, val_2, pminus1, prime ); - mpi_free( pminus1 ); - if ( mpi_cmp_ui( result, 1 ) ) - { - /* Is composite. */ - mpi_free( result ); - progress('.'); - return 0; - } - mpi_free( result ); - } - - if (!cb_func || cb_func (cb_arg, GCRY_PRIME_CHECK_AT_MAYBE_PRIME, prime)) - { - /* Perform stronger tests. */ - if ( is_prime( prime, rm_rounds, &count ) ) - { - if (!cb_func - || cb_func (cb_arg, GCRY_PRIME_CHECK_AT_GOT_PRIME, prime)) - return 1; /* Probably a prime. */ - } - } - progress('.'); - return 0; -} - - -/* - * Return true if n is probably a prime - */ -static int -is_prime (gcry_mpi_t n, int steps, unsigned int *count) -{ - gcry_mpi_t x = mpi_alloc( mpi_get_nlimbs( n ) ); - gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs( n ) ); - gcry_mpi_t z = mpi_alloc( mpi_get_nlimbs( n ) ); - gcry_mpi_t nminus1 = mpi_alloc( mpi_get_nlimbs( n ) ); - gcry_mpi_t a2 = mpi_alloc_set_ui( 2 ); - gcry_mpi_t q; - unsigned i, j, k; - int rc = 0; - unsigned nbits = mpi_get_nbits( n ); - - if (steps < 5) /* Make sure that we do at least 5 rounds. */ - steps = 5; - - mpi_sub_ui( nminus1, n, 1 ); - - /* Find q and k, so that n = 1 + 2^k * q . */ - q = mpi_copy ( nminus1 ); - k = mpi_trailing_zeros ( q ); - mpi_tdiv_q_2exp (q, q, k); - - for (i=0 ; i < steps; i++ ) - { - ++*count; - if( !i ) - { - mpi_set_ui( x, 2 ); - } - else - { - gcry_mpi_randomize( x, nbits, GCRY_WEAK_RANDOM ); - - /* Make sure that the number is smaller than the prime and - keep the randomness of the high bit. */ - if ( mpi_test_bit ( x, nbits-2) ) - { - mpi_set_highbit ( x, nbits-2); /* Clear all higher bits. */ - } - else - { - mpi_set_highbit( x, nbits-2 ); - mpi_clear_bit( x, nbits-2 ); - } - gcry_assert (mpi_cmp (x, nminus1) < 0 && mpi_cmp_ui (x, 1) > 0); - } - gcry_mpi_powm ( y, x, q, n); - if ( mpi_cmp_ui(y, 1) && mpi_cmp( y, nminus1 ) ) - { - for ( j=1; j < k && mpi_cmp( y, nminus1 ); j++ ) - { - gcry_mpi_powm(y, y, a2, n); - if( !mpi_cmp_ui( y, 1 ) ) - goto leave; /* Not a prime. */ - } - if (mpi_cmp( y, nminus1 ) ) - goto leave; /* Not a prime. */ - } - progress('+'); - } - rc = 1; /* May be a prime. */ - - leave: - mpi_free( x ); - mpi_free( y ); - mpi_free( z ); - mpi_free( nminus1 ); - mpi_free( q ); - mpi_free( a2 ); - - return rc; -} - - -/* Given ARRAY of size N with M elements set to true produce a - modified array with the next permutation of M elements. Note, that - ARRAY is used in a one-bit-per-byte approach. To detected the last - permutation it is useful to intialize the array with the first M - element set to true and use this test: - m_out_of_n (array, m, n); - for (i = j = 0; i < n && j < m; i++) - if (array[i]) - j++; - if (j == m) - goto ready; - - This code is based on the algorithm 452 from the "Collected - Algorithms From ACM, Volume II" by C. N. Liu and D. T. Tang. -*/ -static void -m_out_of_n ( char *array, int m, int n ) -{ - int i=0, i1=0, j=0, jp=0, j1=0, k1=0, k2=0; - - if( !m || m >= n ) - return; - - /* Need to handle this simple case separately. */ - if( m == 1 ) - { - for (i=0; i < n; i++ ) - { - if ( array[i] ) - { - array[i++] = 0; - if( i >= n ) - i = 0; - array[i] = 1; - return; - } - } - BUG(); - } - - - for (j=1; j < n; j++ ) - { - if ( array[n-1] == array[n-j-1]) - continue; - j1 = j; - break; - } - - if ( (m & 1) ) - { - /* M is odd. */ - if( array[n-1] ) - { - if( j1 & 1 ) - { - k1 = n - j1; - k2 = k1+2; - if( k2 > n ) - k2 = n; - goto leave; - } - goto scan; - } - k2 = n - j1 - 1; - if( k2 == 0 ) - { - k1 = i; - k2 = n - j1; - } - else if( array[k2] && array[k2-1] ) - k1 = n; - else - k1 = k2 + 1; - } - else - { - /* M is even. */ - if( !array[n-1] ) - { - k1 = n - j1; - k2 = k1 + 1; - goto leave; - } - - if( !(j1 & 1) ) - { - k1 = n - j1; - k2 = k1+2; - if( k2 > n ) - k2 = n; - goto leave; - } - scan: - jp = n - j1 - 1; - for (i=1; i <= jp; i++ ) - { - i1 = jp + 2 - i; - if( array[i1-1] ) - { - if( array[i1-2] ) - { - k1 = i1 - 1; - k2 = n - j1; - } - else - { - k1 = i1 - 1; - k2 = n + 1 - j1; - } - goto leave; - } - } - k1 = 1; - k2 = n + 1 - m; - } - leave: - /* Now complement the two selected bits. */ - array[k1-1] = !array[k1-1]; - array[k2-1] = !array[k2-1]; -} - - -/* Generate a new prime number of PRIME_BITS bits and store it in - PRIME. If FACTOR_BITS is non-zero, one of the prime factors of - (prime - 1) / 2 must be FACTOR_BITS bits long. If FACTORS is - non-zero, allocate a new, NULL-terminated array holding the prime - factors and store it in FACTORS. FLAGS might be used to influence - the prime number generation process. */ -gcry_error_t -gcry_prime_generate (gcry_mpi_t *prime, unsigned int prime_bits, - unsigned int factor_bits, gcry_mpi_t **factors, - gcry_prime_check_func_t cb_func, void *cb_arg, - gcry_random_level_t random_level, - unsigned int flags) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_mpi_t *factors_generated = NULL; - gcry_mpi_t prime_generated = NULL; - unsigned int mode = 0; - - if (!prime) - return gpg_error (GPG_ERR_INV_ARG); - *prime = NULL; - - if (flags & GCRY_PRIME_FLAG_SPECIAL_FACTOR) - mode = 1; - - /* Generate. */ - err = prime_generate_internal ((mode==1), &prime_generated, prime_bits, - factor_bits, NULL, - factors? &factors_generated : NULL, - random_level, flags, 1, - cb_func, cb_arg); - - if (! err) - if (cb_func) - { - /* Additional check. */ - if ( !cb_func (cb_arg, GCRY_PRIME_CHECK_AT_FINISH, prime_generated)) - { - /* Failed, deallocate resources. */ - unsigned int i; - - mpi_free (prime_generated); - if (factors) - { - for (i = 0; factors_generated[i]; i++) - mpi_free (factors_generated[i]); - gcry_free (factors_generated); - } - err = GPG_ERR_GENERAL; - } - } - - if (! err) - { - if (factors) - *factors = factors_generated; - *prime = prime_generated; - } - - return gcry_error (err); -} - -/* Check wether the number X is prime. */ -gcry_error_t -gcry_prime_check (gcry_mpi_t x, unsigned int flags) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_mpi_t val_2 = mpi_alloc_set_ui (2); /* Used by the Fermat test. */ - - (void)flags; - - /* We use 64 rounds because the prime we are going to test is not - guaranteed to be a random one. */ - if (! check_prime (x, val_2, 64, NULL, NULL)) - err = GPG_ERR_NO_PRIME; - - mpi_free (val_2); - - return gcry_error (err); -} - -/* Find a generator for PRIME where the factorization of (prime-1) is - in the NULL terminated array FACTORS. Return the generator as a - newly allocated MPI in R_G. If START_G is not NULL, use this as s - atart for the search. Returns 0 on success.*/ -gcry_error_t -gcry_prime_group_generator (gcry_mpi_t *r_g, - gcry_mpi_t prime, gcry_mpi_t *factors, - gcry_mpi_t start_g) -{ - gcry_mpi_t tmp = gcry_mpi_new (0); - gcry_mpi_t b = gcry_mpi_new (0); - gcry_mpi_t pmin1 = gcry_mpi_new (0); - gcry_mpi_t g = start_g? gcry_mpi_copy (start_g) : gcry_mpi_set_ui (NULL, 3); - int first = 1; - int i, n; - - if (!factors || !r_g || !prime) - return gpg_error (GPG_ERR_INV_ARG); - *r_g = NULL; - - for (n=0; factors[n]; n++) - ; - if (n < 2) - return gpg_error (GPG_ERR_INV_ARG); - - /* Extra sanity check - usually disabled. */ -/* mpi_set (tmp, factors[0]); */ -/* for(i = 1; i < n; i++) */ -/* mpi_mul (tmp, tmp, factors[i]); */ -/* mpi_add_ui (tmp, tmp, 1); */ -/* if (mpi_cmp (prime, tmp)) */ -/* return gpg_error (GPG_ERR_INV_ARG); */ - - gcry_mpi_sub_ui (pmin1, prime, 1); - do - { - if (first) - first = 0; - else - gcry_mpi_add_ui (g, g, 1); - - if (DBG_CIPHER) - { - log_debug ("checking g:"); - gcry_mpi_dump (g); - log_debug ("\n"); - } - else - progress('^'); - - for (i = 0; i < n; i++) - { - mpi_fdiv_q (tmp, pmin1, factors[i]); - gcry_mpi_powm (b, g, tmp, prime); - if (! mpi_cmp_ui (b, 1)) - break; - } - if (DBG_CIPHER) - progress('\n'); - } - while (i < n); - - gcry_mpi_release (tmp); - gcry_mpi_release (b); - gcry_mpi_release (pmin1); - *r_g = g; - - return 0; -} - -/* Convenience function to release the factors array. */ -void -gcry_prime_release_factors (gcry_mpi_t *factors) -{ - if (factors) - { - int i; - - for (i=0; factors[i]; i++) - mpi_free (factors[i]); - gcry_free (factors); - } -} - - - -/* Helper for _gcry_derive_x931_prime. */ -static gcry_mpi_t -find_x931_prime (const gcry_mpi_t pfirst) -{ - gcry_mpi_t val_2 = mpi_alloc_set_ui (2); - gcry_mpi_t prime; - - prime = gcry_mpi_copy (pfirst); - /* If P is even add 1. */ - mpi_set_bit (prime, 0); - - /* We use 64 Rabin-Miller rounds which is better and thus - sufficient. We do not have a Lucas test implementaion thus we - can't do it in the X9.31 preferred way of running a few - Rabin-Miller followed by one Lucas test. */ - while ( !check_prime (prime, val_2, 64, NULL, NULL) ) - mpi_add_ui (prime, prime, 2); - - mpi_free (val_2); - - return prime; -} - - -/* Generate a prime using the algorithm from X9.31 appendix B.4. - - This function requires that the provided public exponent E is odd. - XP, XP1 and XP2 are the seed values. All values are mandatory. - - On success the prime is returned. If R_P1 or R_P2 are given the - internal values P1 and P2 are saved at these addresses. On error - NULL is returned. */ -gcry_mpi_t -_gcry_derive_x931_prime (const gcry_mpi_t xp, - const gcry_mpi_t xp1, const gcry_mpi_t xp2, - const gcry_mpi_t e, - gcry_mpi_t *r_p1, gcry_mpi_t *r_p2) -{ - gcry_mpi_t p1, p2, p1p2, yp0; - - if (!xp || !xp1 || !xp2) - return NULL; - if (!e || !mpi_test_bit (e, 0)) - return NULL; /* We support only odd values for E. */ - - p1 = find_x931_prime (xp1); - p2 = find_x931_prime (xp2); - p1p2 = mpi_alloc_like (xp); - mpi_mul (p1p2, p1, p2); - - { - gcry_mpi_t r1, tmp; - - /* r1 = (p2^{-1} mod p1)p2 - (p1^{-1} mod p2) */ - tmp = mpi_alloc_like (p1); - mpi_invm (tmp, p2, p1); - mpi_mul (tmp, tmp, p2); - r1 = tmp; - - tmp = mpi_alloc_like (p2); - mpi_invm (tmp, p1, p2); - mpi_mul (tmp, tmp, p1); - mpi_sub (r1, r1, tmp); - - /* Fixup a negative value. */ - if (mpi_is_neg (r1)) - mpi_add (r1, r1, p1p2); - - /* yp0 = xp + (r1 - xp mod p1*p2) */ - yp0 = tmp; tmp = NULL; - mpi_subm (yp0, r1, xp, p1p2); - mpi_add (yp0, yp0, xp); - mpi_free (r1); - - /* Fixup a negative value. */ - if (mpi_cmp (yp0, xp) < 0 ) - mpi_add (yp0, yp0, p1p2); - } - - /* yp0 is now the first integer greater than xp with p1 being a - large prime factor of yp0-1 and p2 a large prime factor of yp0+1. */ - - /* Note that the first example from X9.31 (D.1.1) which uses - (Xq1 #1A5CF72EE770DE50CB09ACCEA9#) - (Xq2 #134E4CAA16D2350A21D775C404#) - (Xq #CC1092495D867E64065DEE3E7955F2EBC7D47A2D - 7C9953388F97DDDC3E1CA19C35CA659EDC2FC325 - 6D29C2627479C086A699A49C4C9CEE7EF7BD1B34 - 321DE34A#)))) - returns an yp0 of - #CC1092495D867E64065DEE3E7955F2EBC7D47A2D - 7C9953388F97DDDC3E1CA19C35CA659EDC2FC4E3 - BF20CB896EE37E098A906313271422162CB6C642 - 75C1201F# - and not - #CC1092495D867E64065DEE3E7955F2EBC7D47A2D - 7C9953388F97DDDC3E1CA19C35CA659EDC2FC2E6 - C88FE299D52D78BE405A97E01FD71DD7819ECB91 - FA85A076# - as stated in the standard. This seems to be a bug in X9.31. - */ - - { - gcry_mpi_t val_2 = mpi_alloc_set_ui (2); - gcry_mpi_t gcdtmp = mpi_alloc_like (yp0); - int gcdres; - - mpi_sub_ui (p1p2, p1p2, 1); /* Adjust for loop body. */ - mpi_sub_ui (yp0, yp0, 1); /* Ditto. */ - for (;;) - { - gcdres = gcry_mpi_gcd (gcdtmp, e, yp0); - mpi_add_ui (yp0, yp0, 1); - if (!gcdres) - progress ('/'); /* gcd (e, yp0-1) != 1 */ - else if (check_prime (yp0, val_2, 64, NULL, NULL)) - break; /* Found. */ - /* We add p1p2-1 because yp0 is incremented after the gcd test. */ - mpi_add (yp0, yp0, p1p2); - } - mpi_free (gcdtmp); - mpi_free (val_2); - } - - mpi_free (p1p2); - - progress('\n'); - if (r_p1) - *r_p1 = p1; - else - mpi_free (p1); - if (r_p2) - *r_p2 = p2; - else - mpi_free (p2); - return yp0; -} - - - -/* Generate the two prime used for DSA using the algorithm specified - in FIPS 186-2. PBITS is the desired length of the prime P and a - QBITS the length of the prime Q. If SEED is not supplied and - SEEDLEN is 0 the function generates an appropriate SEED. On - success the generated primes are stored at R_Q and R_P, the counter - value is stored at R_COUNTER and the seed actually used for - generation is stored at R_SEED and R_SEEDVALUE. */ -gpg_err_code_t -_gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, - const void *seed, size_t seedlen, - gcry_mpi_t *r_q, gcry_mpi_t *r_p, - int *r_counter, - void **r_seed, size_t *r_seedlen) -{ - gpg_err_code_t ec; - unsigned char seed_help_buffer[160/8]; /* Used to hold a generated SEED. */ - unsigned char *seed_plus; /* Malloced buffer to hold SEED+x. */ - unsigned char digest[160/8]; /* Helper buffer for SHA-1 digest. */ - gcry_mpi_t val_2 = NULL; /* Helper for the prime test. */ - gcry_mpi_t tmpval = NULL; /* Helper variable. */ - int i; - - unsigned char value_u[160/8]; - int value_n, value_b, value_k; - int counter; - gcry_mpi_t value_w = NULL; - gcry_mpi_t value_x = NULL; - gcry_mpi_t prime_q = NULL; - gcry_mpi_t prime_p = NULL; - - /* FIPS 186-2 allows only for 1024/160 bit. */ - if (pbits != 1024 || qbits != 160) - return GPG_ERR_INV_KEYLEN; - - if (!seed && !seedlen) - ; /* No seed value given: We are asked to generate it. */ - else if (!seed || seedlen < qbits/8) - return GPG_ERR_INV_ARG; - - /* Allocate a buffer to later compute SEED+some_increment. */ - seed_plus = gcry_malloc (seedlen < 20? 20:seedlen); - if (!seed_plus) - { - ec = gpg_err_code_from_syserror (); - goto leave; - } - - val_2 = mpi_alloc_set_ui (2); - value_n = (pbits - 1) / qbits; - value_b = (pbits - 1) - value_n * qbits; - value_w = gcry_mpi_new (pbits); - value_x = gcry_mpi_new (pbits); - - restart: - /* Generate Q. */ - for (;;) - { - /* Step 1: Generate a (new) seed unless one has been supplied. */ - if (!seed) - { - seedlen = sizeof seed_help_buffer; - gcry_create_nonce (seed_help_buffer, seedlen); - seed = seed_help_buffer; - } - - /* Step 2: U = sha1(seed) ^ sha1((seed+1) mod 2^{qbits}) */ - memcpy (seed_plus, seed, seedlen); - for (i=seedlen-1; i >= 0; i--) - { - seed_plus[i]++; - if (seed_plus[i]) - break; - } - gcry_md_hash_buffer (GCRY_MD_SHA1, value_u, seed, seedlen); - gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); - for (i=0; i < sizeof value_u; i++) - value_u[i] ^= digest[i]; - - /* Step 3: Form q from U */ - gcry_mpi_release (prime_q); prime_q = NULL; - ec = gpg_err_code (gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, - value_u, sizeof value_u, NULL)); - if (ec) - goto leave; - mpi_set_highbit (prime_q, qbits-1 ); - mpi_set_bit (prime_q, 0); - - /* Step 4: Test whether Q is prime using 64 round of Rabin-Miller. */ - if (check_prime (prime_q, val_2, 64, NULL, NULL)) - break; /* Yes, Q is prime. */ - - /* Step 5. */ - seed = NULL; /* Force a new seed at Step 1. */ - } - - /* Step 6. Note that we do no use an explicit offset but increment - SEED_PLUS accordingly. SEED_PLUS is currently SEED+1. */ - counter = 0; - - /* Generate P. */ - prime_p = gcry_mpi_new (pbits); - for (;;) - { - /* Step 7: For k = 0,...n let - V_k = sha1(seed+offset+k) mod 2^{qbits} - Step 8: W = V_0 + V_1*2^160 + - ... - + V_{n-1}*2^{(n-1)*160} - + (V_{n} mod 2^b)*2^{n*160} - */ - mpi_set_ui (value_w, 0); - for (value_k=0; value_k <= value_n; value_k++) - { - /* There is no need to have an explicit offset variable: In - the first round we shall have an offset of 2, this is - achieved by using SEED_PLUS which is already at SEED+1, - thus we just need to increment it once again. The - requirement for the next round is to update offset by N, - which we implictly did at the end of this loop, and then - to add one; this one is the same as in the first round. */ - for (i=seedlen-1; i >= 0; i--) - { - seed_plus[i]++; - if (seed_plus[i]) - break; - } - gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); - - gcry_mpi_release (tmpval); tmpval = NULL; - ec = gpg_err_code (gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, - digest, sizeof digest, NULL)); - if (ec) - goto leave; - if (value_k == value_n) - mpi_clear_highbit (tmpval, value_b); /* (V_n mod 2^b) */ - mpi_lshift (tmpval, tmpval, value_k*qbits); - mpi_add (value_w, value_w, tmpval); - } - - /* Step 8 continued: X = W + 2^{L-1} */ - mpi_set_ui (value_x, 0); - mpi_set_highbit (value_x, pbits-1); - mpi_add (value_x, value_x, value_w); - - /* Step 9: c = X mod 2q, p = X - (c - 1) */ - mpi_mul_2exp (tmpval, prime_q, 1); - mpi_mod (tmpval, value_x, tmpval); - mpi_sub_ui (tmpval, tmpval, 1); - mpi_sub (prime_p, value_x, tmpval); - - /* Step 10: If p < 2^{L-1} skip the primality test. */ - /* Step 11 and 12: Primality test. */ - if (mpi_get_nbits (prime_p) >= pbits-1 - && check_prime (prime_p, val_2, 64, NULL, NULL) ) - break; /* Yes, P is prime, continue with Step 15. */ - - /* Step 13: counter = counter + 1, offset = offset + n + 1. */ - counter++; - - /* Step 14: If counter >= 2^12 goto Step 1. */ - if (counter >= 4096) - goto restart; - } - - /* Step 15: Save p, q, counter and seed. */ -/* log_debug ("fips186-2 pbits p=%u q=%u counter=%d\n", */ -/* mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); */ -/* log_printhex("fips186-2 seed:", seed, seedlen); */ -/* log_mpidump ("fips186-2 prime p", prime_p); */ -/* log_mpidump ("fips186-2 prime q", prime_q); */ - if (r_q) - { - *r_q = prime_q; - prime_q = NULL; - } - if (r_p) - { - *r_p = prime_p; - prime_p = NULL; - } - if (r_counter) - *r_counter = counter; - if (r_seed && r_seedlen) - { - memcpy (seed_plus, seed, seedlen); - *r_seed = seed_plus; - seed_plus = NULL; - *r_seedlen = seedlen; - } - - - leave: - gcry_mpi_release (tmpval); - gcry_mpi_release (value_x); - gcry_mpi_release (value_w); - gcry_mpi_release (prime_p); - gcry_mpi_release (prime_q); - gcry_free (seed_plus); - gcry_mpi_release (val_2); - return ec; -} - - - -/* WARNING: The code below has not yet been tested! However, it is - not yet used. We need to wait for FIPS 186-3 final and for test - vectors. - - Generate the two prime used for DSA using the algorithm specified - in FIPS 186-3, A.1.1.2. PBITS is the desired length of the prime P - and a QBITS the length of the prime Q. If SEED is not supplied and - SEEDLEN is 0 the function generates an appropriate SEED. On - success the generated primes are stored at R_Q and R_P, the counter - value is stored at R_COUNTER and the seed actually used for - generation is stored at R_SEED and R_SEEDVALUE. The hash algorithm - used is stored at R_HASHALGO. - - Note that this function is very similar to the fips186_2 code. Due - to the minor differences, other buffer sizes and for documentarion, - we use a separate function. -*/ -gpg_err_code_t -_gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, - const void *seed, size_t seedlen, - gcry_mpi_t *r_q, gcry_mpi_t *r_p, - int *r_counter, - void **r_seed, size_t *r_seedlen, - int *r_hashalgo) -{ - gpg_err_code_t ec; - unsigned char seed_help_buffer[256/8]; /* Used to hold a generated SEED. */ - unsigned char *seed_plus; /* Malloced buffer to hold SEED+x. */ - unsigned char digest[256/8]; /* Helper buffer for SHA-1 digest. */ - gcry_mpi_t val_2 = NULL; /* Helper for the prime test. */ - gcry_mpi_t tmpval = NULL; /* Helper variable. */ - int hashalgo; /* The id of the Approved Hash Function. */ - int i; - - unsigned char value_u[256/8]; - int value_n, value_b, value_j; - int counter; - gcry_mpi_t value_w = NULL; - gcry_mpi_t value_x = NULL; - gcry_mpi_t prime_q = NULL; - gcry_mpi_t prime_p = NULL; - - gcry_assert (sizeof seed_help_buffer == sizeof digest - && sizeof seed_help_buffer == sizeof value_u); - - /* Step 1: Check the requested prime lengths. */ - /* Note that due to the size of our buffers QBITS is limited to 256. */ - if (pbits == 1024 && qbits == 160) - hashalgo = GCRY_MD_SHA1; - else if (pbits == 2048 && qbits == 224) - hashalgo = GCRY_MD_SHA224; - else if (pbits == 2048 && qbits == 256) - hashalgo = GCRY_MD_SHA256; - else if (pbits == 3072 && qbits == 256) - hashalgo = GCRY_MD_SHA256; - else - return GPG_ERR_INV_KEYLEN; - - /* Also check that the hash algorithm is available. */ - ec = gpg_err_code (gcry_md_test_algo (hashalgo)); - if (ec) - return ec; - gcry_assert (qbits/8 <= sizeof digest); - gcry_assert (gcry_md_get_algo_dlen (hashalgo) == qbits/8); - - - /* Step 2: Check seedlen. */ - if (!seed && !seedlen) - ; /* No seed value given: We are asked to generate it. */ - else if (!seed || seedlen < qbits/8) - return GPG_ERR_INV_ARG; - - /* Allocate a buffer to later compute SEED+some_increment and a few - helper variables. */ - seed_plus = gcry_malloc (seedlen < sizeof seed_help_buffer? - sizeof seed_help_buffer : seedlen); - if (!seed_plus) - { - ec = gpg_err_code_from_syserror (); - goto leave; - } - val_2 = mpi_alloc_set_ui (2); - value_w = gcry_mpi_new (pbits); - value_x = gcry_mpi_new (pbits); - - /* Step 3: n = \lceil L / outlen \rceil - 1 */ - value_n = (pbits + qbits - 1) / qbits - 1; - /* Step 4: b = L - 1 - (n * outlen) */ - value_b = pbits - 1 - (value_n * qbits); - - restart: - /* Generate Q. */ - for (;;) - { - /* Step 5: Generate a (new) seed unless one has been supplied. */ - if (!seed) - { - seedlen = qbits/8; - gcry_assert (seedlen <= sizeof seed_help_buffer); - gcry_create_nonce (seed_help_buffer, seedlen); - seed = seed_help_buffer; - } - - /* Step 6: U = hash(seed) */ - gcry_md_hash_buffer (hashalgo, value_u, seed, seedlen); - - /* Step 7: q = 2^{N-1} + U + 1 - (U mod 2) */ - if ( !(value_u[qbits/8-1] & 0x01) ) - { - for (i=qbits/8-1; i >= 0; i--) - { - value_u[i]++; - if (value_u[i]) - break; - } - } - gcry_mpi_release (prime_q); prime_q = NULL; - ec = gpg_err_code (gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, - value_u, sizeof value_u, NULL)); - if (ec) - goto leave; - mpi_set_highbit (prime_q, qbits-1 ); - - /* Step 8: Test whether Q is prime using 64 round of Rabin-Miller. - According to table C.1 this is sufficient for all - supported prime sizes (i.e. up 3072/256). */ - if (check_prime (prime_q, val_2, 64, NULL, NULL)) - break; /* Yes, Q is prime. */ - - /* Step 8. */ - seed = NULL; /* Force a new seed at Step 5. */ - } - - /* Step 11. Note that we do no use an explicit offset but increment - SEED_PLUS accordingly. */ - memcpy (seed_plus, seed, seedlen); - counter = 0; - - /* Generate P. */ - prime_p = gcry_mpi_new (pbits); - for (;;) - { - /* Step 11.1: For j = 0,...n let - V_j = hash(seed+offset+j) - Step 11.2: W = V_0 + V_1*2^outlen + - ... - + V_{n-1}*2^{(n-1)*outlen} - + (V_{n} mod 2^b)*2^{n*outlen} - */ - mpi_set_ui (value_w, 0); - for (value_j=0; value_j <= value_n; value_j++) - { - /* There is no need to have an explicit offset variable: In - the first round we shall have an offset of 1 and a j of - 0. This is achieved by incrementing SEED_PLUS here. For - the next round offset is implicitly updated by using - SEED_PLUS again. */ - for (i=seedlen-1; i >= 0; i--) - { - seed_plus[i]++; - if (seed_plus[i]) - break; - } - gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); - - gcry_mpi_release (tmpval); tmpval = NULL; - ec = gpg_err_code (gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, - digest, sizeof digest, NULL)); - if (ec) - goto leave; - if (value_j == value_n) - mpi_clear_highbit (tmpval, value_b); /* (V_n mod 2^b) */ - mpi_lshift (tmpval, tmpval, value_j*qbits); - mpi_add (value_w, value_w, tmpval); - } - - /* Step 11.3: X = W + 2^{L-1} */ - mpi_set_ui (value_x, 0); - mpi_set_highbit (value_x, pbits-1); - mpi_add (value_x, value_x, value_w); - - /* Step 11.4: c = X mod 2q */ - mpi_mul_2exp (tmpval, prime_q, 1); - mpi_mod (tmpval, value_x, tmpval); - - /* Step 11.5: p = X - (c - 1) */ - mpi_sub_ui (tmpval, tmpval, 1); - mpi_sub (prime_p, value_x, tmpval); - - /* Step 11.6: If p < 2^{L-1} skip the primality test. */ - /* Step 11.7 and 11.8: Primality test. */ - if (mpi_get_nbits (prime_p) >= pbits-1 - && check_prime (prime_p, val_2, 64, NULL, NULL) ) - break; /* Yes, P is prime, continue with Step 15. */ - - /* Step 11.9: counter = counter + 1, offset = offset + n + 1. - If counter >= 4L goto Step 5. */ - counter++; - if (counter >= 4*pbits) - goto restart; - } - - /* Step 12: Save p, q, counter and seed. */ - log_debug ("fips186-3 pbits p=%u q=%u counter=%d\n", - mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); - log_printhex("fips186-3 seed:", seed, seedlen); - log_mpidump ("fips186-3 prime p", prime_p); - log_mpidump ("fips186-3 prime q", prime_q); - if (r_q) - { - *r_q = prime_q; - prime_q = NULL; - } - if (r_p) - { - *r_p = prime_p; - prime_p = NULL; - } - if (r_counter) - *r_counter = counter; - if (r_seed && r_seedlen) - { - memcpy (seed_plus, seed, seedlen); - *r_seed = seed_plus; - seed_plus = NULL; - *r_seedlen = seedlen; - } - if (r_hashalgo) - *r_hashalgo = hashalgo; - - leave: - gcry_mpi_release (tmpval); - gcry_mpi_release (value_x); - gcry_mpi_release (value_w); - gcry_mpi_release (prime_p); - gcry_mpi_release (prime_q); - gcry_free (seed_plus); - gcry_mpi_release (val_2); - return ec; -} - +/* primegen.c - prime number generator + * Copyright (C) 1998, 2000, 2001, 2002, 2003 + * 2004, 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "ath.h" + +static gcry_mpi_t gen_prime (unsigned int nbits, int secret, int randomlevel, + int (*extra_check)(void *, gcry_mpi_t), + void *extra_check_arg); +static int check_prime( gcry_mpi_t prime, gcry_mpi_t val_2, int rm_rounds, + gcry_prime_check_func_t cb_func, void *cb_arg ); +static int is_prime (gcry_mpi_t n, int steps, unsigned int *count); +static void m_out_of_n( char *array, int m, int n ); + +static void (*progress_cb) (void *,const char*,int,int, int ); +static void *progress_cb_data; + +/* Note: 2 is not included because it can be tested more easily by + looking at bit 0. The last entry in this list is marked by a zero */ +static ushort small_prime_numbers[] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, + 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, + 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, + 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, + 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, + 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, + 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, + 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, + 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, + 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, + 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, + 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, + 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, + 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, + 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, + 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, + 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, + 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, + 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, + 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, + 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, + 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, + 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, + 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, + 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, + 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, + 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, + 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, + 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, + 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, + 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, + 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, + 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, + 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, + 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, + 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, + 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, + 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, + 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, + 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, + 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, + 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, + 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, + 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, + 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, + 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, + 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, + 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, + 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, + 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, + 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, + 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, + 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, + 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, + 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, + 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, + 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, + 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, + 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, + 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, + 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, + 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, + 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, + 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, + 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, + 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, + 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, + 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, + 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, + 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, + 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, + 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, + 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, + 4957, 4967, 4969, 4973, 4987, 4993, 4999, + 0 +}; +static int no_of_small_prime_numbers = DIM (small_prime_numbers) - 1; + + + +/* An object and a list to build up a global pool of primes. See + save_pool_prime and get_pool_prime. */ +struct primepool_s +{ + struct primepool_s *next; + gcry_mpi_t prime; /* If this is NULL the entry is not used. */ + unsigned int nbits; + gcry_random_level_t randomlevel; +}; +struct primepool_s *primepool; +/* Mutex used to protect access to the primepool. */ +static ath_mutex_t primepool_lock = ATH_MUTEX_INITIALIZER; + + + +/* Save PRIME which has been generated at RANDOMLEVEL for later + use. Needs to be called while primepool_lock is being hold. Note + that PRIME should be considered released after calling this + function. */ +static void +save_pool_prime (gcry_mpi_t prime, gcry_random_level_t randomlevel) +{ + struct primepool_s *item, *item2; + size_t n; + + for (n=0, item = primepool; item; item = item->next, n++) + if (!item->prime) + break; + if (!item && n > 100) + { + /* Remove some of the entries. Our strategy is removing + the last third from the list. */ + int i; + + for (i=0, item2 = primepool; item2; item2 = item2->next) + { + if (i >= n/3*2) + { + gcry_mpi_release (item2->prime); + item2->prime = NULL; + if (!item) + item = item2; + } + } + } + if (!item) + { + item = gcry_calloc (1, sizeof *item); + if (!item) + { + /* Out of memory. Silently giving up. */ + gcry_mpi_release (prime); + return; + } + item->next = primepool; + primepool = item; + } + item->prime = prime; + item->nbits = mpi_get_nbits (prime); + item->randomlevel = randomlevel; +} + + +/* Return a prime for the prime pool or NULL if none has been found. + The prime needs to match NBITS and randomlevel. This function needs + to be called why the primepool_look is being hold. */ +static gcry_mpi_t +get_pool_prime (unsigned int nbits, gcry_random_level_t randomlevel) +{ + struct primepool_s *item; + + for (item = primepool; item; item = item->next) + if (item->prime + && item->nbits == nbits && item->randomlevel == randomlevel) + { + gcry_mpi_t prime = item->prime; + item->prime = NULL; + gcry_assert (nbits == mpi_get_nbits (prime)); + return prime; + } + return NULL; +} + + + + + + +void +_gcry_register_primegen_progress ( void (*cb)(void *,const char*,int,int,int), + void *cb_data ) +{ + progress_cb = cb; + progress_cb_data = cb_data; +} + + +static void +progress( int c ) +{ + if ( progress_cb ) + progress_cb ( progress_cb_data, "primegen", c, 0, 0 ); +} + + +/**************** + * Generate a prime number (stored in secure memory) + */ +gcry_mpi_t +_gcry_generate_secret_prime (unsigned int nbits, + gcry_random_level_t random_level, + int (*extra_check)(void*, gcry_mpi_t), + void *extra_check_arg) +{ + gcry_mpi_t prime; + + prime = gen_prime (nbits, 1, random_level, extra_check, extra_check_arg); + progress('\n'); + return prime; +} + + +/* Generate a prime number which may be public, i.e. not allocated in + secure memory. */ +gcry_mpi_t +_gcry_generate_public_prime (unsigned int nbits, + gcry_random_level_t random_level, + int (*extra_check)(void*, gcry_mpi_t), + void *extra_check_arg) +{ + gcry_mpi_t prime; + + prime = gen_prime (nbits, 0, random_level, extra_check, extra_check_arg); + progress('\n'); + return prime; +} + + +/* Core prime generation function. The algorithm used to generate + practically save primes is due to Lim and Lee as described in the + CRYPTO '97 proceedings (ISBN3540633847) page 260. + + NEED_Q_FACTOR: If true make sure that at least one factor is of + size qbits. This is for example required for DSA. + PRIME_GENERATED: Adresss of a variable where the resulting prime + number will be stored. + PBITS: Requested size of the prime number. At least 48. + QBITS: One factor of the prime needs to be of this size. Maybe 0 + if this is not required. See also MODE. + G: If not NULL an MPI which will receive a generator for the prime + for use with Elgamal. + RET_FACTORS: if not NULL, an array with all factors are stored at + that address. + ALL_FACTORS: If set to true all factors of prime-1 are returned. + RANDOMLEVEL: How strong should the random numers be. + FLAGS: Prime generation bit flags. Currently supported: + GCRY_PRIME_FLAG_SECRET - The prime needs to be kept secret. + CB_FUNC, CB_ARG: Callback to be used for extra checks. + + */ +static gcry_err_code_t +prime_generate_internal (int need_q_factor, + gcry_mpi_t *prime_generated, unsigned int pbits, + unsigned int qbits, gcry_mpi_t g, + gcry_mpi_t **ret_factors, + gcry_random_level_t randomlevel, unsigned int flags, + int all_factors, + gcry_prime_check_func_t cb_func, void *cb_arg) +{ + gcry_err_code_t err = 0; + gcry_mpi_t *factors_new = NULL; /* Factors to return to the + caller. */ + gcry_mpi_t *factors = NULL; /* Current factors. */ + gcry_random_level_t poolrandomlevel; /* Random level used for pool primes. */ + gcry_mpi_t *pool = NULL; /* Pool of primes. */ + int *pool_in_use = NULL; /* Array with currently used POOL elements. */ + unsigned char *perms = NULL; /* Permutations of POOL. */ + gcry_mpi_t q_factor = NULL; /* Used if QBITS is non-zero. */ + unsigned int fbits = 0; /* Length of prime factors. */ + unsigned int n = 0; /* Number of factors. */ + unsigned int m = 0; /* Number of primes in pool. */ + gcry_mpi_t q = NULL; /* First prime factor. */ + gcry_mpi_t prime = NULL; /* Prime candidate. */ + unsigned int nprime = 0; /* Bits of PRIME. */ + unsigned int req_qbits; /* The original QBITS value. */ + gcry_mpi_t val_2; /* For check_prime(). */ + int is_locked = 0; /* Flag to help unlocking the primepool. */ + unsigned int is_secret = (flags & GCRY_PRIME_FLAG_SECRET); + unsigned int count1 = 0, count2 = 0; + unsigned int i = 0, j = 0; + + if (pbits < 48) + return GPG_ERR_INV_ARG; + + /* We won't use a too strong random elvel for the pooled subprimes. */ + poolrandomlevel = (randomlevel > GCRY_STRONG_RANDOM? + GCRY_STRONG_RANDOM : randomlevel); + + + /* If QBITS is not given, assume a reasonable value. */ + if (!qbits) + qbits = pbits / 3; + + req_qbits = qbits; + + /* Find number of needed prime factors N. */ + for (n = 1; (pbits - qbits - 1) / n >= qbits; n++) + ; + n--; + + val_2 = mpi_alloc_set_ui (2); + + if ((! n) || ((need_q_factor) && (n < 2))) + { + err = GPG_ERR_INV_ARG; + goto leave; + } + + if (need_q_factor) + { + n--; /* Need one factor less because we want a specific Q-FACTOR. */ + fbits = (pbits - 2 * req_qbits -1) / n; + qbits = pbits - req_qbits - n * fbits; + } + else + { + fbits = (pbits - req_qbits -1) / n; + qbits = pbits - n * fbits; + } + + if (DBG_CIPHER) + log_debug ("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n", + pbits, req_qbits, qbits, fbits, n); + + /* Allocate an integer to old the new prime. */ + prime = gcry_mpi_new (pbits); + + /* Generate first prime factor. */ + q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); + + /* Generate a specific Q-Factor if requested. */ + if (need_q_factor) + q_factor = gen_prime (req_qbits, is_secret, randomlevel, NULL, NULL); + + /* Allocate an array to hold all factors + 2 for later usage. */ + factors = gcry_calloc (n + 2, sizeof (*factors)); + if (!factors) + { + err = gpg_err_code_from_errno (errno); + goto leave; + } + + /* Allocate an array to track pool usage. */ + pool_in_use = gcry_malloc (n * sizeof *pool_in_use); + if (!pool_in_use) + { + err = gpg_err_code_from_errno (errno); + goto leave; + } + for (i=0; i < n; i++) + pool_in_use[i] = -1; + + /* Make a pool of 3n+5 primes (this is an arbitrary value). We + require at least 30 primes for are useful selection process. + + Fixme: We need to research the best formula for sizing the pool. + */ + m = n * 3 + 5; + if (need_q_factor) /* Need some more in this case. */ + m += 5; + if (m < 30) + m = 30; + pool = gcry_calloc (m , sizeof (*pool)); + if (! pool) + { + err = gpg_err_code_from_errno (errno); + goto leave; + } + + /* Permutate over the pool of primes until we find a prime of the + requested length. */ + do + { + next_try: + for (i=0; i < n; i++) + pool_in_use[i] = -1; + + if (!perms) + { + /* Allocate new primes. This is done right at the beginning + of the loop and if we have later run out of primes. */ + for (i = 0; i < m; i++) + { + mpi_free (pool[i]); + pool[i] = NULL; + } + + /* Init m_out_of_n(). */ + perms = gcry_calloc (1, m); + if (!perms) + { + err = gpg_err_code_from_errno (errno); + goto leave; + } + + if (ath_mutex_lock (&primepool_lock)) + { + err = GPG_ERR_INTERNAL; + goto leave; + } + is_locked = 1; + for (i = 0; i < n; i++) + { + perms[i] = 1; + /* At a maximum we use strong random for the factors. + This saves us a lot of entropy. Given that Q and + possible Q-factor are also used in the final prime + this should be acceptable. We also don't allocate in + secure memory to save on that scare resource too. If + Q has been allocated in secure memory, the final + prime will be saved there anyway. This is because + our MPI routines take care of that. GnuPG has worked + this way ever since. */ + pool[i] = NULL; + if (is_locked) + { + pool[i] = get_pool_prime (fbits, poolrandomlevel); + if (!pool[i]) + { + if (ath_mutex_unlock (&primepool_lock)) + { + err = GPG_ERR_INTERNAL; + goto leave; + } + is_locked = 0; + } + } + if (!pool[i]) + pool[i] = gen_prime (fbits, 0, poolrandomlevel, NULL, NULL); + pool_in_use[i] = i; + factors[i] = pool[i]; + } + if (is_locked && ath_mutex_unlock (&primepool_lock)) + { + err = GPG_ERR_INTERNAL; + goto leave; + } + is_locked = 0; + } + else + { + /* Get next permutation. */ + m_out_of_n ( (char*)perms, n, m); + if (ath_mutex_lock (&primepool_lock)) + { + err = GPG_ERR_INTERNAL; + goto leave; + } + is_locked = 1; + for (i = j = 0; (i < m) && (j < n); i++) + if (perms[i]) + { + /* If the subprime has not yet beed generated do it now. */ + if (!pool[i] && is_locked) + { + pool[i] = get_pool_prime (fbits, poolrandomlevel); + if (!pool[i]) + { + if (ath_mutex_unlock (&primepool_lock)) + { + err = GPG_ERR_INTERNAL; + goto leave; + } + is_locked = 0; + } + } + if (!pool[i]) + pool[i] = gen_prime (fbits, 0, poolrandomlevel, NULL, NULL); + pool_in_use[j] = i; + factors[j++] = pool[i]; + } + if (is_locked && ath_mutex_unlock (&primepool_lock)) + { + err = GPG_ERR_INTERNAL; + goto leave; + } + is_locked = 0; + if (i == n) + { + /* Ran out of permutations: Allocate new primes. */ + gcry_free (perms); + perms = NULL; + progress ('!'); + goto next_try; + } + } + + /* Generate next prime candidate: + p = 2 * q [ * q_factor] * factor_0 * factor_1 * ... * factor_n + 1. + */ + mpi_set (prime, q); + mpi_mul_ui (prime, prime, 2); + if (need_q_factor) + mpi_mul (prime, prime, q_factor); + for(i = 0; i < n; i++) + mpi_mul (prime, prime, factors[i]); + mpi_add_ui (prime, prime, 1); + nprime = mpi_get_nbits (prime); + + if (nprime < pbits) + { + if (++count1 > 20) + { + count1 = 0; + qbits++; + progress('>'); + mpi_free (q); + q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); + goto next_try; + } + } + else + count1 = 0; + + if (nprime > pbits) + { + if (++count2 > 20) + { + count2 = 0; + qbits--; + progress('<'); + mpi_free (q); + q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); + goto next_try; + } + } + else + count2 = 0; + } + while (! ((nprime == pbits) && check_prime (prime, val_2, 5, + cb_func, cb_arg))); + + if (DBG_CIPHER) + { + progress ('\n'); + log_mpidump ("prime : ", prime); + log_mpidump ("factor q: ", q); + if (need_q_factor) + log_mpidump ("factor q0: ", q_factor); + for (i = 0; i < n; i++) + log_mpidump ("factor pi: ", factors[i]); + log_debug ("bit sizes: prime=%u, q=%u", + mpi_get_nbits (prime), mpi_get_nbits (q)); + if (need_q_factor) + log_debug (", q0=%u", mpi_get_nbits (q_factor)); + for (i = 0; i < n; i++) + log_debug (", p%d=%u", i, mpi_get_nbits (factors[i])); + progress('\n'); + } + + if (ret_factors) + { + /* Caller wants the factors. */ + factors_new = gcry_calloc (n + 4, sizeof (*factors_new)); + if (! factors_new) + { + err = gpg_err_code_from_errno (errno); + goto leave; + } + + if (all_factors) + { + i = 0; + factors_new[i++] = gcry_mpi_set_ui (NULL, 2); + factors_new[i++] = mpi_copy (q); + if (need_q_factor) + factors_new[i++] = mpi_copy (q_factor); + for(j=0; j < n; j++) + factors_new[i++] = mpi_copy (factors[j]); + } + else + { + i = 0; + if (need_q_factor) + { + factors_new[i++] = mpi_copy (q_factor); + for (; i <= n; i++) + factors_new[i] = mpi_copy (factors[i]); + } + else + for (; i < n; i++ ) + factors_new[i] = mpi_copy (factors[i]); + } + } + + if (g) + { + /* Create a generator (start with 3). */ + gcry_mpi_t tmp = mpi_alloc (mpi_get_nlimbs (prime)); + gcry_mpi_t b = mpi_alloc (mpi_get_nlimbs (prime)); + gcry_mpi_t pmin1 = mpi_alloc (mpi_get_nlimbs (prime)); + + if (need_q_factor) + err = GPG_ERR_NOT_IMPLEMENTED; + else + { + factors[n] = q; + factors[n + 1] = mpi_alloc_set_ui (2); + mpi_sub_ui (pmin1, prime, 1); + mpi_set_ui (g, 2); + do + { + mpi_add_ui (g, g, 1); + if (DBG_CIPHER) + { + log_debug ("checking g:"); + gcry_mpi_dump (g); + log_printf ("\n"); + } + else + progress('^'); + for (i = 0; i < n + 2; i++) + { + mpi_fdiv_q (tmp, pmin1, factors[i]); + /* No mpi_pow(), but it is okay to use this with mod + prime. */ + gcry_mpi_powm (b, g, tmp, prime); + if (! mpi_cmp_ui (b, 1)) + break; + } + if (DBG_CIPHER) + progress('\n'); + } + while (i < n + 2); + + mpi_free (factors[n+1]); + mpi_free (tmp); + mpi_free (b); + mpi_free (pmin1); + } + } + + if (! DBG_CIPHER) + progress ('\n'); + + + leave: + if (pool) + { + is_locked = !ath_mutex_lock (&primepool_lock); + for(i = 0; i < m; i++) + { + if (pool[i]) + { + for (j=0; j < n; j++) + if (pool_in_use[j] == i) + break; + if (j == n && is_locked) + { + /* This pooled subprime has not been used. */ + save_pool_prime (pool[i], poolrandomlevel); + } + else + mpi_free (pool[i]); + } + } + if (is_locked && ath_mutex_unlock (&primepool_lock)) + err = GPG_ERR_INTERNAL; + is_locked = 0; + gcry_free (pool); + } + gcry_free (pool_in_use); + if (factors) + gcry_free (factors); /* Factors are shallow copies. */ + if (perms) + gcry_free (perms); + + mpi_free (val_2); + mpi_free (q); + mpi_free (q_factor); + + if (! err) + { + *prime_generated = prime; + if (ret_factors) + *ret_factors = factors_new; + } + else + { + if (factors_new) + { + for (i = 0; factors_new[i]; i++) + mpi_free (factors_new[i]); + gcry_free (factors_new); + } + mpi_free (prime); + } + + return err; +} + + +/* Generate a prime used for discrete logarithm algorithms; i.e. this + prime will be public and no strong random is required. */ +gcry_mpi_t +_gcry_generate_elg_prime (int mode, unsigned pbits, unsigned qbits, + gcry_mpi_t g, gcry_mpi_t **ret_factors) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_mpi_t prime = NULL; + + err = prime_generate_internal ((mode == 1), &prime, pbits, qbits, g, + ret_factors, GCRY_WEAK_RANDOM, 0, 0, + NULL, NULL); + + return prime; +} + + +static gcry_mpi_t +gen_prime (unsigned int nbits, int secret, int randomlevel, + int (*extra_check)(void *, gcry_mpi_t), void *extra_check_arg) +{ + gcry_mpi_t prime, ptest, pminus1, val_2, val_3, result; + int i; + unsigned int x, step; + unsigned int count1, count2; + int *mods; + +/* if ( DBG_CIPHER ) */ +/* log_debug ("generate a prime of %u bits ", nbits ); */ + + if (nbits < 16) + log_fatal ("can't generate a prime with less than %d bits\n", 16); + + mods = gcry_xmalloc( no_of_small_prime_numbers * sizeof *mods ); + /* Make nbits fit into gcry_mpi_t implementation. */ + val_2 = mpi_alloc_set_ui( 2 ); + val_3 = mpi_alloc_set_ui( 3); + prime = secret? gcry_mpi_snew ( nbits ): gcry_mpi_new ( nbits ); + result = mpi_alloc_like( prime ); + pminus1= mpi_alloc_like( prime ); + ptest = mpi_alloc_like( prime ); + count1 = count2 = 0; + for (;;) + { /* try forvever */ + int dotcount=0; + + /* generate a random number */ + gcry_mpi_randomize( prime, nbits, randomlevel ); + + /* Set high order bit to 1, set low order bit to 1. If we are + generating a secret prime we are most probably doing that + for RSA, to make sure that the modulus does have the + requested key size we set the 2 high order bits. */ + mpi_set_highbit (prime, nbits-1); + if (secret) + mpi_set_bit (prime, nbits-2); + mpi_set_bit(prime, 0); + + /* Calculate all remainders. */ + for (i=0; (x = small_prime_numbers[i]); i++ ) + mods[i] = mpi_fdiv_r_ui(NULL, prime, x); + + /* Now try some primes starting with prime. */ + for(step=0; step < 20000; step += 2 ) + { + /* Check against all the small primes we have in mods. */ + count1++; + for (i=0; (x = small_prime_numbers[i]); i++ ) + { + while ( mods[i] + step >= x ) + mods[i] -= x; + if ( !(mods[i] + step) ) + break; + } + if ( x ) + continue; /* Found a multiple of an already known prime. */ + + mpi_add_ui( ptest, prime, step ); + + /* Do a fast Fermat test now. */ + count2++; + mpi_sub_ui( pminus1, ptest, 1); + gcry_mpi_powm( result, val_2, pminus1, ptest ); + if ( !mpi_cmp_ui( result, 1 ) ) + { + /* Not composite, perform stronger tests */ + if (is_prime(ptest, 5, &count2 )) + { + if (!mpi_test_bit( ptest, nbits-1-secret )) + { + progress('\n'); + log_debug ("overflow in prime generation\n"); + break; /* Stop loop, continue with a new prime. */ + } + + if (extra_check && extra_check (extra_check_arg, ptest)) + { + /* The extra check told us that this prime is + not of the caller's taste. */ + progress ('/'); + } + else + { + /* Got it. */ + mpi_free(val_2); + mpi_free(val_3); + mpi_free(result); + mpi_free(pminus1); + mpi_free(prime); + gcry_free(mods); + return ptest; + } + } + } + if (++dotcount == 10 ) + { + progress('.'); + dotcount = 0; + } + } + progress(':'); /* restart with a new random value */ + } +} + +/**************** + * Returns: true if this may be a prime + * RM_ROUNDS gives the number of Rabin-Miller tests to run. + */ +static int +check_prime( gcry_mpi_t prime, gcry_mpi_t val_2, int rm_rounds, + gcry_prime_check_func_t cb_func, void *cb_arg) +{ + int i; + unsigned int x; + unsigned int count=0; + + /* Check against small primes. */ + for (i=0; (x = small_prime_numbers[i]); i++ ) + { + if ( mpi_divisible_ui( prime, x ) ) + return 0; + } + + /* A quick Fermat test. */ + { + gcry_mpi_t result = mpi_alloc_like( prime ); + gcry_mpi_t pminus1 = mpi_alloc_like( prime ); + mpi_sub_ui( pminus1, prime, 1); + gcry_mpi_powm( result, val_2, pminus1, prime ); + mpi_free( pminus1 ); + if ( mpi_cmp_ui( result, 1 ) ) + { + /* Is composite. */ + mpi_free( result ); + progress('.'); + return 0; + } + mpi_free( result ); + } + + if (!cb_func || cb_func (cb_arg, GCRY_PRIME_CHECK_AT_MAYBE_PRIME, prime)) + { + /* Perform stronger tests. */ + if ( is_prime( prime, rm_rounds, &count ) ) + { + if (!cb_func + || cb_func (cb_arg, GCRY_PRIME_CHECK_AT_GOT_PRIME, prime)) + return 1; /* Probably a prime. */ + } + } + progress('.'); + return 0; +} + + +/* + * Return true if n is probably a prime + */ +static int +is_prime (gcry_mpi_t n, int steps, unsigned int *count) +{ + gcry_mpi_t x = mpi_alloc( mpi_get_nlimbs( n ) ); + gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs( n ) ); + gcry_mpi_t z = mpi_alloc( mpi_get_nlimbs( n ) ); + gcry_mpi_t nminus1 = mpi_alloc( mpi_get_nlimbs( n ) ); + gcry_mpi_t a2 = mpi_alloc_set_ui( 2 ); + gcry_mpi_t q; + unsigned i, j, k; + int rc = 0; + unsigned nbits = mpi_get_nbits( n ); + + if (steps < 5) /* Make sure that we do at least 5 rounds. */ + steps = 5; + + mpi_sub_ui( nminus1, n, 1 ); + + /* Find q and k, so that n = 1 + 2^k * q . */ + q = mpi_copy ( nminus1 ); + k = mpi_trailing_zeros ( q ); + mpi_tdiv_q_2exp (q, q, k); + + for (i=0 ; i < steps; i++ ) + { + ++*count; + if( !i ) + { + mpi_set_ui( x, 2 ); + } + else + { + gcry_mpi_randomize( x, nbits, GCRY_WEAK_RANDOM ); + + /* Make sure that the number is smaller than the prime and + keep the randomness of the high bit. */ + if ( mpi_test_bit ( x, nbits-2) ) + { + mpi_set_highbit ( x, nbits-2); /* Clear all higher bits. */ + } + else + { + mpi_set_highbit( x, nbits-2 ); + mpi_clear_bit( x, nbits-2 ); + } + gcry_assert (mpi_cmp (x, nminus1) < 0 && mpi_cmp_ui (x, 1) > 0); + } + gcry_mpi_powm ( y, x, q, n); + if ( mpi_cmp_ui(y, 1) && mpi_cmp( y, nminus1 ) ) + { + for ( j=1; j < k && mpi_cmp( y, nminus1 ); j++ ) + { + gcry_mpi_powm(y, y, a2, n); + if( !mpi_cmp_ui( y, 1 ) ) + goto leave; /* Not a prime. */ + } + if (mpi_cmp( y, nminus1 ) ) + goto leave; /* Not a prime. */ + } + progress('+'); + } + rc = 1; /* May be a prime. */ + + leave: + mpi_free( x ); + mpi_free( y ); + mpi_free( z ); + mpi_free( nminus1 ); + mpi_free( q ); + mpi_free( a2 ); + + return rc; +} + + +/* Given ARRAY of size N with M elements set to true produce a + modified array with the next permutation of M elements. Note, that + ARRAY is used in a one-bit-per-byte approach. To detected the last + permutation it is useful to initialize the array with the first M + element set to true and use this test: + m_out_of_n (array, m, n); + for (i = j = 0; i < n && j < m; i++) + if (array[i]) + j++; + if (j == m) + goto ready; + + This code is based on the algorithm 452 from the "Collected + Algorithms From ACM, Volume II" by C. N. Liu and D. T. Tang. +*/ +static void +m_out_of_n ( char *array, int m, int n ) +{ + int i=0, i1=0, j=0, jp=0, j1=0, k1=0, k2=0; + + if( !m || m >= n ) + return; + + /* Need to handle this simple case separately. */ + if( m == 1 ) + { + for (i=0; i < n; i++ ) + { + if ( array[i] ) + { + array[i++] = 0; + if( i >= n ) + i = 0; + array[i] = 1; + return; + } + } + BUG(); + } + + + for (j=1; j < n; j++ ) + { + if ( array[n-1] == array[n-j-1]) + continue; + j1 = j; + break; + } + + if ( (m & 1) ) + { + /* M is odd. */ + if( array[n-1] ) + { + if( j1 & 1 ) + { + k1 = n - j1; + k2 = k1+2; + if( k2 > n ) + k2 = n; + goto leave; + } + goto scan; + } + k2 = n - j1 - 1; + if( k2 == 0 ) + { + k1 = i; + k2 = n - j1; + } + else if( array[k2] && array[k2-1] ) + k1 = n; + else + k1 = k2 + 1; + } + else + { + /* M is even. */ + if( !array[n-1] ) + { + k1 = n - j1; + k2 = k1 + 1; + goto leave; + } + + if( !(j1 & 1) ) + { + k1 = n - j1; + k2 = k1+2; + if( k2 > n ) + k2 = n; + goto leave; + } + scan: + jp = n - j1 - 1; + for (i=1; i <= jp; i++ ) + { + i1 = jp + 2 - i; + if( array[i1-1] ) + { + if( array[i1-2] ) + { + k1 = i1 - 1; + k2 = n - j1; + } + else + { + k1 = i1 - 1; + k2 = n + 1 - j1; + } + goto leave; + } + } + k1 = 1; + k2 = n + 1 - m; + } + leave: + /* Now complement the two selected bits. */ + array[k1-1] = !array[k1-1]; + array[k2-1] = !array[k2-1]; +} + + +/* Generate a new prime number of PRIME_BITS bits and store it in + PRIME. If FACTOR_BITS is non-zero, one of the prime factors of + (prime - 1) / 2 must be FACTOR_BITS bits long. If FACTORS is + non-zero, allocate a new, NULL-terminated array holding the prime + factors and store it in FACTORS. FLAGS might be used to influence + the prime number generation process. */ +gcry_error_t +gcry_prime_generate (gcry_mpi_t *prime, unsigned int prime_bits, + unsigned int factor_bits, gcry_mpi_t **factors, + gcry_prime_check_func_t cb_func, void *cb_arg, + gcry_random_level_t random_level, + unsigned int flags) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_mpi_t *factors_generated = NULL; + gcry_mpi_t prime_generated = NULL; + unsigned int mode = 0; + + if (!prime) + return gpg_error (GPG_ERR_INV_ARG); + *prime = NULL; + + if (flags & GCRY_PRIME_FLAG_SPECIAL_FACTOR) + mode = 1; + + /* Generate. */ + err = prime_generate_internal ((mode==1), &prime_generated, prime_bits, + factor_bits, NULL, + factors? &factors_generated : NULL, + random_level, flags, 1, + cb_func, cb_arg); + + if (! err) + if (cb_func) + { + /* Additional check. */ + if ( !cb_func (cb_arg, GCRY_PRIME_CHECK_AT_FINISH, prime_generated)) + { + /* Failed, deallocate resources. */ + unsigned int i; + + mpi_free (prime_generated); + if (factors) + { + for (i = 0; factors_generated[i]; i++) + mpi_free (factors_generated[i]); + gcry_free (factors_generated); + } + err = GPG_ERR_GENERAL; + } + } + + if (! err) + { + if (factors) + *factors = factors_generated; + *prime = prime_generated; + } + + return gcry_error (err); +} + +/* Check whether the number X is prime. */ +gcry_error_t +gcry_prime_check (gcry_mpi_t x, unsigned int flags) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_mpi_t val_2 = mpi_alloc_set_ui (2); /* Used by the Fermat test. */ + + (void)flags; + + /* We use 64 rounds because the prime we are going to test is not + guaranteed to be a random one. */ + if (! check_prime (x, val_2, 64, NULL, NULL)) + err = GPG_ERR_NO_PRIME; + + mpi_free (val_2); + + return gcry_error (err); +} + +/* Find a generator for PRIME where the factorization of (prime-1) is + in the NULL terminated array FACTORS. Return the generator as a + newly allocated MPI in R_G. If START_G is not NULL, use this as s + atart for the search. Returns 0 on success.*/ +gcry_error_t +gcry_prime_group_generator (gcry_mpi_t *r_g, + gcry_mpi_t prime, gcry_mpi_t *factors, + gcry_mpi_t start_g) +{ + gcry_mpi_t tmp = gcry_mpi_new (0); + gcry_mpi_t b = gcry_mpi_new (0); + gcry_mpi_t pmin1 = gcry_mpi_new (0); + gcry_mpi_t g = start_g? gcry_mpi_copy (start_g) : gcry_mpi_set_ui (NULL, 3); + int first = 1; + int i, n; + + if (!factors || !r_g || !prime) + return gpg_error (GPG_ERR_INV_ARG); + *r_g = NULL; + + for (n=0; factors[n]; n++) + ; + if (n < 2) + return gpg_error (GPG_ERR_INV_ARG); + + /* Extra sanity check - usually disabled. */ +/* mpi_set (tmp, factors[0]); */ +/* for(i = 1; i < n; i++) */ +/* mpi_mul (tmp, tmp, factors[i]); */ +/* mpi_add_ui (tmp, tmp, 1); */ +/* if (mpi_cmp (prime, tmp)) */ +/* return gpg_error (GPG_ERR_INV_ARG); */ + + gcry_mpi_sub_ui (pmin1, prime, 1); + do + { + if (first) + first = 0; + else + gcry_mpi_add_ui (g, g, 1); + + if (DBG_CIPHER) + { + log_debug ("checking g:"); + gcry_mpi_dump (g); + log_debug ("\n"); + } + else + progress('^'); + + for (i = 0; i < n; i++) + { + mpi_fdiv_q (tmp, pmin1, factors[i]); + gcry_mpi_powm (b, g, tmp, prime); + if (! mpi_cmp_ui (b, 1)) + break; + } + if (DBG_CIPHER) + progress('\n'); + } + while (i < n); + + gcry_mpi_release (tmp); + gcry_mpi_release (b); + gcry_mpi_release (pmin1); + *r_g = g; + + return 0; +} + +/* Convenience function to release the factors array. */ +void +gcry_prime_release_factors (gcry_mpi_t *factors) +{ + if (factors) + { + int i; + + for (i=0; factors[i]; i++) + mpi_free (factors[i]); + gcry_free (factors); + } +} + + + +/* Helper for _gcry_derive_x931_prime. */ +static gcry_mpi_t +find_x931_prime (const gcry_mpi_t pfirst) +{ + gcry_mpi_t val_2 = mpi_alloc_set_ui (2); + gcry_mpi_t prime; + + prime = gcry_mpi_copy (pfirst); + /* If P is even add 1. */ + mpi_set_bit (prime, 0); + + /* We use 64 Rabin-Miller rounds which is better and thus + sufficient. We do not have a Lucas test implementaion thus we + can't do it in the X9.31 preferred way of running a few + Rabin-Miller followed by one Lucas test. */ + while ( !check_prime (prime, val_2, 64, NULL, NULL) ) + mpi_add_ui (prime, prime, 2); + + mpi_free (val_2); + + return prime; +} + + +/* Generate a prime using the algorithm from X9.31 appendix B.4. + + This function requires that the provided public exponent E is odd. + XP, XP1 and XP2 are the seed values. All values are mandatory. + + On success the prime is returned. If R_P1 or R_P2 are given the + internal values P1 and P2 are saved at these addresses. On error + NULL is returned. */ +gcry_mpi_t +_gcry_derive_x931_prime (const gcry_mpi_t xp, + const gcry_mpi_t xp1, const gcry_mpi_t xp2, + const gcry_mpi_t e, + gcry_mpi_t *r_p1, gcry_mpi_t *r_p2) +{ + gcry_mpi_t p1, p2, p1p2, yp0; + + if (!xp || !xp1 || !xp2) + return NULL; + if (!e || !mpi_test_bit (e, 0)) + return NULL; /* We support only odd values for E. */ + + p1 = find_x931_prime (xp1); + p2 = find_x931_prime (xp2); + p1p2 = mpi_alloc_like (xp); + mpi_mul (p1p2, p1, p2); + + { + gcry_mpi_t r1, tmp; + + /* r1 = (p2^{-1} mod p1)p2 - (p1^{-1} mod p2) */ + tmp = mpi_alloc_like (p1); + mpi_invm (tmp, p2, p1); + mpi_mul (tmp, tmp, p2); + r1 = tmp; + + tmp = mpi_alloc_like (p2); + mpi_invm (tmp, p1, p2); + mpi_mul (tmp, tmp, p1); + mpi_sub (r1, r1, tmp); + + /* Fixup a negative value. */ + if (mpi_is_neg (r1)) + mpi_add (r1, r1, p1p2); + + /* yp0 = xp + (r1 - xp mod p1*p2) */ + yp0 = tmp; tmp = NULL; + mpi_subm (yp0, r1, xp, p1p2); + mpi_add (yp0, yp0, xp); + mpi_free (r1); + + /* Fixup a negative value. */ + if (mpi_cmp (yp0, xp) < 0 ) + mpi_add (yp0, yp0, p1p2); + } + + /* yp0 is now the first integer greater than xp with p1 being a + large prime factor of yp0-1 and p2 a large prime factor of yp0+1. */ + + /* Note that the first example from X9.31 (D.1.1) which uses + (Xq1 #1A5CF72EE770DE50CB09ACCEA9#) + (Xq2 #134E4CAA16D2350A21D775C404#) + (Xq #CC1092495D867E64065DEE3E7955F2EBC7D47A2D + 7C9953388F97DDDC3E1CA19C35CA659EDC2FC325 + 6D29C2627479C086A699A49C4C9CEE7EF7BD1B34 + 321DE34A#)))) + returns an yp0 of + #CC1092495D867E64065DEE3E7955F2EBC7D47A2D + 7C9953388F97DDDC3E1CA19C35CA659EDC2FC4E3 + BF20CB896EE37E098A906313271422162CB6C642 + 75C1201F# + and not + #CC1092495D867E64065DEE3E7955F2EBC7D47A2D + 7C9953388F97DDDC3E1CA19C35CA659EDC2FC2E6 + C88FE299D52D78BE405A97E01FD71DD7819ECB91 + FA85A076# + as stated in the standard. This seems to be a bug in X9.31. + */ + + { + gcry_mpi_t val_2 = mpi_alloc_set_ui (2); + gcry_mpi_t gcdtmp = mpi_alloc_like (yp0); + int gcdres; + + mpi_sub_ui (p1p2, p1p2, 1); /* Adjust for loop body. */ + mpi_sub_ui (yp0, yp0, 1); /* Ditto. */ + for (;;) + { + gcdres = gcry_mpi_gcd (gcdtmp, e, yp0); + mpi_add_ui (yp0, yp0, 1); + if (!gcdres) + progress ('/'); /* gcd (e, yp0-1) != 1 */ + else if (check_prime (yp0, val_2, 64, NULL, NULL)) + break; /* Found. */ + /* We add p1p2-1 because yp0 is incremented after the gcd test. */ + mpi_add (yp0, yp0, p1p2); + } + mpi_free (gcdtmp); + mpi_free (val_2); + } + + mpi_free (p1p2); + + progress('\n'); + if (r_p1) + *r_p1 = p1; + else + mpi_free (p1); + if (r_p2) + *r_p2 = p2; + else + mpi_free (p2); + return yp0; +} + + + +/* Generate the two prime used for DSA using the algorithm specified + in FIPS 186-2. PBITS is the desired length of the prime P and a + QBITS the length of the prime Q. If SEED is not supplied and + SEEDLEN is 0 the function generates an appropriate SEED. On + success the generated primes are stored at R_Q and R_P, the counter + value is stored at R_COUNTER and the seed actually used for + generation is stored at R_SEED and R_SEEDVALUE. */ +gpg_err_code_t +_gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, + const void *seed, size_t seedlen, + gcry_mpi_t *r_q, gcry_mpi_t *r_p, + int *r_counter, + void **r_seed, size_t *r_seedlen) +{ + gpg_err_code_t ec; + unsigned char seed_help_buffer[160/8]; /* Used to hold a generated SEED. */ + unsigned char *seed_plus; /* Malloced buffer to hold SEED+x. */ + unsigned char digest[160/8]; /* Helper buffer for SHA-1 digest. */ + gcry_mpi_t val_2 = NULL; /* Helper for the prime test. */ + gcry_mpi_t tmpval = NULL; /* Helper variable. */ + int i; + + unsigned char value_u[160/8]; + int value_n, value_b, value_k; + int counter; + gcry_mpi_t value_w = NULL; + gcry_mpi_t value_x = NULL; + gcry_mpi_t prime_q = NULL; + gcry_mpi_t prime_p = NULL; + + /* FIPS 186-2 allows only for 1024/160 bit. */ + if (pbits != 1024 || qbits != 160) + return GPG_ERR_INV_KEYLEN; + + if (!seed && !seedlen) + ; /* No seed value given: We are asked to generate it. */ + else if (!seed || seedlen < qbits/8) + return GPG_ERR_INV_ARG; + + /* Allocate a buffer to later compute SEED+some_increment. */ + seed_plus = gcry_malloc (seedlen < 20? 20:seedlen); + if (!seed_plus) + { + ec = gpg_err_code_from_syserror (); + goto leave; + } + + val_2 = mpi_alloc_set_ui (2); + value_n = (pbits - 1) / qbits; + value_b = (pbits - 1) - value_n * qbits; + value_w = gcry_mpi_new (pbits); + value_x = gcry_mpi_new (pbits); + + restart: + /* Generate Q. */ + for (;;) + { + /* Step 1: Generate a (new) seed unless one has been supplied. */ + if (!seed) + { + seedlen = sizeof seed_help_buffer; + gcry_create_nonce (seed_help_buffer, seedlen); + seed = seed_help_buffer; + } + + /* Step 2: U = sha1(seed) ^ sha1((seed+1) mod 2^{qbits}) */ + memcpy (seed_plus, seed, seedlen); + for (i=seedlen-1; i >= 0; i--) + { + seed_plus[i]++; + if (seed_plus[i]) + break; + } + gcry_md_hash_buffer (GCRY_MD_SHA1, value_u, seed, seedlen); + gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); + for (i=0; i < sizeof value_u; i++) + value_u[i] ^= digest[i]; + + /* Step 3: Form q from U */ + gcry_mpi_release (prime_q); prime_q = NULL; + ec = gpg_err_code (gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, + value_u, sizeof value_u, NULL)); + if (ec) + goto leave; + mpi_set_highbit (prime_q, qbits-1 ); + mpi_set_bit (prime_q, 0); + + /* Step 4: Test whether Q is prime using 64 round of Rabin-Miller. */ + if (check_prime (prime_q, val_2, 64, NULL, NULL)) + break; /* Yes, Q is prime. */ + + /* Step 5. */ + seed = NULL; /* Force a new seed at Step 1. */ + } + + /* Step 6. Note that we do no use an explicit offset but increment + SEED_PLUS accordingly. SEED_PLUS is currently SEED+1. */ + counter = 0; + + /* Generate P. */ + prime_p = gcry_mpi_new (pbits); + for (;;) + { + /* Step 7: For k = 0,...n let + V_k = sha1(seed+offset+k) mod 2^{qbits} + Step 8: W = V_0 + V_1*2^160 + + ... + + V_{n-1}*2^{(n-1)*160} + + (V_{n} mod 2^b)*2^{n*160} + */ + mpi_set_ui (value_w, 0); + for (value_k=0; value_k <= value_n; value_k++) + { + /* There is no need to have an explicit offset variable: In + the first round we shall have an offset of 2, this is + achieved by using SEED_PLUS which is already at SEED+1, + thus we just need to increment it once again. The + requirement for the next round is to update offset by N, + which we implictly did at the end of this loop, and then + to add one; this one is the same as in the first round. */ + for (i=seedlen-1; i >= 0; i--) + { + seed_plus[i]++; + if (seed_plus[i]) + break; + } + gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); + + gcry_mpi_release (tmpval); tmpval = NULL; + ec = gpg_err_code (gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, + digest, sizeof digest, NULL)); + if (ec) + goto leave; + if (value_k == value_n) + mpi_clear_highbit (tmpval, value_b); /* (V_n mod 2^b) */ + mpi_lshift (tmpval, tmpval, value_k*qbits); + mpi_add (value_w, value_w, tmpval); + } + + /* Step 8 continued: X = W + 2^{L-1} */ + mpi_set_ui (value_x, 0); + mpi_set_highbit (value_x, pbits-1); + mpi_add (value_x, value_x, value_w); + + /* Step 9: c = X mod 2q, p = X - (c - 1) */ + mpi_mul_2exp (tmpval, prime_q, 1); + mpi_mod (tmpval, value_x, tmpval); + mpi_sub_ui (tmpval, tmpval, 1); + mpi_sub (prime_p, value_x, tmpval); + + /* Step 10: If p < 2^{L-1} skip the primality test. */ + /* Step 11 and 12: Primality test. */ + if (mpi_get_nbits (prime_p) >= pbits-1 + && check_prime (prime_p, val_2, 64, NULL, NULL) ) + break; /* Yes, P is prime, continue with Step 15. */ + + /* Step 13: counter = counter + 1, offset = offset + n + 1. */ + counter++; + + /* Step 14: If counter >= 2^12 goto Step 1. */ + if (counter >= 4096) + goto restart; + } + + /* Step 15: Save p, q, counter and seed. */ +/* log_debug ("fips186-2 pbits p=%u q=%u counter=%d\n", */ +/* mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); */ +/* log_printhex("fips186-2 seed:", seed, seedlen); */ +/* log_mpidump ("fips186-2 prime p", prime_p); */ +/* log_mpidump ("fips186-2 prime q", prime_q); */ + if (r_q) + { + *r_q = prime_q; + prime_q = NULL; + } + if (r_p) + { + *r_p = prime_p; + prime_p = NULL; + } + if (r_counter) + *r_counter = counter; + if (r_seed && r_seedlen) + { + memcpy (seed_plus, seed, seedlen); + *r_seed = seed_plus; + seed_plus = NULL; + *r_seedlen = seedlen; + } + + + leave: + gcry_mpi_release (tmpval); + gcry_mpi_release (value_x); + gcry_mpi_release (value_w); + gcry_mpi_release (prime_p); + gcry_mpi_release (prime_q); + gcry_free (seed_plus); + gcry_mpi_release (val_2); + return ec; +} + + + +/* WARNING: The code below has not yet been tested! However, it is + not yet used. We need to wait for FIPS 186-3 final and for test + vectors. + + Generate the two prime used for DSA using the algorithm specified + in FIPS 186-3, A.1.1.2. PBITS is the desired length of the prime P + and a QBITS the length of the prime Q. If SEED is not supplied and + SEEDLEN is 0 the function generates an appropriate SEED. On + success the generated primes are stored at R_Q and R_P, the counter + value is stored at R_COUNTER and the seed actually used for + generation is stored at R_SEED and R_SEEDVALUE. The hash algorithm + used is stored at R_HASHALGO. + + Note that this function is very similar to the fips186_2 code. Due + to the minor differences, other buffer sizes and for documentarion, + we use a separate function. +*/ +gpg_err_code_t +_gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, + const void *seed, size_t seedlen, + gcry_mpi_t *r_q, gcry_mpi_t *r_p, + int *r_counter, + void **r_seed, size_t *r_seedlen, + int *r_hashalgo) +{ + gpg_err_code_t ec; + unsigned char seed_help_buffer[256/8]; /* Used to hold a generated SEED. */ + unsigned char *seed_plus; /* Malloced buffer to hold SEED+x. */ + unsigned char digest[256/8]; /* Helper buffer for SHA-1 digest. */ + gcry_mpi_t val_2 = NULL; /* Helper for the prime test. */ + gcry_mpi_t tmpval = NULL; /* Helper variable. */ + int hashalgo; /* The id of the Approved Hash Function. */ + int i; + + unsigned char value_u[256/8]; + int value_n, value_b, value_j; + int counter; + gcry_mpi_t value_w = NULL; + gcry_mpi_t value_x = NULL; + gcry_mpi_t prime_q = NULL; + gcry_mpi_t prime_p = NULL; + + gcry_assert (sizeof seed_help_buffer == sizeof digest + && sizeof seed_help_buffer == sizeof value_u); + + /* Step 1: Check the requested prime lengths. */ + /* Note that due to the size of our buffers QBITS is limited to 256. */ + if (pbits == 1024 && qbits == 160) + hashalgo = GCRY_MD_SHA1; + else if (pbits == 2048 && qbits == 224) + hashalgo = GCRY_MD_SHA224; + else if (pbits == 2048 && qbits == 256) + hashalgo = GCRY_MD_SHA256; + else if (pbits == 3072 && qbits == 256) + hashalgo = GCRY_MD_SHA256; + else + return GPG_ERR_INV_KEYLEN; + + /* Also check that the hash algorithm is available. */ + ec = gpg_err_code (gcry_md_test_algo (hashalgo)); + if (ec) + return ec; + gcry_assert (qbits/8 <= sizeof digest); + gcry_assert (gcry_md_get_algo_dlen (hashalgo) == qbits/8); + + + /* Step 2: Check seedlen. */ + if (!seed && !seedlen) + ; /* No seed value given: We are asked to generate it. */ + else if (!seed || seedlen < qbits/8) + return GPG_ERR_INV_ARG; + + /* Allocate a buffer to later compute SEED+some_increment and a few + helper variables. */ + seed_plus = gcry_malloc (seedlen < sizeof seed_help_buffer? + sizeof seed_help_buffer : seedlen); + if (!seed_plus) + { + ec = gpg_err_code_from_syserror (); + goto leave; + } + val_2 = mpi_alloc_set_ui (2); + value_w = gcry_mpi_new (pbits); + value_x = gcry_mpi_new (pbits); + + /* Step 3: n = \lceil L / outlen \rceil - 1 */ + value_n = (pbits + qbits - 1) / qbits - 1; + /* Step 4: b = L - 1 - (n * outlen) */ + value_b = pbits - 1 - (value_n * qbits); + + restart: + /* Generate Q. */ + for (;;) + { + /* Step 5: Generate a (new) seed unless one has been supplied. */ + if (!seed) + { + seedlen = qbits/8; + gcry_assert (seedlen <= sizeof seed_help_buffer); + gcry_create_nonce (seed_help_buffer, seedlen); + seed = seed_help_buffer; + } + + /* Step 6: U = hash(seed) */ + gcry_md_hash_buffer (hashalgo, value_u, seed, seedlen); + + /* Step 7: q = 2^{N-1} + U + 1 - (U mod 2) */ + if ( !(value_u[qbits/8-1] & 0x01) ) + { + for (i=qbits/8-1; i >= 0; i--) + { + value_u[i]++; + if (value_u[i]) + break; + } + } + gcry_mpi_release (prime_q); prime_q = NULL; + ec = gpg_err_code (gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, + value_u, sizeof value_u, NULL)); + if (ec) + goto leave; + mpi_set_highbit (prime_q, qbits-1 ); + + /* Step 8: Test whether Q is prime using 64 round of Rabin-Miller. + According to table C.1 this is sufficient for all + supported prime sizes (i.e. up 3072/256). */ + if (check_prime (prime_q, val_2, 64, NULL, NULL)) + break; /* Yes, Q is prime. */ + + /* Step 8. */ + seed = NULL; /* Force a new seed at Step 5. */ + } + + /* Step 11. Note that we do no use an explicit offset but increment + SEED_PLUS accordingly. */ + memcpy (seed_plus, seed, seedlen); + counter = 0; + + /* Generate P. */ + prime_p = gcry_mpi_new (pbits); + for (;;) + { + /* Step 11.1: For j = 0,...n let + V_j = hash(seed+offset+j) + Step 11.2: W = V_0 + V_1*2^outlen + + ... + + V_{n-1}*2^{(n-1)*outlen} + + (V_{n} mod 2^b)*2^{n*outlen} + */ + mpi_set_ui (value_w, 0); + for (value_j=0; value_j <= value_n; value_j++) + { + /* There is no need to have an explicit offset variable: In + the first round we shall have an offset of 1 and a j of + 0. This is achieved by incrementing SEED_PLUS here. For + the next round offset is implicitly updated by using + SEED_PLUS again. */ + for (i=seedlen-1; i >= 0; i--) + { + seed_plus[i]++; + if (seed_plus[i]) + break; + } + gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); + + gcry_mpi_release (tmpval); tmpval = NULL; + ec = gpg_err_code (gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, + digest, sizeof digest, NULL)); + if (ec) + goto leave; + if (value_j == value_n) + mpi_clear_highbit (tmpval, value_b); /* (V_n mod 2^b) */ + mpi_lshift (tmpval, tmpval, value_j*qbits); + mpi_add (value_w, value_w, tmpval); + } + + /* Step 11.3: X = W + 2^{L-1} */ + mpi_set_ui (value_x, 0); + mpi_set_highbit (value_x, pbits-1); + mpi_add (value_x, value_x, value_w); + + /* Step 11.4: c = X mod 2q */ + mpi_mul_2exp (tmpval, prime_q, 1); + mpi_mod (tmpval, value_x, tmpval); + + /* Step 11.5: p = X - (c - 1) */ + mpi_sub_ui (tmpval, tmpval, 1); + mpi_sub (prime_p, value_x, tmpval); + + /* Step 11.6: If p < 2^{L-1} skip the primality test. */ + /* Step 11.7 and 11.8: Primality test. */ + if (mpi_get_nbits (prime_p) >= pbits-1 + && check_prime (prime_p, val_2, 64, NULL, NULL) ) + break; /* Yes, P is prime, continue with Step 15. */ + + /* Step 11.9: counter = counter + 1, offset = offset + n + 1. + If counter >= 4L goto Step 5. */ + counter++; + if (counter >= 4*pbits) + goto restart; + } + + /* Step 12: Save p, q, counter and seed. */ + log_debug ("fips186-3 pbits p=%u q=%u counter=%d\n", + mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); + log_printhex("fips186-3 seed:", seed, seedlen); + log_mpidump ("fips186-3 prime p", prime_p); + log_mpidump ("fips186-3 prime q", prime_q); + if (r_q) + { + *r_q = prime_q; + prime_q = NULL; + } + if (r_p) + { + *r_p = prime_p; + prime_p = NULL; + } + if (r_counter) + *r_counter = counter; + if (r_seed && r_seedlen) + { + memcpy (seed_plus, seed, seedlen); + *r_seed = seed_plus; + seed_plus = NULL; + *r_seedlen = seedlen; + } + if (r_hashalgo) + *r_hashalgo = hashalgo; + + leave: + gcry_mpi_release (tmpval); + gcry_mpi_release (value_x); + gcry_mpi_release (value_w); + gcry_mpi_release (prime_p); + gcry_mpi_release (prime_q); + gcry_free (seed_plus); + gcry_mpi_release (val_2); + return ec; +} + diff --git a/libgcrypt-1.4.6/cipher/pubkey.c b/libgcrypt-1.4.6/cipher/pubkey.c index 08abcbf..28d18f9 100644 --- a/libgcrypt-1.4.6/cipher/pubkey.c +++ b/libgcrypt-1.4.6/cipher/pubkey.c @@ -1,2749 +1,2749 @@ -/* pubkey.c - pubkey dispatcher - * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005, - * 2007, 2008 Free Software Foundation, Inc. - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser general Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see . - */ - -#include -#include -#include -#include -#include - -#include "g10lib.h" -#include "mpi.h" -#include "cipher.h" -#include "ath.h" - - -static gcry_err_code_t pubkey_decrypt (int algo, gcry_mpi_t *result, - gcry_mpi_t *data, gcry_mpi_t *skey, - int flags); -static gcry_err_code_t pubkey_sign (int algo, gcry_mpi_t *resarr, - gcry_mpi_t hash, gcry_mpi_t *skey); -static gcry_err_code_t pubkey_verify (int algo, gcry_mpi_t hash, - gcry_mpi_t *data, gcry_mpi_t *pkey, - int (*cmp) (void *, gcry_mpi_t), - void *opaque); - - -/* A dummy extraspec so that we do not need to tests the extraspec - field from the module specification against NULL and instead - directly test the respective fields of extraspecs. */ -static pk_extra_spec_t dummy_extra_spec; - - -/* This is the list of the default public-key ciphers included in - libgcrypt. FIPS_ALLOWED indicated whether the algorithm is used in - FIPS mode. */ -static struct pubkey_table_entry -{ - gcry_pk_spec_t *pubkey; - pk_extra_spec_t *extraspec; - unsigned int algorithm; - int fips_allowed; -} pubkey_table[] = - { -#if USE_RSA - { &_gcry_pubkey_spec_rsa, - &_gcry_pubkey_extraspec_rsa, GCRY_PK_RSA, 1}, -#endif -#if USE_ELGAMAL - { &_gcry_pubkey_spec_elg, - &_gcry_pubkey_extraspec_elg, GCRY_PK_ELG }, - { &_gcry_pubkey_spec_elg, - &_gcry_pubkey_extraspec_elg, GCRY_PK_ELG_E }, -#endif -#if USE_DSA - { &_gcry_pubkey_spec_dsa, - &_gcry_pubkey_extraspec_dsa, GCRY_PK_DSA, 1 }, -#endif -#if USE_ECC - { &_gcry_pubkey_spec_ecdsa, - &_gcry_pubkey_extraspec_ecdsa, GCRY_PK_ECDSA, 0 }, -#endif - { NULL, 0 }, - }; - -/* List of registered ciphers. */ -static gcry_module_t pubkeys_registered; - -/* This is the lock protecting PUBKEYS_REGISTERED. */ -static ath_mutex_t pubkeys_registered_lock = ATH_MUTEX_INITIALIZER;; - -/* Flag to check wether the default pubkeys have already been - registered. */ -static int default_pubkeys_registered; - -/* Convenient macro for registering the default digests. */ -#define REGISTER_DEFAULT_PUBKEYS \ - do \ - { \ - ath_mutex_lock (&pubkeys_registered_lock); \ - if (! default_pubkeys_registered) \ - { \ - pk_register_default (); \ - default_pubkeys_registered = 1; \ - } \ - ath_mutex_unlock (&pubkeys_registered_lock); \ - } \ - while (0) - -/* These dummy functions are used in case a cipher implementation - refuses to provide it's own functions. */ - -static gcry_err_code_t -dummy_generate (int algorithm, unsigned int nbits, unsigned long dummy, - gcry_mpi_t *skey, gcry_mpi_t **retfactors) -{ - (void)algorithm; - (void)nbits; - (void)dummy; - (void)skey; - (void)retfactors; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} - -static gcry_err_code_t -dummy_check_secret_key (int algorithm, gcry_mpi_t *skey) -{ - (void)algorithm; - (void)skey; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} - -static gcry_err_code_t -dummy_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *pkey, int flags) -{ - (void)algorithm; - (void)resarr; - (void)data; - (void)pkey; - (void)flags; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} - -static gcry_err_code_t -dummy_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data, - gcry_mpi_t *skey, int flags) -{ - (void)algorithm; - (void)result; - (void)data; - (void)skey; - (void)flags; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} - -static gcry_err_code_t -dummy_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *skey) -{ - (void)algorithm; - (void)resarr; - (void)data; - (void)skey; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} - -static gcry_err_code_t -dummy_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data, - gcry_mpi_t *pkey, - int (*cmp) (void *, gcry_mpi_t), void *opaquev) -{ - (void)algorithm; - (void)hash; - (void)data; - (void)pkey; - (void)cmp; - (void)opaquev; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} - -static unsigned -dummy_get_nbits (int algorithm, gcry_mpi_t *pkey) -{ - (void)algorithm; - (void)pkey; - fips_signal_error ("using dummy public key function"); - return 0; -} - -/* Internal function. Register all the pubkeys included in - PUBKEY_TABLE. Returns zero on success or an error code. */ -static void -pk_register_default (void) -{ - gcry_err_code_t err = 0; - int i; - - for (i = 0; (! err) && pubkey_table[i].pubkey; i++) - { -#define pubkey_use_dummy(func) \ - if (! pubkey_table[i].pubkey->func) \ - pubkey_table[i].pubkey->func = dummy_##func; - - pubkey_use_dummy (generate); - pubkey_use_dummy (check_secret_key); - pubkey_use_dummy (encrypt); - pubkey_use_dummy (decrypt); - pubkey_use_dummy (sign); - pubkey_use_dummy (verify); - pubkey_use_dummy (get_nbits); -#undef pubkey_use_dummy - - err = _gcry_module_add (&pubkeys_registered, - pubkey_table[i].algorithm, - (void *) pubkey_table[i].pubkey, - (void *) pubkey_table[i].extraspec, - NULL); - } - - if (err) - BUG (); -} - -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_pk_lookup_func_name (void *spec, void *data) -{ - gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) spec; - char *name = (char *) data; - const char **aliases = pubkey->aliases; - int ret = stricmp (name, pubkey->name); - - while (ret && *aliases) - ret = stricmp (name, *aliases++); - - return ! ret; -} - -/* Internal function. Lookup a pubkey entry by it's name. */ -static gcry_module_t -gcry_pk_lookup_name (const char *name) -{ - gcry_module_t pubkey; - - pubkey = _gcry_module_lookup (pubkeys_registered, (void *) name, - gcry_pk_lookup_func_name); - - return pubkey; -} - -/* Register a new pubkey module whose specification can be found in - PUBKEY. On success, a new algorithm ID is stored in ALGORITHM_ID - and a pointer representhing this module is stored in MODULE. */ -gcry_error_t -_gcry_pk_register (gcry_pk_spec_t *pubkey, - pk_extra_spec_t *extraspec, - unsigned int *algorithm_id, - gcry_module_t *module) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_module_t mod; - - /* We do not support module loading in fips mode. */ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - ath_mutex_lock (&pubkeys_registered_lock); - err = _gcry_module_add (&pubkeys_registered, 0, - (void *) pubkey, - (void *)(extraspec? extraspec : &dummy_extra_spec), - &mod); - ath_mutex_unlock (&pubkeys_registered_lock); - - if (! err) - { - *module = mod; - *algorithm_id = mod->mod_id; - } - - return err; -} - -/* Unregister the pubkey identified by ID, which must have been - registered with gcry_pk_register. */ -void -gcry_pk_unregister (gcry_module_t module) -{ - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); -} - -static void -release_mpi_array (gcry_mpi_t *array) -{ - for (; *array; array++) - { - mpi_free(*array); - *array = NULL; - } -} - -/**************** - * Map a string to the pubkey algo - */ -int -gcry_pk_map_name (const char *string) -{ - gcry_module_t pubkey; - int algorithm = 0; - - if (!string) - return 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = gcry_pk_lookup_name (string); - if (pubkey) - { - algorithm = pubkey->mod_id; - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return algorithm; -} - - -/* Map the public key algorithm whose ID is contained in ALGORITHM to - a string representation of the algorithm name. For unknown - algorithm IDs this functions returns "?". */ -const char * -gcry_pk_algo_name (int algorithm) -{ - gcry_module_t pubkey; - const char *name; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - name = ((gcry_pk_spec_t *) pubkey->spec)->name; - _gcry_module_release (pubkey); - } - else - name = "?"; - ath_mutex_unlock (&pubkeys_registered_lock); - - return name; -} - - -/* A special version of gcry_pk_algo name to return the first aliased - name of the algorithm. This is required to adhere to the spki - specs where the algorithm names are lowercase. */ -const char * -_gcry_pk_aliased_algo_name (int algorithm) -{ - const char *name = NULL; - gcry_module_t module; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) module->spec; - - name = pubkey->aliases? *pubkey->aliases : NULL; - if (!name || !*name) - name = pubkey->name; - _gcry_module_release (module); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return name; -} - - -static void -disable_pubkey_algo (int algorithm) -{ - gcry_module_t pubkey; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - if (! (pubkey-> flags & FLAG_MODULE_DISABLED)) - pubkey->flags |= FLAG_MODULE_DISABLED; - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); -} - - -/**************** - * A USE of 0 means: don't care. - */ -static gcry_err_code_t -check_pubkey_algo (int algorithm, unsigned use) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_pk_spec_t *pubkey; - gcry_module_t module; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - - if (((use & GCRY_PK_USAGE_SIGN) - && (! (pubkey->use & GCRY_PK_USAGE_SIGN))) - || ((use & GCRY_PK_USAGE_ENCR) - && (! (pubkey->use & GCRY_PK_USAGE_ENCR)))) - err = GPG_ERR_WRONG_PUBKEY_ALGO; - else if (module->flags & FLAG_MODULE_DISABLED) - err = GPG_ERR_PUBKEY_ALGO; - _gcry_module_release (module); - } - else - err = GPG_ERR_PUBKEY_ALGO; - ath_mutex_unlock (&pubkeys_registered_lock); - - return err; -} - - -/**************** - * Return the number of public key material numbers - */ -static int -pubkey_get_npkey (int algorithm) -{ - gcry_module_t pubkey; - int npkey = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - npkey = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_pkey); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return npkey; -} - -/**************** - * Return the number of secret key material numbers - */ -static int -pubkey_get_nskey (int algorithm) -{ - gcry_module_t pubkey; - int nskey = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - nskey = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_skey); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return nskey; -} - -/**************** - * Return the number of signature material numbers - */ -static int -pubkey_get_nsig (int algorithm) -{ - gcry_module_t pubkey; - int nsig = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - nsig = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_sig); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return nsig; -} - -/**************** - * Return the number of encryption material numbers - */ -static int -pubkey_get_nenc (int algorithm) -{ - gcry_module_t pubkey; - int nenc = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - nenc = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_enc); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return nenc; -} - - -/* Generate a new public key with algorithm ALGORITHM of size NBITS - and return it at SKEY. USE_E depends on the ALGORITHM. GENPARMS - is passed to the algorithm module if it features an extended - generation function. RETFACTOR is used by some algorithms to - return certain additional information which are in general not - required. - - The function returns the error code number or 0 on success. */ -static gcry_err_code_t -pubkey_generate (int algorithm, - unsigned int nbits, - unsigned long use_e, - gcry_sexp_t genparms, - gcry_mpi_t *skey, gcry_mpi_t **retfactors, - gcry_sexp_t *r_extrainfo) -{ - gcry_err_code_t ec = GPG_ERR_PUBKEY_ALGO; - gcry_module_t pubkey; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - pk_extra_spec_t *extraspec = pubkey->extraspec; - - if (extraspec && extraspec->ext_generate) - { - /* Use the extended generate function. */ - ec = extraspec->ext_generate - (algorithm, nbits, use_e, genparms, skey, retfactors, r_extrainfo); - } - else - { - /* Use the standard generate function. */ - ec = ((gcry_pk_spec_t *) pubkey->spec)->generate - (algorithm, nbits, use_e, skey, retfactors); - } - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return ec; -} - - -static gcry_err_code_t -pubkey_check_secret_key (int algorithm, gcry_mpi_t *skey) -{ - gcry_err_code_t err = GPG_ERR_PUBKEY_ALGO; - gcry_module_t pubkey; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - err = ((gcry_pk_spec_t *) pubkey->spec)->check_secret_key - (algorithm, skey); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return err; -} - - -/**************** - * This is the interface to the public key encryption. Encrypt DATA - * with PKEY and put it into RESARR which should be an array of MPIs - * of size PUBKEY_MAX_NENC (or less if the algorithm allows this - - * check with pubkey_get_nenc() ) - */ -static gcry_err_code_t -pubkey_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *pkey, int flags) -{ - gcry_pk_spec_t *pubkey; - gcry_module_t module; - gcry_err_code_t rc; - int i; - - /* Note: In fips mode DBG_CIPHER will enver evaluate to true but as - an extra failsafe protection we explicitly test for fips mode - here. */ - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_encrypt: algo=%d\n", algorithm); - for(i = 0; i < pubkey_get_npkey (algorithm); i++) - log_mpidump (" pkey:", pkey[i]); - log_mpidump (" data:", data); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->encrypt (algorithm, resarr, data, pkey, flags); - _gcry_module_release (module); - goto ready; - } - rc = GPG_ERR_PUBKEY_ALGO; - - ready: - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!rc && DBG_CIPHER && !fips_mode ()) - { - for(i = 0; i < pubkey_get_nenc (algorithm); i++) - log_mpidump(" encr:", resarr[i] ); - } - return rc; -} - - -/**************** - * This is the interface to the public key decryption. - * ALGO gives the algorithm to use and this implicitly determines - * the size of the arrays. - * result is a pointer to a mpi variable which will receive a - * newly allocated mpi or NULL in case of an error. - */ -static gcry_err_code_t -pubkey_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data, - gcry_mpi_t *skey, int flags) -{ - gcry_pk_spec_t *pubkey; - gcry_module_t module; - gcry_err_code_t rc; - int i; - - *result = NULL; /* so the caller can always do a mpi_free */ - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_decrypt: algo=%d\n", algorithm); - for(i = 0; i < pubkey_get_nskey (algorithm); i++) - log_mpidump (" skey:", skey[i]); - for(i = 0; i < pubkey_get_nenc (algorithm); i++) - log_mpidump (" data:", data[i]); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->decrypt (algorithm, result, data, skey, flags); - _gcry_module_release (module); - goto ready; - } - - rc = GPG_ERR_PUBKEY_ALGO; - - ready: - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!rc && DBG_CIPHER && !fips_mode ()) - log_mpidump (" plain:", *result); - - return rc; -} - - -/**************** - * This is the interface to the public key signing. - * Sign data with skey and put the result into resarr which - * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the - * algorithm allows this - check with pubkey_get_nsig() ) - */ -static gcry_err_code_t -pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *skey) -{ - gcry_pk_spec_t *pubkey; - gcry_module_t module; - gcry_err_code_t rc; - int i; - - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_sign: algo=%d\n", algorithm); - for(i = 0; i < pubkey_get_nskey (algorithm); i++) - log_mpidump (" skey:", skey[i]); - log_mpidump(" data:", data ); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->sign (algorithm, resarr, data, skey); - _gcry_module_release (module); - goto ready; - } - - rc = GPG_ERR_PUBKEY_ALGO; - - ready: - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!rc && DBG_CIPHER && !fips_mode ()) - for (i = 0; i < pubkey_get_nsig (algorithm); i++) - log_mpidump (" sig:", resarr[i]); - - return rc; -} - -/**************** - * Verify a public key signature. - * Return 0 if the signature is good - */ -static gcry_err_code_t -pubkey_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data, - gcry_mpi_t *pkey, - int (*cmp)(void *, gcry_mpi_t), void *opaquev) -{ - gcry_pk_spec_t *pubkey; - gcry_module_t module; - gcry_err_code_t rc; - int i; - - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_verify: algo=%d\n", algorithm); - for (i = 0; i < pubkey_get_npkey (algorithm); i++) - log_mpidump (" pkey:", pkey[i]); - for (i = 0; i < pubkey_get_nsig (algorithm); i++) - log_mpidump (" sig:", data[i]); - log_mpidump (" hash:", hash); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->verify (algorithm, hash, data, pkey, cmp, opaquev); - _gcry_module_release (module); - goto ready; - } - - rc = GPG_ERR_PUBKEY_ALGO; - - ready: - ath_mutex_unlock (&pubkeys_registered_lock); - return rc; -} - - -/* Internal function. */ -static gcry_err_code_t -sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names, - gcry_mpi_t *elements, const char *algo_name) -{ - gcry_err_code_t err = 0; - int i, idx; - const char *name; - gcry_sexp_t list; - - for (name = element_names, idx = 0; *name && !err; name++, idx++) - { - list = gcry_sexp_find_token (key_sexp, name, 1); - if (!list) - elements[idx] = NULL; - else - { - elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (list); - if (!elements[idx]) - err = GPG_ERR_INV_OBJ; - } - } - - if (!err) - { - /* Check that all elements are available. */ - for (name = element_names, idx = 0; *name; name++, idx++) - if (!elements[idx]) - break; - if (*name) - { - err = GPG_ERR_NO_OBJ; - /* Some are missing. Before bailing out we test for - optional parameters. */ - if (algo_name && !strcmp (algo_name, "RSA") - && !strcmp (element_names, "nedpqu") ) - { - /* This is RSA. Test whether we got N, E and D and that - the optional P, Q and U are all missing. */ - if (elements[0] && elements[1] && elements[2] - && !elements[3] && !elements[4] && !elements[5]) - err = 0; - } - } - } - - - if (err) - { - for (i = 0; i < idx; i++) - if (elements[i]) - gcry_free (elements[i]); - } - return err; -} - - -/* Internal function used for ecc. Note, that this function makes use - of its intimate knowledge about the ECC parameters from ecc.c. */ -static gcry_err_code_t -sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names, - gcry_mpi_t *elements, pk_extra_spec_t *extraspec) - -{ - gcry_err_code_t err = 0; - int idx; - const char *name; - gcry_sexp_t list; - - /* Clear the array for easier error cleanup. */ - for (name = element_names, idx = 0; *name; name++, idx++) - elements[idx] = NULL; - gcry_assert (idx >= 6); /* We know that ECC has at least 6 elements. */ - - /* Init the array with the available curve parameters. */ - for (name = element_names, idx = 0; *name && !err; name++, idx++) - { - list = gcry_sexp_find_token (key_sexp, name, 1); - if (!list) - elements[idx] = NULL; - else - { - elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (list); - if (!elements[idx]) - { - err = GPG_ERR_INV_OBJ; - goto leave; - } - } - } - - /* Check whether a curve parameter has been given and then fill any - missing elements. */ - list = gcry_sexp_find_token (key_sexp, "curve", 5); - if (list) - { - if (extraspec->get_param) - { - char *curve; - gcry_mpi_t params[6]; - - for (idx = 0; idx < DIM(params); idx++) - params[idx] = NULL; - - curve = _gcry_sexp_nth_string (list, 1); - gcry_sexp_release (list); - if (!curve) - { - /* No curve name given (or out of core). */ - err = GPG_ERR_INV_OBJ; - goto leave; - } - err = extraspec->get_param (curve, params); - gcry_free (curve); - if (err) - goto leave; - - for (idx = 0; idx < DIM(params); idx++) - { - if (!elements[idx]) - elements[idx] = params[idx]; - else - mpi_free (params[idx]); - } - } - else - { - gcry_sexp_release (list); - err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */ - goto leave; - } - } - - /* Check that all parameters are known. */ - for (name = element_names, idx = 0; *name; name++, idx++) - if (!elements[idx]) - { - err = GPG_ERR_NO_OBJ; - goto leave; - } - - leave: - if (err) - { - for (name = element_names, idx = 0; *name; name++, idx++) - if (elements[idx]) - gcry_free (elements[idx]); - } - return err; -} - - - -/**************** - * Convert a S-Exp with either a private or a public key to our - * internal format. Currently we do only support the following - * algorithms: - * dsa - * rsa - * openpgp-dsa - * openpgp-rsa - * openpgp-elg - * openpgp-elg-sig - * ecdsa - * Provide a SE with the first element be either "private-key" or - * or "public-key". It is followed by a list with its first element - * be one of the above algorithm identifiers and the remaning - * elements are pairs with parameter-id and value. - * NOTE: we look through the list to find a list beginning with - * "private-key" or "public-key" - the first one found is used. - * - * Returns: A pointer to an allocated array of MPIs if the return value is - * zero; the caller has to release this array. - * - * Example of a DSA public key: - * (private-key - * (dsa - * (p ) - * (g ) - * (y ) - * (x ) - * ) - * ) - * The are expected to be in GCRYMPI_FMT_USG - */ -static gcry_err_code_t -sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray, - gcry_module_t *retalgo) -{ - gcry_err_code_t err = 0; - gcry_sexp_t list, l2; - char *name; - const char *elems; - gcry_mpi_t *array; - gcry_module_t module; - gcry_pk_spec_t *pubkey; - pk_extra_spec_t *extraspec; - int is_ecc; - - /* Check that the first element is valid. */ - list = gcry_sexp_find_token (sexp, - want_private? "private-key":"public-key", 0); - if (!list) - return GPG_ERR_INV_OBJ; /* Does not contain a key object. */ - - l2 = gcry_sexp_cadr( list ); - gcry_sexp_release ( list ); - list = l2; - name = _gcry_sexp_nth_string (list, 0); - if (!name) - { - gcry_sexp_release ( list ); - return GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - - /* Fixme: We should make sure that an ECC key is always named "ecc" - and not "ecdsa". "ecdsa" should be used for the signature - itself. We need a function to test whether an algorithm given - with a key is compatible with an application of the key (signing, - encryption). For RSA this is easy, but ECC is the first - algorithm which has many flavours. */ - is_ecc = ( !strcmp (name, "ecdsa") || !strcmp (name, "ecc") ); - gcry_free (name); - - if (!module) - { - gcry_sexp_release (list); - return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ - } - else - { - pubkey = (gcry_pk_spec_t *) module->spec; - extraspec = module->extraspec; - } - - elems = want_private ? pubkey->elements_skey : pubkey->elements_pkey; - array = gcry_calloc (strlen (elems) + 1, sizeof (*array)); - if (!array) - err = gpg_err_code_from_errno (errno); - if (!err) - { - if (is_ecc) - err = sexp_elements_extract_ecc (list, elems, array, extraspec); - else - err = sexp_elements_extract (list, elems, array, pubkey->name); - } - - gcry_sexp_release (list); - - if (err) - { - gcry_free (array); - - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - } - else - { - *retarray = array; - *retalgo = module; - } - - return err; -} - - -static gcry_err_code_t -sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray, - gcry_module_t *retalgo) -{ - gcry_err_code_t err = 0; - gcry_sexp_t list, l2; - char *name; - const char *elems; - gcry_mpi_t *array; - gcry_module_t module; - gcry_pk_spec_t *pubkey; - - /* Check that the first element is valid. */ - list = gcry_sexp_find_token( sexp, "sig-val" , 0 ); - if (!list) - return GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */ - - l2 = gcry_sexp_nth (list, 1); - if (!l2) - { - gcry_sexp_release (list); - return GPG_ERR_NO_OBJ; /* No cadr for the sig object. */ - } - name = _gcry_sexp_nth_string (l2, 0); - if (!name) - { - gcry_sexp_release (list); - gcry_sexp_release (l2); - return GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - } - else if (!strcmp (name, "flags")) - { - /* Skip flags, since they are not used but here just for the - sake of consistent S-expressions. */ - gcry_free (name); - gcry_sexp_release (l2); - l2 = gcry_sexp_nth (list, 2); - if (!l2) - { - gcry_sexp_release (list); - return GPG_ERR_INV_OBJ; - } - name = _gcry_sexp_nth_string (l2, 0); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - gcry_free (name); - name = NULL; - - if (!module) - { - gcry_sexp_release (l2); - gcry_sexp_release (list); - return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ - } - else - pubkey = (gcry_pk_spec_t *) module->spec; - - elems = pubkey->elements_sig; - array = gcry_calloc (strlen (elems) + 1 , sizeof *array ); - if (!array) - err = gpg_err_code_from_errno (errno); - - if (!err) - err = sexp_elements_extract (list, elems, array, NULL); - - gcry_sexp_release (l2); - gcry_sexp_release (list); - - if (err) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - - gcry_free (array); - } - else - { - *retarray = array; - *retalgo = module; - } - - return err; -} - - -/**************** - * Take sexp and return an array of MPI as used for our internal decrypt - * function. - * s_data = (enc-val - * [(flags [pkcs1])] - * ( - * ( ) - * ... - * ( ) - * )) - * RET_MODERN is set to true when at least an empty flags list has been found. - */ -static gcry_err_code_t -sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo, - int *ret_modern, int *ret_want_pkcs1, int *flags) -{ - gcry_err_code_t err = 0; - gcry_sexp_t list = NULL, l2 = NULL; - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - char *name = NULL; - size_t n; - int parsed_flags = 0; - const char *elems; - gcry_mpi_t *array = NULL; - - *ret_want_pkcs1 = 0; - *ret_modern = 0; - - /* Check that the first element is valid. */ - list = gcry_sexp_find_token (sexp, "enc-val" , 0); - if (!list) - { - err = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */ - goto leave; - } - - l2 = gcry_sexp_nth (list, 1); - if (!l2) - { - err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */ - goto leave; - } - - /* Extract identifier of sublist. */ - name = _gcry_sexp_nth_string (l2, 0); - if (!name) - { - err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - goto leave; - } - - if (!strcmp (name, "flags")) - { - /* There is a flags element - process it. */ - const char *s; - int i; - - *ret_modern = 1; - for (i = gcry_sexp_length (l2) - 1; i > 0; i--) - { - s = gcry_sexp_nth_data (l2, i, &n); - if (! s) - ; /* Not a data element - ignore. */ - else if (n == 3 && !memcmp (s, "raw", 3)) - ; /* This is just a dummy as it is the default. */ - else if (n == 5 && !memcmp (s, "pkcs1", 5)) - *ret_want_pkcs1 = 1; - else if (n == 11 && ! memcmp (s, "no-blinding", 11)) - parsed_flags |= PUBKEY_FLAG_NO_BLINDING; - else - { - err = GPG_ERR_INV_FLAG; - goto leave; - } - } - - /* Get the next which has the actual data. */ - gcry_sexp_release (l2); - l2 = gcry_sexp_nth (list, 2); - if (!l2) - { - err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */ - goto leave; - } - - /* Extract sublist identifier. */ - gcry_free (name); - name = _gcry_sexp_nth_string (l2, 0); - if (!name) - { - err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - goto leave; - } - - gcry_sexp_release (list); - list = l2; - l2 = NULL; - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!module) - { - err = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ - goto leave; - } - pubkey = (gcry_pk_spec_t *) module->spec; - - elems = pubkey->elements_enc; - array = gcry_calloc (strlen (elems) + 1, sizeof (*array)); - if (!array) - { - err = gpg_err_code_from_errno (errno); - goto leave; - } - - err = sexp_elements_extract (list, elems, array, NULL); - - leave: - gcry_sexp_release (list); - gcry_sexp_release (l2); - gcry_free (name); - - if (err) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - gcry_free (array); - } - else - { - *retarray = array; - *retalgo = module; - *flags = parsed_flags; - } - - return err; -} - -/* Take the hash value and convert into an MPI, suitable for - passing to the low level functions. We currently support the - old style way of passing just a MPI and the modern interface which - allows to pass flags so that we can choose between raw and pkcs1 - padding - may be more padding options later. - - () - or - (data - [(flags [pkcs1])] - [(hash )] - [(value )] - ) - - Either the VALUE or the HASH element must be present for use - with signatures. VALUE is used for encryption. - - NBITS is the length of the key in bits. - -*/ -static gcry_err_code_t -sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi, - int for_encryption, int *flags) -{ - gcry_err_code_t rc = 0; - gcry_sexp_t ldata, lhash, lvalue; - int i; - size_t n; - const char *s; - int is_raw = 0, is_pkcs1 = 0, unknown_flag=0; - int parsed_flags = 0, dummy_flags; - - if (! flags) - flags = &dummy_flags; - - *ret_mpi = NULL; - ldata = gcry_sexp_find_token (input, "data", 0); - if (!ldata) - { /* assume old style */ - *ret_mpi = gcry_sexp_nth_mpi (input, 0, 0); - return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ; - } - - /* see whether there is a flags object */ - { - gcry_sexp_t lflags = gcry_sexp_find_token (ldata, "flags", 0); - if (lflags) - { /* parse the flags list. */ - for (i=gcry_sexp_length (lflags)-1; i > 0; i--) - { - s = gcry_sexp_nth_data (lflags, i, &n); - if (!s) - ; /* not a data element*/ - else if ( n == 3 && !memcmp (s, "raw", 3)) - is_raw = 1; - else if ( n == 5 && !memcmp (s, "pkcs1", 5)) - is_pkcs1 = 1; - else if (n == 11 && ! memcmp (s, "no-blinding", 11)) - parsed_flags |= PUBKEY_FLAG_NO_BLINDING; - else - unknown_flag = 1; - } - gcry_sexp_release (lflags); - } - } - - if (!is_pkcs1 && !is_raw) - is_raw = 1; /* default to raw */ - - /* Get HASH or MPI */ - lhash = gcry_sexp_find_token (ldata, "hash", 0); - lvalue = lhash? NULL : gcry_sexp_find_token (ldata, "value", 0); - - if (!(!lhash ^ !lvalue)) - rc = GPG_ERR_INV_OBJ; /* none or both given */ - else if (unknown_flag) - rc = GPG_ERR_INV_FLAG; - else if (is_raw && is_pkcs1 && !for_encryption) - rc = GPG_ERR_CONFLICT; - else if (is_raw && lvalue) - { - *ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, 0); - if (!*ret_mpi) - rc = GPG_ERR_INV_OBJ; - } - else if (is_pkcs1 && lvalue && for_encryption) - { - /* Create pkcs#1 block type 2 padding. */ - unsigned char *frame = NULL; - size_t nframe = (nbits+7) / 8; - const void * value; - size_t valuelen; - unsigned char *p; - - if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen ) - rc = GPG_ERR_INV_OBJ; - else if (valuelen + 7 > nframe || !nframe) - { - /* Can't encode a VALUELEN value in a NFRAME bytes frame. */ - rc = GPG_ERR_TOO_SHORT; /* the key is too short */ - } - else if ( !(frame = gcry_malloc_secure (nframe))) - rc = gpg_err_code_from_errno (errno); - else - { - n = 0; - frame[n++] = 0; - frame[n++] = 2; /* block type */ - i = nframe - 3 - valuelen; - gcry_assert (i > 0); - p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM); - /* Replace zero bytes by new values. */ - for (;;) - { - int j, k; - unsigned char *pp; - - /* Count the zero bytes. */ - for (j=k=0; j < i; j++) - { - if (!p[j]) - k++; - } - if (!k) - break; /* Okay: no (more) zero bytes. */ - - k += k/128 + 3; /* Better get some more. */ - pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM); - for (j=0; j < i && k; ) - { - if (!p[j]) - p[j] = pp[--k]; - if (p[j]) - j++; - } - gcry_free (pp); - } - memcpy (frame+n, p, i); - n += i; - gcry_free (p); - - frame[n++] = 0; - memcpy (frame+n, value, valuelen); - n += valuelen; - gcry_assert (n == nframe); - - /* FIXME, error checking? */ - gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, n, &nframe); - } - - gcry_free(frame); - } - else if (is_pkcs1 && lhash && !for_encryption) - { - /* Create pkcs#1 block type 1 padding. */ - if (gcry_sexp_length (lhash) != 3) - rc = GPG_ERR_INV_OBJ; - else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n ) - rc = GPG_ERR_INV_OBJ; - else - { - static struct { const char *name; int algo; } hashnames[] = - { { "sha1", GCRY_MD_SHA1 }, - { "md5", GCRY_MD_MD5 }, - { "sha256", GCRY_MD_SHA256 }, - { "ripemd160", GCRY_MD_RMD160 }, - { "rmd160", GCRY_MD_RMD160 }, - { "sha384", GCRY_MD_SHA384 }, - { "sha512", GCRY_MD_SHA512 }, - { "sha224", GCRY_MD_SHA224 }, - { "md2", GCRY_MD_MD2 }, - { "md4", GCRY_MD_MD4 }, - { "tiger", GCRY_MD_TIGER }, - { "haval", GCRY_MD_HAVAL }, - { NULL, 0 } - }; - int algo; - byte asn[100]; - byte *frame = NULL; - size_t nframe = (nbits+7) / 8; - const void * value; - size_t valuelen; - size_t asnlen, dlen; - - for (i=0; hashnames[i].name; i++) - { - if ( strlen (hashnames[i].name) == n - && !memcmp (hashnames[i].name, s, n)) - break; - } - if (hashnames[i].name) - algo = hashnames[i].algo; - else - { - /* In case of not listed or dynamically allocated hash - algorithm we fall back to this somewhat slower - method. Further, it also allows to use OIDs as - algorithm names. */ - char *tmpname; - - tmpname = gcry_malloc (n+1); - if (!tmpname) - algo = 0; /* Out of core - silently give up. */ - else - { - memcpy (tmpname, s, n); - tmpname[n] = 0; - algo = gcry_md_map_name (tmpname); - gcry_free (tmpname); - } - } - - asnlen = DIM(asn); - dlen = gcry_md_get_algo_dlen (algo); - - if (!algo) - rc = GPG_ERR_DIGEST_ALGO; - else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen)) - || !valuelen ) - rc = GPG_ERR_INV_OBJ; - else if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen)) - { - /* We don't have yet all of the above algorithms. */ - rc = GPG_ERR_NOT_IMPLEMENTED; - } - else if ( valuelen != dlen ) - { - /* Hash value does not match the length of digest for - the given algorithm. */ - rc = GPG_ERR_CONFLICT; - } - else if( !dlen || dlen + asnlen + 4 > nframe) - { - /* Can't encode an DLEN byte digest MD into a NFRAME - byte frame. */ - rc = GPG_ERR_TOO_SHORT; - } - else if ( !(frame = gcry_malloc (nframe)) ) - rc = gpg_err_code_from_errno (errno); - else - { /* Assemble the pkcs#1 block type 1. */ - n = 0; - frame[n++] = 0; - frame[n++] = 1; /* block type */ - i = nframe - valuelen - asnlen - 3 ; - gcry_assert (i > 1); - memset (frame+n, 0xff, i ); - n += i; - frame[n++] = 0; - memcpy (frame+n, asn, asnlen); - n += asnlen; - memcpy (frame+n, value, valuelen ); - n += valuelen; - gcry_assert (n == nframe); - - /* Convert it into an MPI. FIXME: error checking? */ - gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, n, &nframe); - } - - gcry_free (frame); - } - } - else - rc = GPG_ERR_CONFLICT; - - gcry_sexp_release (ldata); - gcry_sexp_release (lhash); - gcry_sexp_release (lvalue); - - if (!rc) - *flags = parsed_flags; - - return rc; -} - - -/* - Do a PK encrypt operation - - Caller has to provide a public key as the SEXP pkey and data as a - SEXP with just one MPI in it. Alternativly S_DATA might be a - complex S-Expression, similar to the one used for signature - verification. This provides a flag which allows to handle PKCS#1 - block type 2 padding. The function returns a a sexp which may be - passed to to pk_decrypt. - - Returns: 0 or an errorcode. - - s_data = See comment for sexp_data_to_mpi - s_pkey = - r_ciph = (enc-val - ( - ( ) - ... - ( ) - )) - -*/ -gcry_error_t -gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey) -{ - gcry_mpi_t *pkey = NULL, data = NULL, *ciph = NULL; - const char *algo_name, *algo_elems; - int flags; - gcry_err_code_t rc; - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - - *r_ciph = NULL; - - REGISTER_DEFAULT_PUBKEYS; - - /* Get the key. */ - rc = sexp_to_key (s_pkey, 0, &pkey, &module); - if (rc) - goto leave; - - gcry_assert (module); - pubkey = (gcry_pk_spec_t *) module->spec; - - /* If aliases for the algorithm name exists, take the first one - instead of the regular name to adhere to SPKI conventions. We - assume that the first alias name is the lowercase version of the - regular one. This change is required for compatibility with - 1.1.12 generated S-expressions. */ - algo_name = pubkey->aliases? *pubkey->aliases : NULL; - if (!algo_name || !*algo_name) - algo_name = pubkey->name; - - algo_elems = pubkey->elements_enc; - - /* Get the stuff we want to encrypt. */ - rc = sexp_data_to_mpi (s_data, gcry_pk_get_nbits (s_pkey), &data, 1, - &flags); - if (rc) - goto leave; - - /* Now we can encrypt DATA to CIPH. */ - ciph = gcry_calloc (strlen (algo_elems) + 1, sizeof (*ciph)); - if (!ciph) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - rc = pubkey_encrypt (module->mod_id, ciph, data, pkey, flags); - mpi_free (data); - data = NULL; - if (rc) - goto leave; - - /* We did it. Now build the return list */ - { - char *string, *p; - int i; - size_t nelem = strlen (algo_elems); - size_t needed = 19 + strlen (algo_name) + (nelem * 5); - void **arg_list; - - /* Build the string. */ - string = p = gcry_malloc (needed); - if (!string) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - p = stpcpy ( p, "(enc-val(" ); - p = stpcpy ( p, algo_name ); - for (i=0; algo_elems[i]; i++ ) - { - *p++ = '('; - *p++ = algo_elems[i]; - p = stpcpy ( p, "%m)" ); - } - strcpy ( p, "))" ); - - /* And now the ugly part: We don't have a function to pass an - * array to a format string, so we have to do it this way :-(. */ - /* FIXME: There is now such a format specifier, so we can - change the code to be more clear. */ - arg_list = malloc (nelem * sizeof *arg_list); - if (!arg_list) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - - for (i = 0; i < nelem; i++) - arg_list[i] = ciph + i; - - rc = gcry_sexp_build_array (r_ciph, NULL, string, arg_list); - free (arg_list); - if (rc) - BUG (); - gcry_free (string); - } - - leave: - if (pkey) - { - release_mpi_array (pkey); - gcry_free (pkey); - } - - if (ciph) - { - release_mpi_array (ciph); - gcry_free (ciph); - } - - if (module) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - } - - return gcry_error (rc); -} - -/* - Do a PK decrypt operation - - Caller has to provide a secret key as the SEXP skey and data in a - format as created by gcry_pk_encrypt. For historic reasons the - function returns simply an MPI as an S-expression part; this is - deprecated and the new method should be used which returns a real - S-expressionl this is selected by adding at least an empty flags - list to S_DATA. - - Returns: 0 or an errorcode. - - s_data = (enc-val - [(flags)] - ( - ( ) - ... - ( ) - )) - s_skey = - r_plain= Either an incomplete S-expression without the parentheses - or if the flags list is used (even if empty) a real S-expression: - (value PLAIN). - */ -gcry_error_t -gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) -{ - gcry_mpi_t *skey = NULL, *data = NULL, plain = NULL; - int modern, want_pkcs1, flags; - gcry_err_code_t rc; - gcry_module_t module_enc = NULL, module_key = NULL; - gcry_pk_spec_t *pubkey = NULL; - - *r_plain = NULL; - - REGISTER_DEFAULT_PUBKEYS; - - rc = sexp_to_key (s_skey, 1, &skey, &module_key); - if (rc) - goto leave; - - rc = sexp_to_enc (s_data, &data, &module_enc, &modern, &want_pkcs1, &flags); - if (rc) - goto leave; - - if (module_key->mod_id != module_enc->mod_id) - { - rc = GPG_ERR_CONFLICT; /* Key algo does not match data algo. */ - goto leave; - } - - pubkey = (gcry_pk_spec_t *) module_key->spec; - - rc = pubkey_decrypt (module_key->mod_id, &plain, data, skey, flags); - if (rc) - goto leave; - - if (gcry_sexp_build (r_plain, NULL, modern? "(value %m)" : "%m", plain)) - BUG (); - - leave: - if (skey) - { - release_mpi_array (skey); - gcry_free (skey); - } - - if (plain) - mpi_free (plain); - - if (data) - { - release_mpi_array (data); - gcry_free (data); - } - - if (module_key || module_enc) - { - ath_mutex_lock (&pubkeys_registered_lock); - if (module_key) - _gcry_module_release (module_key); - if (module_enc) - _gcry_module_release (module_enc); - ath_mutex_unlock (&pubkeys_registered_lock); - } - - return gcry_error (rc); -} - - - -/* - Create a signature. - - Caller has to provide a secret key as the SEXP skey and data - expressed as a SEXP list hash with only one element which should - instantly be available as a MPI. Alternatively the structure given - below may be used for S_HASH, it provides the abiliy to pass flags - to the operation; the only flag defined by now is "pkcs1" which - does PKCS#1 block type 1 style padding. - - Returns: 0 or an errorcode. - In case of 0 the function returns a new SEXP with the - signature value; the structure of this signature depends on the - other arguments but is always suitable to be passed to - gcry_pk_verify - - s_hash = See comment for sexp_data_to_mpi - - s_skey = - r_sig = (sig-val - ( - ( ) - ... - ( )) - [(hash algo)]) - - Note that (hash algo) in R_SIG is not used. -*/ -gcry_error_t -gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) -{ - gcry_mpi_t *skey = NULL, hash = NULL, *result = NULL; - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - const char *algo_name, *algo_elems; - int i; - gcry_err_code_t rc; - - *r_sig = NULL; - - REGISTER_DEFAULT_PUBKEYS; - - rc = sexp_to_key (s_skey, 1, &skey, &module); - if (rc) - goto leave; - - gcry_assert (module); - pubkey = (gcry_pk_spec_t *) module->spec; - algo_name = pubkey->aliases? *pubkey->aliases : NULL; - if (!algo_name || !*algo_name) - algo_name = pubkey->name; - - algo_elems = pubkey->elements_sig; - - /* Get the stuff we want to sign. Note that pk_get_nbits does also - work on a private key. */ - rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_skey), - &hash, 0, NULL); - if (rc) - goto leave; - - result = gcry_calloc (strlen (algo_elems) + 1, sizeof (*result)); - if (!result) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - rc = pubkey_sign (module->mod_id, result, hash, skey); - if (rc) - goto leave; - - { - char *string, *p; - size_t nelem, needed = strlen (algo_name) + 20; - void **arg_list; - - nelem = strlen (algo_elems); - - /* Count elements, so that we can allocate enough space. */ - needed += 10 * nelem; - - /* Build the string. */ - string = p = gcry_malloc (needed); - if (!string) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - p = stpcpy (p, "(sig-val("); - p = stpcpy (p, algo_name); - for (i = 0; algo_elems[i]; i++) - { - *p++ = '('; - *p++ = algo_elems[i]; - p = stpcpy (p, "%m)"); - } - strcpy (p, "))"); - - arg_list = malloc (nelem * sizeof *arg_list); - if (!arg_list) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - - for (i = 0; i < nelem; i++) - arg_list[i] = result + i; - - rc = gcry_sexp_build_array (r_sig, NULL, string, arg_list); - free (arg_list); - if (rc) - BUG (); - gcry_free (string); - } - - leave: - if (skey) - { - release_mpi_array (skey); - gcry_free (skey); - } - - if (hash) - mpi_free (hash); - - if (result) - { - release_mpi_array (result); - gcry_free (result); - } - - return gcry_error (rc); -} - - -/* - Verify a signature. - - Caller has to supply the public key pkey, the signature sig and his - hashvalue data. Public key has to be a standard public key given - as an S-Exp, sig is a S-Exp as returned from gcry_pk_sign and data - must be an S-Exp like the one in sign too. */ -gcry_error_t -gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey) -{ - gcry_module_t module_key = NULL, module_sig = NULL; - gcry_mpi_t *pkey = NULL, hash = NULL, *sig = NULL; - gcry_err_code_t rc; - - REGISTER_DEFAULT_PUBKEYS; - - rc = sexp_to_key (s_pkey, 0, &pkey, &module_key); - if (rc) - goto leave; - - rc = sexp_to_sig (s_sig, &sig, &module_sig); - if (rc) - goto leave; - - /* Fixme: Check that the algorithm of S_SIG is compatible to the one - of S_PKEY. */ - - if (module_key->mod_id != module_sig->mod_id) - { - rc = GPG_ERR_CONFLICT; - goto leave; - } - - rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_pkey), &hash, 0, 0); - if (rc) - goto leave; - - rc = pubkey_verify (module_key->mod_id, hash, sig, pkey, NULL, NULL); - - leave: - if (pkey) - { - release_mpi_array (pkey); - gcry_free (pkey); - } - if (sig) - { - release_mpi_array (sig); - gcry_free (sig); - } - if (hash) - mpi_free (hash); - - if (module_key || module_sig) - { - ath_mutex_lock (&pubkeys_registered_lock); - if (module_key) - _gcry_module_release (module_key); - if (module_sig) - _gcry_module_release (module_sig); - ath_mutex_unlock (&pubkeys_registered_lock); - } - - return gcry_error (rc); -} - - -/* - Test a key. - - This may be used either for a public or a secret key to see whether - the internal structure is okay. - - Returns: 0 or an errorcode. - - s_key = */ -gcry_error_t -gcry_pk_testkey (gcry_sexp_t s_key) -{ - gcry_module_t module = NULL; - gcry_mpi_t *key = NULL; - gcry_err_code_t rc; - - REGISTER_DEFAULT_PUBKEYS; - - /* Note we currently support only secret key checking. */ - rc = sexp_to_key (s_key, 1, &key, &module); - if (! rc) - { - rc = pubkey_check_secret_key (module->mod_id, key); - release_mpi_array (key); - gcry_free (key); - } - return gcry_error (rc); -} - - -/* - Create a public key pair and return it in r_key. - How the key is created depends on s_parms: - (genkey - (algo - (parameter_name_1 ....) - .... - (parameter_name_n ....) - )) - The key is returned in a format depending on the - algorithm. Both, private and secret keys are returned - and optionally some additional informatin. - For elgamal we return this structure: - (key-data - (public-key - (elg - (p ) - (g ) - (y ) - ) - ) - (private-key - (elg - (p ) - (g ) - (y ) - (x ) - ) - ) - (misc-key-info - (pm1-factors n1 n2 ... nn) - )) - */ -gcry_error_t -gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) -{ - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - gcry_sexp_t list = NULL; - gcry_sexp_t l2 = NULL; - gcry_sexp_t l3 = NULL; - char *name = NULL; - size_t n; - gcry_err_code_t rc = GPG_ERR_NO_ERROR; - int i; - const char *algo_name = NULL; - int algo; - const char *sec_elems = NULL, *pub_elems = NULL; - gcry_mpi_t skey[12]; - gcry_mpi_t *factors = NULL; - gcry_sexp_t extrainfo = NULL; - unsigned int nbits = 0; - unsigned long use_e = 0; - - skey[0] = NULL; - *r_key = NULL; - - REGISTER_DEFAULT_PUBKEYS; - - list = gcry_sexp_find_token (s_parms, "genkey", 0); - if (!list) - { - rc = GPG_ERR_INV_OBJ; /* Does not contain genkey data. */ - goto leave; - } - - l2 = gcry_sexp_cadr (list); - gcry_sexp_release (list); - list = l2; - l2 = NULL; - if (! list) - { - rc = GPG_ERR_NO_OBJ; /* No cdr for the genkey. */ - goto leave; - } - - name = _gcry_sexp_nth_string (list, 0); - if (!name) - { - rc = GPG_ERR_INV_OBJ; /* Algo string missing. */ - goto leave; - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - gcry_free (name); - name = NULL; - if (!module) - { - rc = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ - goto leave; - } - - pubkey = (gcry_pk_spec_t *) module->spec; - algo = module->mod_id; - algo_name = pubkey->aliases? *pubkey->aliases : NULL; - if (!algo_name || !*algo_name) - algo_name = pubkey->name; - pub_elems = pubkey->elements_pkey; - sec_elems = pubkey->elements_skey; - if (strlen (sec_elems) >= DIM(skey)) - BUG (); - - /* Handle the optional rsa-use-e element. Actually this belong into - the algorithm module but we have this parameter in the public - module API, so we need to parse it right here. */ - l2 = gcry_sexp_find_token (list, "rsa-use-e", 0); - if (l2) - { - char buf[50]; - const char *s; - - s = gcry_sexp_nth_data (l2, 1, &n); - if ( !s || n >= DIM (buf) - 1 ) - { - rc = GPG_ERR_INV_OBJ; /* No value or value too large. */ - goto leave; - } - memcpy (buf, s, n); - buf[n] = 0; - use_e = strtoul (buf, NULL, 0); - gcry_sexp_release (l2); - l2 = NULL; - } - else - use_e = 65537; /* Not given, use the value generated by old versions. */ - - - /* Get the "nbits" parameter. */ - l2 = gcry_sexp_find_token (list, "nbits", 0); - if (l2) - { - char buf[50]; - const char *s; - - s = gcry_sexp_nth_data (l2, 1, &n); - if (!s || n >= DIM (buf) - 1 ) - { - rc = GPG_ERR_INV_OBJ; /* NBITS given without a cdr. */ - goto leave; - } - memcpy (buf, s, n); - buf[n] = 0; - nbits = (unsigned int)strtoul (buf, NULL, 0); - gcry_sexp_release (l2); l2 = NULL; - } - else - nbits = 0; - - /* Pass control to the algorithm module. */ - rc = pubkey_generate (module->mod_id, nbits, use_e, list, skey, - &factors, &extrainfo); - gcry_sexp_release (list); list = NULL; - if (rc) - goto leave; - - /* Key generation succeeded: Build an S-expression. */ - { - char *string, *p; - size_t nelem=0, nelem_cp = 0, needed=0; - gcry_mpi_t mpis[30]; - - /* Estimate size of format string. */ - nelem = strlen (pub_elems) + strlen (sec_elems); - if (factors) - { - for (i = 0; factors[i]; i++) - nelem++; - } - nelem_cp = nelem; - - needed += nelem * 10; - /* (+5 is for EXTRAINFO ("%S")). */ - needed += 2 * strlen (algo_name) + 300 + 5; - if (nelem > DIM (mpis)) - BUG (); - - /* Build the string. */ - nelem = 0; - string = p = gcry_malloc (needed); - if (!string) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - p = stpcpy (p, "(key-data"); - p = stpcpy (p, "(public-key("); - p = stpcpy (p, algo_name); - for(i = 0; pub_elems[i]; i++) - { - *p++ = '('; - *p++ = pub_elems[i]; - p = stpcpy (p, "%m)"); - mpis[nelem++] = skey[i]; - } - p = stpcpy (p, "))"); - p = stpcpy (p, "(private-key("); - p = stpcpy (p, algo_name); - for (i = 0; sec_elems[i]; i++) - { - *p++ = '('; - *p++ = sec_elems[i]; - p = stpcpy (p, "%m)"); - mpis[nelem++] = skey[i]; - } - p = stpcpy (p, "))"); - - /* Hack to make release_mpi_array() work. */ - skey[i] = NULL; - - if (extrainfo) - { - /* If we have extrainfo we should not have any factors. */ - p = stpcpy (p, "%S"); - } - else if (factors && factors[0]) - { - p = stpcpy (p, "(misc-key-info(pm1-factors"); - for(i = 0; factors[i]; i++) - { - p = stpcpy (p, "%m"); - mpis[nelem++] = factors[i]; - } - p = stpcpy (p, "))"); - } - strcpy (p, ")"); - gcry_assert (p - string < needed); - - while (nelem < DIM (mpis)) - mpis[nelem++] = NULL; - - { - int elem_n = strlen (pub_elems) + strlen (sec_elems); - void **arg_list; - - /* Allocate one extra for EXTRAINFO ("%S"). */ - arg_list = gcry_calloc (nelem_cp+1, sizeof *arg_list); - if (!arg_list) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - for (i = 0; i < elem_n; i++) - arg_list[i] = mpis + i; - if (extrainfo) - arg_list[i] = &extrainfo; - else if (factors && factors[0]) - { - for (; i < nelem_cp; i++) - arg_list[i] = factors + i - elem_n; - } - - rc = gcry_sexp_build_array (r_key, NULL, string, arg_list); - gcry_free (arg_list); - if (rc) - BUG (); - gcry_assert (DIM (mpis) == 30); /* Reminder to make sure that - the array gets increased if - new parameters are added. */ - } - gcry_free (string); - } - - leave: - gcry_free (name); - gcry_sexp_release (extrainfo); - release_mpi_array (skey); - /* Don't free SKEY itself, it is an stack allocated array. */ - - if (factors) - { - release_mpi_array ( factors ); - gcry_free (factors); - } - - gcry_sexp_release (l3); - gcry_sexp_release (l2); - gcry_sexp_release (list); - - if (module) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - } - - return gcry_error (rc); -} - - -/* - Get the number of nbits from the public key. - - Hmmm: Should we have really this function or is it better to have a - more general function to retrieve different properties of the key? */ -unsigned int -gcry_pk_get_nbits (gcry_sexp_t key) -{ - gcry_module_t module = NULL; - gcry_pk_spec_t *pubkey; - gcry_mpi_t *keyarr = NULL; - unsigned int nbits = 0; - gcry_err_code_t rc; - - REGISTER_DEFAULT_PUBKEYS; - - rc = sexp_to_key (key, 0, &keyarr, &module); - if (rc == GPG_ERR_INV_OBJ) - rc = sexp_to_key (key, 1, &keyarr, &module); - if (rc) - return 0; /* Error - 0 is a suitable indication for that. */ - - pubkey = (gcry_pk_spec_t *) module->spec; - nbits = (*pubkey->get_nbits) (module->mod_id, keyarr); - - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - - release_mpi_array (keyarr); - gcry_free (keyarr); - - return nbits; -} - - -/* Return the so called KEYGRIP which is the SHA-1 hash of the public - key parameters expressed in a way depended on the algorithm. - - ARRAY must either be 20 bytes long or NULL; in the latter case a - newly allocated array of that size is returned, otherwise ARRAY or - NULL is returned to indicate an error which is most likely an - unknown algorithm. The function accepts public or secret keys. */ -unsigned char * -gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array) -{ - gcry_sexp_t list = NULL, l2 = NULL; - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - pk_extra_spec_t *extraspec; - const char *s; - char *name = NULL; - int idx; - const char *elems; - gcry_md_hd_t md = NULL; - - REGISTER_DEFAULT_PUBKEYS; - - /* Check that the first element is valid. */ - list = gcry_sexp_find_token (key, "public-key", 0); - if (! list) - list = gcry_sexp_find_token (key, "private-key", 0); - if (! list) - list = gcry_sexp_find_token (key, "protected-private-key", 0); - if (! list) - list = gcry_sexp_find_token (key, "shadowed-private-key", 0); - if (! list) - return NULL; /* No public- or private-key object. */ - - l2 = gcry_sexp_cadr (list); - gcry_sexp_release (list); - list = l2; - l2 = NULL; - - name = _gcry_sexp_nth_string (list, 0); - if (!name) - goto fail; /* Invalid structure of object. */ - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!module) - goto fail; /* Unknown algorithm. */ - - pubkey = (gcry_pk_spec_t *) module->spec; - extraspec = module->extraspec; - - elems = pubkey->elements_grip; - if (!elems) - goto fail; /* No grip parameter. */ - - if (gcry_md_open (&md, GCRY_MD_SHA1, 0)) - goto fail; - - if (extraspec && extraspec->comp_keygrip) - { - /* Module specific method to compute a keygrip. */ - if (extraspec->comp_keygrip (md, list)) - goto fail; - } - else - { - /* Generic method to compute a keygrip. */ - for (idx = 0, s = elems; *s; s++, idx++) - { - const char *data; - size_t datalen; - char buf[30]; - - l2 = gcry_sexp_find_token (list, s, 1); - if (! l2) - goto fail; - data = gcry_sexp_nth_data (l2, 1, &datalen); - if (! data) - goto fail; - - snprintf (buf, sizeof buf, "(1:%c%u:", *s, (unsigned int)datalen); - gcry_md_write (md, buf, strlen (buf)); - gcry_md_write (md, data, datalen); - gcry_sexp_release (l2); - gcry_md_write (md, ")", 1); - } - } - - if (!array) - { - array = gcry_malloc (20); - if (! array) - goto fail; - } - - memcpy (array, gcry_md_read (md, GCRY_MD_SHA1), 20); - gcry_md_close (md); - gcry_sexp_release (list); - return array; - - fail: - gcry_free (name); - gcry_sexp_release (l2); - gcry_md_close (md); - gcry_sexp_release (list); - return NULL; -} - - -gcry_error_t -gcry_pk_ctl (int cmd, void *buffer, size_t buflen) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - REGISTER_DEFAULT_PUBKEYS; - - switch (cmd) - { - case GCRYCTL_DISABLE_ALGO: - /* This one expects a buffer pointing to an integer with the - algo number. */ - if ((! buffer) || (buflen != sizeof (int))) - err = GPG_ERR_INV_ARG; - else - disable_pubkey_algo (*((int *) buffer)); - break; - - default: - err = GPG_ERR_INV_OP; - } - - return gcry_error (err); -} - - -/* Return information about the given algorithm - - WHAT selects the kind of information returned: - - GCRYCTL_TEST_ALGO: - Returns 0 when the specified algorithm is available for use. - Buffer must be NULL, nbytes may have the address of a variable - with the required usage of the algorithm. It may be 0 for don't - care or a combination of the GCRY_PK_USAGE_xxx flags; - - GCRYCTL_GET_ALGO_USAGE: - Return the usage glafs for the give algo. An invalid alog - does return 0. Disabled algos are ignored here becuase we - only want to know whether the algo is at all capable of - the usage. - - Note: Because this function is in most cases used to return an - integer value, we can make it easier for the caller to just look at - the return value. The caller will in all cases consult the value - and thereby detecting whether a error occured or not (i.e. while - checking the block size) */ -gcry_error_t -gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - switch (what) - { - case GCRYCTL_TEST_ALGO: - { - int use = nbytes ? *nbytes : 0; - if (buffer) - err = GPG_ERR_INV_ARG; - else if (check_pubkey_algo (algorithm, use)) - err = GPG_ERR_PUBKEY_ALGO; - break; - } - - case GCRYCTL_GET_ALGO_USAGE: - { - gcry_module_t pubkey; - int use = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - use = ((gcry_pk_spec_t *) pubkey->spec)->use; - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - /* FIXME? */ - *nbytes = use; - - break; - } - - case GCRYCTL_GET_ALGO_NPKEY: - { - /* FIXME? */ - int npkey = pubkey_get_npkey (algorithm); - *nbytes = npkey; - break; - } - case GCRYCTL_GET_ALGO_NSKEY: - { - /* FIXME? */ - int nskey = pubkey_get_nskey (algorithm); - *nbytes = nskey; - break; - } - case GCRYCTL_GET_ALGO_NSIGN: - { - /* FIXME? */ - int nsign = pubkey_get_nsig (algorithm); - *nbytes = nsign; - break; - } - case GCRYCTL_GET_ALGO_NENCR: - { - /* FIXME? */ - int nencr = pubkey_get_nenc (algorithm); - *nbytes = nencr; - break; - } - - default: - err = GPG_ERR_INV_OP; - } - - return gcry_error (err); -} - - -/* Explicitly initialize this module. */ -gcry_err_code_t -_gcry_pk_init (void) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - REGISTER_DEFAULT_PUBKEYS; - - return err; -} - - -gcry_err_code_t -_gcry_pk_module_lookup (int algorithm, gcry_module_t *module) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_module_t pubkey; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - *module = pubkey; - else - err = GPG_ERR_PUBKEY_ALGO; - ath_mutex_unlock (&pubkeys_registered_lock); - - return err; -} - - -void -_gcry_pk_module_release (gcry_module_t module) -{ - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); -} - -/* Get a list consisting of the IDs of the loaded pubkey modules. If - LIST is zero, write the number of loaded pubkey modules to - LIST_LENGTH and return. If LIST is non-zero, the first - *LIST_LENGTH algorithm IDs are stored in LIST, which must be of - according size. In case there are less pubkey modules than - *LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */ -gcry_error_t -gcry_pk_list (int *list, int *list_length) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - ath_mutex_lock (&pubkeys_registered_lock); - err = _gcry_module_list (pubkeys_registered, list, list_length); - ath_mutex_unlock (&pubkeys_registered_lock); - - return err; -} - - -/* Run the selftests for pubkey algorithm ALGO with optional reporting - function REPORT. */ -gpg_error_t -_gcry_pk_selftest (int algo, int extended, selftest_report_func_t report) -{ - gcry_module_t module = NULL; - pk_extra_spec_t *extraspec = NULL; - gcry_err_code_t ec = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algo); - if (module && !(module->flags & FLAG_MODULE_DISABLED)) - extraspec = module->extraspec; - ath_mutex_unlock (&pubkeys_registered_lock); - if (extraspec && extraspec->selftest) - ec = extraspec->selftest (algo, extended, report); - else - { - ec = GPG_ERR_PUBKEY_ALGO; - if (report) - report ("pubkey", algo, "module", - module && !(module->flags & FLAG_MODULE_DISABLED)? - "no selftest available" : - module? "algorithm disabled" : "algorithm not found"); - } - - if (module) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - } - return gpg_error (ec); -} - - -/* This function is only used by ac.c! */ -gcry_err_code_t -_gcry_pk_get_elements (int algo, char **enc, char **sig) -{ - gcry_module_t pubkey; - gcry_pk_spec_t *spec; - gcry_err_code_t err; - char *enc_cp; - char *sig_cp; - - REGISTER_DEFAULT_PUBKEYS; - - enc_cp = NULL; - sig_cp = NULL; - spec = NULL; - - pubkey = _gcry_module_lookup_id (pubkeys_registered, algo); - if (! pubkey) - { - err = GPG_ERR_INTERNAL; - goto out; - } - spec = pubkey->spec; - - if (enc) - { - enc_cp = strdup (spec->elements_enc); - if (! enc_cp) - { - err = gpg_err_code_from_errno (errno); - goto out; - } - } - - if (sig) - { - sig_cp = strdup (spec->elements_sig); - if (! sig_cp) - { - err = gpg_err_code_from_errno (errno); - goto out; - } - } - - if (enc) - *enc = enc_cp; - if (sig) - *sig = sig_cp; - err = 0; - - out: - - _gcry_module_release (pubkey); - if (err) - { - free (enc_cp); - free (sig_cp); - } - - return err; -} +/* pubkey.c - pubkey dispatcher + * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005, + * 2007, 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "ath.h" + + +static gcry_err_code_t pubkey_decrypt (int algo, gcry_mpi_t *result, + gcry_mpi_t *data, gcry_mpi_t *skey, + int flags); +static gcry_err_code_t pubkey_sign (int algo, gcry_mpi_t *resarr, + gcry_mpi_t hash, gcry_mpi_t *skey); +static gcry_err_code_t pubkey_verify (int algo, gcry_mpi_t hash, + gcry_mpi_t *data, gcry_mpi_t *pkey, + int (*cmp) (void *, gcry_mpi_t), + void *opaque); + + +/* A dummy extraspec so that we do not need to tests the extraspec + field from the module specification against NULL and instead + directly test the respective fields of extraspecs. */ +static pk_extra_spec_t dummy_extra_spec; + + +/* This is the list of the default public-key ciphers included in + libgcrypt. FIPS_ALLOWED indicated whether the algorithm is used in + FIPS mode. */ +static struct pubkey_table_entry +{ + gcry_pk_spec_t *pubkey; + pk_extra_spec_t *extraspec; + unsigned int algorithm; + int fips_allowed; +} pubkey_table[] = + { +#if USE_RSA + { &_gcry_pubkey_spec_rsa, + &_gcry_pubkey_extraspec_rsa, GCRY_PK_RSA, 1}, +#endif +#if USE_ELGAMAL + { &_gcry_pubkey_spec_elg, + &_gcry_pubkey_extraspec_elg, GCRY_PK_ELG }, + { &_gcry_pubkey_spec_elg, + &_gcry_pubkey_extraspec_elg, GCRY_PK_ELG_E }, +#endif +#if USE_DSA + { &_gcry_pubkey_spec_dsa, + &_gcry_pubkey_extraspec_dsa, GCRY_PK_DSA, 1 }, +#endif +#if USE_ECC + { &_gcry_pubkey_spec_ecdsa, + &_gcry_pubkey_extraspec_ecdsa, GCRY_PK_ECDSA, 0 }, +#endif + { NULL, 0 }, + }; + +/* List of registered ciphers. */ +static gcry_module_t pubkeys_registered; + +/* This is the lock protecting PUBKEYS_REGISTERED. */ +static ath_mutex_t pubkeys_registered_lock = ATH_MUTEX_INITIALIZER;; + +/* Flag to check whether the default pubkeys have already been + registered. */ +static int default_pubkeys_registered; + +/* Convenient macro for registering the default digests. */ +#define REGISTER_DEFAULT_PUBKEYS \ + do \ + { \ + ath_mutex_lock (&pubkeys_registered_lock); \ + if (! default_pubkeys_registered) \ + { \ + pk_register_default (); \ + default_pubkeys_registered = 1; \ + } \ + ath_mutex_unlock (&pubkeys_registered_lock); \ + } \ + while (0) + +/* These dummy functions are used in case a cipher implementation + refuses to provide it's own functions. */ + +static gcry_err_code_t +dummy_generate (int algorithm, unsigned int nbits, unsigned long dummy, + gcry_mpi_t *skey, gcry_mpi_t **retfactors) +{ + (void)algorithm; + (void)nbits; + (void)dummy; + (void)skey; + (void)retfactors; + fips_signal_error ("using dummy public key function"); + return GPG_ERR_NOT_IMPLEMENTED; +} + +static gcry_err_code_t +dummy_check_secret_key (int algorithm, gcry_mpi_t *skey) +{ + (void)algorithm; + (void)skey; + fips_signal_error ("using dummy public key function"); + return GPG_ERR_NOT_IMPLEMENTED; +} + +static gcry_err_code_t +dummy_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, + gcry_mpi_t *pkey, int flags) +{ + (void)algorithm; + (void)resarr; + (void)data; + (void)pkey; + (void)flags; + fips_signal_error ("using dummy public key function"); + return GPG_ERR_NOT_IMPLEMENTED; +} + +static gcry_err_code_t +dummy_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data, + gcry_mpi_t *skey, int flags) +{ + (void)algorithm; + (void)result; + (void)data; + (void)skey; + (void)flags; + fips_signal_error ("using dummy public key function"); + return GPG_ERR_NOT_IMPLEMENTED; +} + +static gcry_err_code_t +dummy_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, + gcry_mpi_t *skey) +{ + (void)algorithm; + (void)resarr; + (void)data; + (void)skey; + fips_signal_error ("using dummy public key function"); + return GPG_ERR_NOT_IMPLEMENTED; +} + +static gcry_err_code_t +dummy_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data, + gcry_mpi_t *pkey, + int (*cmp) (void *, gcry_mpi_t), void *opaquev) +{ + (void)algorithm; + (void)hash; + (void)data; + (void)pkey; + (void)cmp; + (void)opaquev; + fips_signal_error ("using dummy public key function"); + return GPG_ERR_NOT_IMPLEMENTED; +} + +static unsigned +dummy_get_nbits (int algorithm, gcry_mpi_t *pkey) +{ + (void)algorithm; + (void)pkey; + fips_signal_error ("using dummy public key function"); + return 0; +} + +/* Internal function. Register all the pubkeys included in + PUBKEY_TABLE. Returns zero on success or an error code. */ +static void +pk_register_default (void) +{ + gcry_err_code_t err = 0; + int i; + + for (i = 0; (! err) && pubkey_table[i].pubkey; i++) + { +#define pubkey_use_dummy(func) \ + if (! pubkey_table[i].pubkey->func) \ + pubkey_table[i].pubkey->func = dummy_##func; + + pubkey_use_dummy (generate); + pubkey_use_dummy (check_secret_key); + pubkey_use_dummy (encrypt); + pubkey_use_dummy (decrypt); + pubkey_use_dummy (sign); + pubkey_use_dummy (verify); + pubkey_use_dummy (get_nbits); +#undef pubkey_use_dummy + + err = _gcry_module_add (&pubkeys_registered, + pubkey_table[i].algorithm, + (void *) pubkey_table[i].pubkey, + (void *) pubkey_table[i].extraspec, + NULL); + } + + if (err) + BUG (); +} + +/* Internal callback function. Used via _gcry_module_lookup. */ +static int +gcry_pk_lookup_func_name (void *spec, void *data) +{ + gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) spec; + char *name = (char *) data; + const char **aliases = pubkey->aliases; + int ret = _stricmp (name, pubkey->name); + + while (ret && *aliases) + ret = _stricmp (name, *aliases++); + + return ! ret; +} + +/* Internal function. Lookup a pubkey entry by it's name. */ +static gcry_module_t +gcry_pk_lookup_name (const char *name) +{ + gcry_module_t pubkey; + + pubkey = _gcry_module_lookup (pubkeys_registered, (void *) name, + gcry_pk_lookup_func_name); + + return pubkey; +} + +/* Register a new pubkey module whose specification can be found in + PUBKEY. On success, a new algorithm ID is stored in ALGORITHM_ID + and a pointer representhing this module is stored in MODULE. */ +gcry_error_t +_gcry_pk_register (gcry_pk_spec_t *pubkey, + pk_extra_spec_t *extraspec, + unsigned int *algorithm_id, + gcry_module_t *module) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_module_t mod; + + /* We do not support module loading in fips mode. */ + if (fips_mode ()) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + + ath_mutex_lock (&pubkeys_registered_lock); + err = _gcry_module_add (&pubkeys_registered, 0, + (void *) pubkey, + (void *)(extraspec? extraspec : &dummy_extra_spec), + &mod); + ath_mutex_unlock (&pubkeys_registered_lock); + + if (! err) + { + *module = mod; + *algorithm_id = mod->mod_id; + } + + return err; +} + +/* Unregister the pubkey identified by ID, which must have been + registered with gcry_pk_register. */ +void +gcry_pk_unregister (gcry_module_t module) +{ + ath_mutex_lock (&pubkeys_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&pubkeys_registered_lock); +} + +static void +release_mpi_array (gcry_mpi_t *array) +{ + for (; *array; array++) + { + mpi_free(*array); + *array = NULL; + } +} + +/**************** + * Map a string to the pubkey algo + */ +int +gcry_pk_map_name (const char *string) +{ + gcry_module_t pubkey; + int algorithm = 0; + + if (!string) + return 0; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + pubkey = gcry_pk_lookup_name (string); + if (pubkey) + { + algorithm = pubkey->mod_id; + _gcry_module_release (pubkey); + } + ath_mutex_unlock (&pubkeys_registered_lock); + + return algorithm; +} + + +/* Map the public key algorithm whose ID is contained in ALGORITHM to + a string representation of the algorithm name. For unknown + algorithm IDs this functions returns "?". */ +const char * +gcry_pk_algo_name (int algorithm) +{ + gcry_module_t pubkey; + const char *name; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (pubkey) + { + name = ((gcry_pk_spec_t *) pubkey->spec)->name; + _gcry_module_release (pubkey); + } + else + name = "?"; + ath_mutex_unlock (&pubkeys_registered_lock); + + return name; +} + + +/* A special version of gcry_pk_algo name to return the first aliased + name of the algorithm. This is required to adhere to the spki + specs where the algorithm names are lowercase. */ +const char * +_gcry_pk_aliased_algo_name (int algorithm) +{ + const char *name = NULL; + gcry_module_t module; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + module = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (module) + { + gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) module->spec; + + name = pubkey->aliases? *pubkey->aliases : NULL; + if (!name || !*name) + name = pubkey->name; + _gcry_module_release (module); + } + ath_mutex_unlock (&pubkeys_registered_lock); + + return name; +} + + +static void +disable_pubkey_algo (int algorithm) +{ + gcry_module_t pubkey; + + ath_mutex_lock (&pubkeys_registered_lock); + pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (pubkey) + { + if (! (pubkey-> flags & FLAG_MODULE_DISABLED)) + pubkey->flags |= FLAG_MODULE_DISABLED; + _gcry_module_release (pubkey); + } + ath_mutex_unlock (&pubkeys_registered_lock); +} + + +/**************** + * A USE of 0 means: don't care. + */ +static gcry_err_code_t +check_pubkey_algo (int algorithm, unsigned use) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_pk_spec_t *pubkey; + gcry_module_t module; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + module = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (module) + { + pubkey = (gcry_pk_spec_t *) module->spec; + + if (((use & GCRY_PK_USAGE_SIGN) + && (! (pubkey->use & GCRY_PK_USAGE_SIGN))) + || ((use & GCRY_PK_USAGE_ENCR) + && (! (pubkey->use & GCRY_PK_USAGE_ENCR)))) + err = GPG_ERR_WRONG_PUBKEY_ALGO; + else if (module->flags & FLAG_MODULE_DISABLED) + err = GPG_ERR_PUBKEY_ALGO; + _gcry_module_release (module); + } + else + err = GPG_ERR_PUBKEY_ALGO; + ath_mutex_unlock (&pubkeys_registered_lock); + + return err; +} + + +/**************** + * Return the number of public key material numbers + */ +static int +pubkey_get_npkey (int algorithm) +{ + gcry_module_t pubkey; + int npkey = 0; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (pubkey) + { + npkey = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_pkey); + _gcry_module_release (pubkey); + } + ath_mutex_unlock (&pubkeys_registered_lock); + + return npkey; +} + +/**************** + * Return the number of secret key material numbers + */ +static int +pubkey_get_nskey (int algorithm) +{ + gcry_module_t pubkey; + int nskey = 0; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (pubkey) + { + nskey = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_skey); + _gcry_module_release (pubkey); + } + ath_mutex_unlock (&pubkeys_registered_lock); + + return nskey; +} + +/**************** + * Return the number of signature material numbers + */ +static int +pubkey_get_nsig (int algorithm) +{ + gcry_module_t pubkey; + int nsig = 0; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (pubkey) + { + nsig = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_sig); + _gcry_module_release (pubkey); + } + ath_mutex_unlock (&pubkeys_registered_lock); + + return nsig; +} + +/**************** + * Return the number of encryption material numbers + */ +static int +pubkey_get_nenc (int algorithm) +{ + gcry_module_t pubkey; + int nenc = 0; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (pubkey) + { + nenc = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_enc); + _gcry_module_release (pubkey); + } + ath_mutex_unlock (&pubkeys_registered_lock); + + return nenc; +} + + +/* Generate a new public key with algorithm ALGORITHM of size NBITS + and return it at SKEY. USE_E depends on the ALGORITHM. GENPARMS + is passed to the algorithm module if it features an extended + generation function. RETFACTOR is used by some algorithms to + return certain additional information which are in general not + required. + + The function returns the error code number or 0 on success. */ +static gcry_err_code_t +pubkey_generate (int algorithm, + unsigned int nbits, + unsigned long use_e, + gcry_sexp_t genparms, + gcry_mpi_t *skey, gcry_mpi_t **retfactors, + gcry_sexp_t *r_extrainfo) +{ + gcry_err_code_t ec = GPG_ERR_PUBKEY_ALGO; + gcry_module_t pubkey; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (pubkey) + { + pk_extra_spec_t *extraspec = pubkey->extraspec; + + if (extraspec && extraspec->ext_generate) + { + /* Use the extended generate function. */ + ec = extraspec->ext_generate + (algorithm, nbits, use_e, genparms, skey, retfactors, r_extrainfo); + } + else + { + /* Use the standard generate function. */ + ec = ((gcry_pk_spec_t *) pubkey->spec)->generate + (algorithm, nbits, use_e, skey, retfactors); + } + _gcry_module_release (pubkey); + } + ath_mutex_unlock (&pubkeys_registered_lock); + + return ec; +} + + +static gcry_err_code_t +pubkey_check_secret_key (int algorithm, gcry_mpi_t *skey) +{ + gcry_err_code_t err = GPG_ERR_PUBKEY_ALGO; + gcry_module_t pubkey; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (pubkey) + { + err = ((gcry_pk_spec_t *) pubkey->spec)->check_secret_key + (algorithm, skey); + _gcry_module_release (pubkey); + } + ath_mutex_unlock (&pubkeys_registered_lock); + + return err; +} + + +/**************** + * This is the interface to the public key encryption. Encrypt DATA + * with PKEY and put it into RESARR which should be an array of MPIs + * of size PUBKEY_MAX_NENC (or less if the algorithm allows this - + * check with pubkey_get_nenc() ) + */ +static gcry_err_code_t +pubkey_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, + gcry_mpi_t *pkey, int flags) +{ + gcry_pk_spec_t *pubkey; + gcry_module_t module; + gcry_err_code_t rc; + int i; + + /* Note: In fips mode DBG_CIPHER will enver evaluate to true but as + an extra failsafe protection we explicitly test for fips mode + here. */ + if (DBG_CIPHER && !fips_mode ()) + { + log_debug ("pubkey_encrypt: algo=%d\n", algorithm); + for(i = 0; i < pubkey_get_npkey (algorithm); i++) + log_mpidump (" pkey:", pkey[i]); + log_mpidump (" data:", data); + } + + ath_mutex_lock (&pubkeys_registered_lock); + module = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (module) + { + pubkey = (gcry_pk_spec_t *) module->spec; + rc = pubkey->encrypt (algorithm, resarr, data, pkey, flags); + _gcry_module_release (module); + goto ready; + } + rc = GPG_ERR_PUBKEY_ALGO; + + ready: + ath_mutex_unlock (&pubkeys_registered_lock); + + if (!rc && DBG_CIPHER && !fips_mode ()) + { + for(i = 0; i < pubkey_get_nenc (algorithm); i++) + log_mpidump(" encr:", resarr[i] ); + } + return rc; +} + + +/**************** + * This is the interface to the public key decryption. + * ALGO gives the algorithm to use and this implicitly determines + * the size of the arrays. + * result is a pointer to a mpi variable which will receive a + * newly allocated mpi or NULL in case of an error. + */ +static gcry_err_code_t +pubkey_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data, + gcry_mpi_t *skey, int flags) +{ + gcry_pk_spec_t *pubkey; + gcry_module_t module; + gcry_err_code_t rc; + int i; + + *result = NULL; /* so the caller can always do a mpi_free */ + if (DBG_CIPHER && !fips_mode ()) + { + log_debug ("pubkey_decrypt: algo=%d\n", algorithm); + for(i = 0; i < pubkey_get_nskey (algorithm); i++) + log_mpidump (" skey:", skey[i]); + for(i = 0; i < pubkey_get_nenc (algorithm); i++) + log_mpidump (" data:", data[i]); + } + + ath_mutex_lock (&pubkeys_registered_lock); + module = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (module) + { + pubkey = (gcry_pk_spec_t *) module->spec; + rc = pubkey->decrypt (algorithm, result, data, skey, flags); + _gcry_module_release (module); + goto ready; + } + + rc = GPG_ERR_PUBKEY_ALGO; + + ready: + ath_mutex_unlock (&pubkeys_registered_lock); + + if (!rc && DBG_CIPHER && !fips_mode ()) + log_mpidump (" plain:", *result); + + return rc; +} + + +/**************** + * This is the interface to the public key signing. + * Sign data with skey and put the result into resarr which + * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the + * algorithm allows this - check with pubkey_get_nsig() ) + */ +static gcry_err_code_t +pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, + gcry_mpi_t *skey) +{ + gcry_pk_spec_t *pubkey; + gcry_module_t module; + gcry_err_code_t rc; + int i; + + if (DBG_CIPHER && !fips_mode ()) + { + log_debug ("pubkey_sign: algo=%d\n", algorithm); + for(i = 0; i < pubkey_get_nskey (algorithm); i++) + log_mpidump (" skey:", skey[i]); + log_mpidump(" data:", data ); + } + + ath_mutex_lock (&pubkeys_registered_lock); + module = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (module) + { + pubkey = (gcry_pk_spec_t *) module->spec; + rc = pubkey->sign (algorithm, resarr, data, skey); + _gcry_module_release (module); + goto ready; + } + + rc = GPG_ERR_PUBKEY_ALGO; + + ready: + ath_mutex_unlock (&pubkeys_registered_lock); + + if (!rc && DBG_CIPHER && !fips_mode ()) + for (i = 0; i < pubkey_get_nsig (algorithm); i++) + log_mpidump (" sig:", resarr[i]); + + return rc; +} + +/**************** + * Verify a public key signature. + * Return 0 if the signature is good + */ +static gcry_err_code_t +pubkey_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data, + gcry_mpi_t *pkey, + int (*cmp)(void *, gcry_mpi_t), void *opaquev) +{ + gcry_pk_spec_t *pubkey; + gcry_module_t module; + gcry_err_code_t rc; + int i; + + if (DBG_CIPHER && !fips_mode ()) + { + log_debug ("pubkey_verify: algo=%d\n", algorithm); + for (i = 0; i < pubkey_get_npkey (algorithm); i++) + log_mpidump (" pkey:", pkey[i]); + for (i = 0; i < pubkey_get_nsig (algorithm); i++) + log_mpidump (" sig:", data[i]); + log_mpidump (" hash:", hash); + } + + ath_mutex_lock (&pubkeys_registered_lock); + module = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (module) + { + pubkey = (gcry_pk_spec_t *) module->spec; + rc = pubkey->verify (algorithm, hash, data, pkey, cmp, opaquev); + _gcry_module_release (module); + goto ready; + } + + rc = GPG_ERR_PUBKEY_ALGO; + + ready: + ath_mutex_unlock (&pubkeys_registered_lock); + return rc; +} + + +/* Internal function. */ +static gcry_err_code_t +sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names, + gcry_mpi_t *elements, const char *algo_name) +{ + gcry_err_code_t err = 0; + int i, idx; + const char *name; + gcry_sexp_t list; + + for (name = element_names, idx = 0; *name && !err; name++, idx++) + { + list = gcry_sexp_find_token (key_sexp, name, 1); + if (!list) + elements[idx] = NULL; + else + { + elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (list); + if (!elements[idx]) + err = GPG_ERR_INV_OBJ; + } + } + + if (!err) + { + /* Check that all elements are available. */ + for (name = element_names, idx = 0; *name; name++, idx++) + if (!elements[idx]) + break; + if (*name) + { + err = GPG_ERR_NO_OBJ; + /* Some are missing. Before bailing out we test for + optional parameters. */ + if (algo_name && !strcmp (algo_name, "RSA") + && !strcmp (element_names, "nedpqu") ) + { + /* This is RSA. Test whether we got N, E and D and that + the optional P, Q and U are all missing. */ + if (elements[0] && elements[1] && elements[2] + && !elements[3] && !elements[4] && !elements[5]) + err = 0; + } + } + } + + + if (err) + { + for (i = 0; i < idx; i++) + if (elements[i]) + gcry_free (elements[i]); + } + return err; +} + + +/* Internal function used for ecc. Note, that this function makes use + of its intimate knowledge about the ECC parameters from ecc.c. */ +static gcry_err_code_t +sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names, + gcry_mpi_t *elements, pk_extra_spec_t *extraspec) + +{ + gcry_err_code_t err = 0; + int idx; + const char *name; + gcry_sexp_t list; + + /* Clear the array for easier error cleanup. */ + for (name = element_names, idx = 0; *name; name++, idx++) + elements[idx] = NULL; + gcry_assert (idx >= 6); /* We know that ECC has at least 6 elements. */ + + /* Init the array with the available curve parameters. */ + for (name = element_names, idx = 0; *name && !err; name++, idx++) + { + list = gcry_sexp_find_token (key_sexp, name, 1); + if (!list) + elements[idx] = NULL; + else + { + elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (list); + if (!elements[idx]) + { + err = GPG_ERR_INV_OBJ; + goto leave; + } + } + } + + /* Check whether a curve parameter has been given and then fill any + missing elements. */ + list = gcry_sexp_find_token (key_sexp, "curve", 5); + if (list) + { + if (extraspec->get_param) + { + char *curve; + gcry_mpi_t params[6]; + + for (idx = 0; idx < DIM(params); idx++) + params[idx] = NULL; + + curve = _gcry_sexp_nth_string (list, 1); + gcry_sexp_release (list); + if (!curve) + { + /* No curve name given (or out of core). */ + err = GPG_ERR_INV_OBJ; + goto leave; + } + err = extraspec->get_param (curve, params); + gcry_free (curve); + if (err) + goto leave; + + for (idx = 0; idx < DIM(params); idx++) + { + if (!elements[idx]) + elements[idx] = params[idx]; + else + mpi_free (params[idx]); + } + } + else + { + gcry_sexp_release (list); + err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */ + goto leave; + } + } + + /* Check that all parameters are known. */ + for (name = element_names, idx = 0; *name; name++, idx++) + if (!elements[idx]) + { + err = GPG_ERR_NO_OBJ; + goto leave; + } + + leave: + if (err) + { + for (name = element_names, idx = 0; *name; name++, idx++) + if (elements[idx]) + gcry_free (elements[idx]); + } + return err; +} + + + +/**************** + * Convert a S-Exp with either a private or a public key to our + * internal format. Currently we do only support the following + * algorithms: + * dsa + * rsa + * openpgp-dsa + * openpgp-rsa + * openpgp-elg + * openpgp-elg-sig + * ecdsa + * Provide a SE with the first element be either "private-key" or + * or "public-key". It is followed by a list with its first element + * be one of the above algorithm identifiers and the remaning + * elements are pairs with parameter-id and value. + * NOTE: we look through the list to find a list beginning with + * "private-key" or "public-key" - the first one found is used. + * + * Returns: A pointer to an allocated array of MPIs if the return value is + * zero; the caller has to release this array. + * + * Example of a DSA public key: + * (private-key + * (dsa + * (p ) + * (g ) + * (y ) + * (x ) + * ) + * ) + * The are expected to be in GCRYMPI_FMT_USG + */ +static gcry_err_code_t +sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray, + gcry_module_t *retalgo) +{ + gcry_err_code_t err = 0; + gcry_sexp_t list, l2; + char *name; + const char *elems; + gcry_mpi_t *array; + gcry_module_t module; + gcry_pk_spec_t *pubkey; + pk_extra_spec_t *extraspec; + int is_ecc; + + /* Check that the first element is valid. */ + list = gcry_sexp_find_token (sexp, + want_private? "private-key":"public-key", 0); + if (!list) + return GPG_ERR_INV_OBJ; /* Does not contain a key object. */ + + l2 = gcry_sexp_cadr( list ); + gcry_sexp_release ( list ); + list = l2; + name = _gcry_sexp_nth_string (list, 0); + if (!name) + { + gcry_sexp_release ( list ); + return GPG_ERR_INV_OBJ; /* Invalid structure of object. */ + } + + ath_mutex_lock (&pubkeys_registered_lock); + module = gcry_pk_lookup_name (name); + ath_mutex_unlock (&pubkeys_registered_lock); + + /* Fixme: We should make sure that an ECC key is always named "ecc" + and not "ecdsa". "ecdsa" should be used for the signature + itself. We need a function to test whether an algorithm given + with a key is compatible with an application of the key (signing, + encryption). For RSA this is easy, but ECC is the first + algorithm which has many flavours. */ + is_ecc = ( !strcmp (name, "ecdsa") || !strcmp (name, "ecc") ); + gcry_free (name); + + if (!module) + { + gcry_sexp_release (list); + return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ + } + else + { + pubkey = (gcry_pk_spec_t *) module->spec; + extraspec = module->extraspec; + } + + elems = want_private ? pubkey->elements_skey : pubkey->elements_pkey; + array = gcry_calloc (strlen (elems) + 1, sizeof (*array)); + if (!array) + err = gpg_err_code_from_errno (errno); + if (!err) + { + if (is_ecc) + err = sexp_elements_extract_ecc (list, elems, array, extraspec); + else + err = sexp_elements_extract (list, elems, array, pubkey->name); + } + + gcry_sexp_release (list); + + if (err) + { + gcry_free (array); + + ath_mutex_lock (&pubkeys_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&pubkeys_registered_lock); + } + else + { + *retarray = array; + *retalgo = module; + } + + return err; +} + + +static gcry_err_code_t +sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray, + gcry_module_t *retalgo) +{ + gcry_err_code_t err = 0; + gcry_sexp_t list, l2; + char *name; + const char *elems; + gcry_mpi_t *array; + gcry_module_t module; + gcry_pk_spec_t *pubkey; + + /* Check that the first element is valid. */ + list = gcry_sexp_find_token( sexp, "sig-val" , 0 ); + if (!list) + return GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */ + + l2 = gcry_sexp_nth (list, 1); + if (!l2) + { + gcry_sexp_release (list); + return GPG_ERR_NO_OBJ; /* No cadr for the sig object. */ + } + name = _gcry_sexp_nth_string (l2, 0); + if (!name) + { + gcry_sexp_release (list); + gcry_sexp_release (l2); + return GPG_ERR_INV_OBJ; /* Invalid structure of object. */ + } + else if (!strcmp (name, "flags")) + { + /* Skip flags, since they are not used but here just for the + sake of consistent S-expressions. */ + gcry_free (name); + gcry_sexp_release (l2); + l2 = gcry_sexp_nth (list, 2); + if (!l2) + { + gcry_sexp_release (list); + return GPG_ERR_INV_OBJ; + } + name = _gcry_sexp_nth_string (l2, 0); + } + + ath_mutex_lock (&pubkeys_registered_lock); + module = gcry_pk_lookup_name (name); + ath_mutex_unlock (&pubkeys_registered_lock); + gcry_free (name); + name = NULL; + + if (!module) + { + gcry_sexp_release (l2); + gcry_sexp_release (list); + return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ + } + else + pubkey = (gcry_pk_spec_t *) module->spec; + + elems = pubkey->elements_sig; + array = gcry_calloc (strlen (elems) + 1 , sizeof *array ); + if (!array) + err = gpg_err_code_from_errno (errno); + + if (!err) + err = sexp_elements_extract (list, elems, array, NULL); + + gcry_sexp_release (l2); + gcry_sexp_release (list); + + if (err) + { + ath_mutex_lock (&pubkeys_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&pubkeys_registered_lock); + + gcry_free (array); + } + else + { + *retarray = array; + *retalgo = module; + } + + return err; +} + + +/**************** + * Take sexp and return an array of MPI as used for our internal decrypt + * function. + * s_data = (enc-val + * [(flags [pkcs1])] + * ( + * ( ) + * ... + * ( ) + * )) + * RET_MODERN is set to true when at least an empty flags list has been found. + */ +static gcry_err_code_t +sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo, + int *ret_modern, int *ret_want_pkcs1, int *flags) +{ + gcry_err_code_t err = 0; + gcry_sexp_t list = NULL, l2 = NULL; + gcry_pk_spec_t *pubkey = NULL; + gcry_module_t module = NULL; + char *name = NULL; + size_t n; + int parsed_flags = 0; + const char *elems; + gcry_mpi_t *array = NULL; + + *ret_want_pkcs1 = 0; + *ret_modern = 0; + + /* Check that the first element is valid. */ + list = gcry_sexp_find_token (sexp, "enc-val" , 0); + if (!list) + { + err = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */ + goto leave; + } + + l2 = gcry_sexp_nth (list, 1); + if (!l2) + { + err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */ + goto leave; + } + + /* Extract identifier of sublist. */ + name = _gcry_sexp_nth_string (l2, 0); + if (!name) + { + err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ + goto leave; + } + + if (!strcmp (name, "flags")) + { + /* There is a flags element - process it. */ + const char *s; + int i; + + *ret_modern = 1; + for (i = gcry_sexp_length (l2) - 1; i > 0; i--) + { + s = gcry_sexp_nth_data (l2, i, &n); + if (! s) + ; /* Not a data element - ignore. */ + else if (n == 3 && !memcmp (s, "raw", 3)) + ; /* This is just a dummy as it is the default. */ + else if (n == 5 && !memcmp (s, "pkcs1", 5)) + *ret_want_pkcs1 = 1; + else if (n == 11 && ! memcmp (s, "no-blinding", 11)) + parsed_flags |= PUBKEY_FLAG_NO_BLINDING; + else + { + err = GPG_ERR_INV_FLAG; + goto leave; + } + } + + /* Get the next which has the actual data. */ + gcry_sexp_release (l2); + l2 = gcry_sexp_nth (list, 2); + if (!l2) + { + err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */ + goto leave; + } + + /* Extract sublist identifier. */ + gcry_free (name); + name = _gcry_sexp_nth_string (l2, 0); + if (!name) + { + err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ + goto leave; + } + + gcry_sexp_release (list); + list = l2; + l2 = NULL; + } + + ath_mutex_lock (&pubkeys_registered_lock); + module = gcry_pk_lookup_name (name); + ath_mutex_unlock (&pubkeys_registered_lock); + + if (!module) + { + err = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ + goto leave; + } + pubkey = (gcry_pk_spec_t *) module->spec; + + elems = pubkey->elements_enc; + array = gcry_calloc (strlen (elems) + 1, sizeof (*array)); + if (!array) + { + err = gpg_err_code_from_errno (errno); + goto leave; + } + + err = sexp_elements_extract (list, elems, array, NULL); + + leave: + gcry_sexp_release (list); + gcry_sexp_release (l2); + gcry_free (name); + + if (err) + { + ath_mutex_lock (&pubkeys_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&pubkeys_registered_lock); + gcry_free (array); + } + else + { + *retarray = array; + *retalgo = module; + *flags = parsed_flags; + } + + return err; +} + +/* Take the hash value and convert into an MPI, suitable for + passing to the low level functions. We currently support the + old style way of passing just a MPI and the modern interface which + allows to pass flags so that we can choose between raw and pkcs1 + padding - may be more padding options later. + + () + or + (data + [(flags [pkcs1])] + [(hash )] + [(value )] + ) + + Either the VALUE or the HASH element must be present for use + with signatures. VALUE is used for encryption. + + NBITS is the length of the key in bits. + +*/ +static gcry_err_code_t +sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi, + int for_encryption, int *flags) +{ + gcry_err_code_t rc = 0; + gcry_sexp_t ldata, lhash, lvalue; + int i; + size_t n; + const char *s; + int is_raw = 0, is_pkcs1 = 0, unknown_flag=0; + int parsed_flags = 0, dummy_flags; + + if (! flags) + flags = &dummy_flags; + + *ret_mpi = NULL; + ldata = gcry_sexp_find_token (input, "data", 0); + if (!ldata) + { /* assume old style */ + *ret_mpi = gcry_sexp_nth_mpi (input, 0, 0); + return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ; + } + + /* see whether there is a flags object */ + { + gcry_sexp_t lflags = gcry_sexp_find_token (ldata, "flags", 0); + if (lflags) + { /* parse the flags list. */ + for (i=gcry_sexp_length (lflags)-1; i > 0; i--) + { + s = gcry_sexp_nth_data (lflags, i, &n); + if (!s) + ; /* not a data element*/ + else if ( n == 3 && !memcmp (s, "raw", 3)) + is_raw = 1; + else if ( n == 5 && !memcmp (s, "pkcs1", 5)) + is_pkcs1 = 1; + else if (n == 11 && ! memcmp (s, "no-blinding", 11)) + parsed_flags |= PUBKEY_FLAG_NO_BLINDING; + else + unknown_flag = 1; + } + gcry_sexp_release (lflags); + } + } + + if (!is_pkcs1 && !is_raw) + is_raw = 1; /* default to raw */ + + /* Get HASH or MPI */ + lhash = gcry_sexp_find_token (ldata, "hash", 0); + lvalue = lhash? NULL : gcry_sexp_find_token (ldata, "value", 0); + + if (!(!lhash ^ !lvalue)) + rc = GPG_ERR_INV_OBJ; /* none or both given */ + else if (unknown_flag) + rc = GPG_ERR_INV_FLAG; + else if (is_raw && is_pkcs1 && !for_encryption) + rc = GPG_ERR_CONFLICT; + else if (is_raw && lvalue) + { + *ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, 0); + if (!*ret_mpi) + rc = GPG_ERR_INV_OBJ; + } + else if (is_pkcs1 && lvalue && for_encryption) + { + /* Create pkcs#1 block type 2 padding. */ + unsigned char *frame = NULL; + size_t nframe = (nbits+7) / 8; + const void * value; + size_t valuelen; + unsigned char *p; + + if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen ) + rc = GPG_ERR_INV_OBJ; + else if (valuelen + 7 > nframe || !nframe) + { + /* Can't encode a VALUELEN value in a NFRAME bytes frame. */ + rc = GPG_ERR_TOO_SHORT; /* the key is too short */ + } + else if ( !(frame = gcry_malloc_secure (nframe))) + rc = gpg_err_code_from_errno (errno); + else + { + n = 0; + frame[n++] = 0; + frame[n++] = 2; /* block type */ + i = nframe - 3 - valuelen; + gcry_assert (i > 0); + p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM); + /* Replace zero bytes by new values. */ + for (;;) + { + int j, k; + unsigned char *pp; + + /* Count the zero bytes. */ + for (j=k=0; j < i; j++) + { + if (!p[j]) + k++; + } + if (!k) + break; /* Okay: no (more) zero bytes. */ + + k += k/128 + 3; /* Better get some more. */ + pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM); + for (j=0; j < i && k; ) + { + if (!p[j]) + p[j] = pp[--k]; + if (p[j]) + j++; + } + gcry_free (pp); + } + memcpy (frame+n, p, i); + n += i; + gcry_free (p); + + frame[n++] = 0; + memcpy (frame+n, value, valuelen); + n += valuelen; + gcry_assert (n == nframe); + + /* FIXME, error checking? */ + gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, n, &nframe); + } + + gcry_free(frame); + } + else if (is_pkcs1 && lhash && !for_encryption) + { + /* Create pkcs#1 block type 1 padding. */ + if (gcry_sexp_length (lhash) != 3) + rc = GPG_ERR_INV_OBJ; + else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n ) + rc = GPG_ERR_INV_OBJ; + else + { + static struct { const char *name; int algo; } hashnames[] = + { { "sha1", GCRY_MD_SHA1 }, + { "md5", GCRY_MD_MD5 }, + { "sha256", GCRY_MD_SHA256 }, + { "ripemd160", GCRY_MD_RMD160 }, + { "rmd160", GCRY_MD_RMD160 }, + { "sha384", GCRY_MD_SHA384 }, + { "sha512", GCRY_MD_SHA512 }, + { "sha224", GCRY_MD_SHA224 }, + { "md2", GCRY_MD_MD2 }, + { "md4", GCRY_MD_MD4 }, + { "tiger", GCRY_MD_TIGER }, + { "haval", GCRY_MD_HAVAL }, + { NULL, 0 } + }; + int algo; + byte asn[100]; + byte *frame = NULL; + size_t nframe = (nbits+7) / 8; + const void * value; + size_t valuelen; + size_t asnlen, dlen; + + for (i=0; hashnames[i].name; i++) + { + if ( strlen (hashnames[i].name) == n + && !memcmp (hashnames[i].name, s, n)) + break; + } + if (hashnames[i].name) + algo = hashnames[i].algo; + else + { + /* In case of not listed or dynamically allocated hash + algorithm we fall back to this somewhat slower + method. Further, it also allows to use OIDs as + algorithm names. */ + char *tmpname; + + tmpname = gcry_malloc (n+1); + if (!tmpname) + algo = 0; /* Out of core - silently give up. */ + else + { + memcpy (tmpname, s, n); + tmpname[n] = 0; + algo = gcry_md_map_name (tmpname); + gcry_free (tmpname); + } + } + + asnlen = DIM(asn); + dlen = gcry_md_get_algo_dlen (algo); + + if (!algo) + rc = GPG_ERR_DIGEST_ALGO; + else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen)) + || !valuelen ) + rc = GPG_ERR_INV_OBJ; + else if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen)) + { + /* We don't have yet all of the above algorithms. */ + rc = GPG_ERR_NOT_IMPLEMENTED; + } + else if ( valuelen != dlen ) + { + /* Hash value does not match the length of digest for + the given algorithm. */ + rc = GPG_ERR_CONFLICT; + } + else if( !dlen || dlen + asnlen + 4 > nframe) + { + /* Can't encode an DLEN byte digest MD into a NFRAME + byte frame. */ + rc = GPG_ERR_TOO_SHORT; + } + else if ( !(frame = gcry_malloc (nframe)) ) + rc = gpg_err_code_from_errno (errno); + else + { /* Assemble the pkcs#1 block type 1. */ + n = 0; + frame[n++] = 0; + frame[n++] = 1; /* block type */ + i = nframe - valuelen - asnlen - 3 ; + gcry_assert (i > 1); + memset (frame+n, 0xff, i ); + n += i; + frame[n++] = 0; + memcpy (frame+n, asn, asnlen); + n += asnlen; + memcpy (frame+n, value, valuelen ); + n += valuelen; + gcry_assert (n == nframe); + + /* Convert it into an MPI. FIXME: error checking? */ + gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, n, &nframe); + } + + gcry_free (frame); + } + } + else + rc = GPG_ERR_CONFLICT; + + gcry_sexp_release (ldata); + gcry_sexp_release (lhash); + gcry_sexp_release (lvalue); + + if (!rc) + *flags = parsed_flags; + + return rc; +} + + +/* + Do a PK encrypt operation + + Caller has to provide a public key as the SEXP pkey and data as a + SEXP with just one MPI in it. Alternatively S_DATA might be a + complex S-Expression, similar to the one used for signature + verification. This provides a flag which allows to handle PKCS#1 + block type 2 padding. The function returns a a sexp which may be + passed to to pk_decrypt. + + Returns: 0 or an errorcode. + + s_data = See comment for sexp_data_to_mpi + s_pkey = + r_ciph = (enc-val + ( + ( ) + ... + ( ) + )) + +*/ +gcry_error_t +gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey) +{ + gcry_mpi_t *pkey = NULL, data = NULL, *ciph = NULL; + const char *algo_name, *algo_elems; + int flags; + gcry_err_code_t rc; + gcry_pk_spec_t *pubkey = NULL; + gcry_module_t module = NULL; + + *r_ciph = NULL; + + REGISTER_DEFAULT_PUBKEYS; + + /* Get the key. */ + rc = sexp_to_key (s_pkey, 0, &pkey, &module); + if (rc) + goto leave; + + gcry_assert (module); + pubkey = (gcry_pk_spec_t *) module->spec; + + /* If aliases for the algorithm name exists, take the first one + instead of the regular name to adhere to SPKI conventions. We + assume that the first alias name is the lowercase version of the + regular one. This change is required for compatibility with + 1.1.12 generated S-expressions. */ + algo_name = pubkey->aliases? *pubkey->aliases : NULL; + if (!algo_name || !*algo_name) + algo_name = pubkey->name; + + algo_elems = pubkey->elements_enc; + + /* Get the stuff we want to encrypt. */ + rc = sexp_data_to_mpi (s_data, gcry_pk_get_nbits (s_pkey), &data, 1, + &flags); + if (rc) + goto leave; + + /* Now we can encrypt DATA to CIPH. */ + ciph = gcry_calloc (strlen (algo_elems) + 1, sizeof (*ciph)); + if (!ciph) + { + rc = gpg_err_code_from_errno (errno); + goto leave; + } + rc = pubkey_encrypt (module->mod_id, ciph, data, pkey, flags); + mpi_free (data); + data = NULL; + if (rc) + goto leave; + + /* We did it. Now build the return list */ + { + char *string, *p; + int i; + size_t nelem = strlen (algo_elems); + size_t needed = 19 + strlen (algo_name) + (nelem * 5); + void **arg_list; + + /* Build the string. */ + string = p = gcry_malloc (needed); + if (!string) + { + rc = gpg_err_code_from_errno (errno); + goto leave; + } + p = stpcpy ( p, "(enc-val(" ); + p = stpcpy ( p, algo_name ); + for (i=0; algo_elems[i]; i++ ) + { + *p++ = '('; + *p++ = algo_elems[i]; + p = stpcpy ( p, "%m)" ); + } + strcpy ( p, "))" ); + + /* And now the ugly part: We don't have a function to pass an + * array to a format string, so we have to do it this way :-(. */ + /* FIXME: There is now such a format specifier, so we can + change the code to be more clear. */ + arg_list = malloc (nelem * sizeof *arg_list); + if (!arg_list) + { + rc = gpg_err_code_from_errno (errno); + goto leave; + } + + for (i = 0; i < nelem; i++) + arg_list[i] = ciph + i; + + rc = gcry_sexp_build_array (r_ciph, NULL, string, arg_list); + free (arg_list); + if (rc) + BUG (); + gcry_free (string); + } + + leave: + if (pkey) + { + release_mpi_array (pkey); + gcry_free (pkey); + } + + if (ciph) + { + release_mpi_array (ciph); + gcry_free (ciph); + } + + if (module) + { + ath_mutex_lock (&pubkeys_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&pubkeys_registered_lock); + } + + return gcry_error (rc); +} + +/* + Do a PK decrypt operation + + Caller has to provide a secret key as the SEXP skey and data in a + format as created by gcry_pk_encrypt. For historic reasons the + function returns simply an MPI as an S-expression part; this is + deprecated and the new method should be used which returns a real + S-expressionl this is selected by adding at least an empty flags + list to S_DATA. + + Returns: 0 or an errorcode. + + s_data = (enc-val + [(flags)] + ( + ( ) + ... + ( ) + )) + s_skey = + r_plain= Either an incomplete S-expression without the parentheses + or if the flags list is used (even if empty) a real S-expression: + (value PLAIN). + */ +gcry_error_t +gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) +{ + gcry_mpi_t *skey = NULL, *data = NULL, plain = NULL; + int modern, want_pkcs1, flags; + gcry_err_code_t rc; + gcry_module_t module_enc = NULL, module_key = NULL; + gcry_pk_spec_t *pubkey = NULL; + + *r_plain = NULL; + + REGISTER_DEFAULT_PUBKEYS; + + rc = sexp_to_key (s_skey, 1, &skey, &module_key); + if (rc) + goto leave; + + rc = sexp_to_enc (s_data, &data, &module_enc, &modern, &want_pkcs1, &flags); + if (rc) + goto leave; + + if (module_key->mod_id != module_enc->mod_id) + { + rc = GPG_ERR_CONFLICT; /* Key algo does not match data algo. */ + goto leave; + } + + pubkey = (gcry_pk_spec_t *) module_key->spec; + + rc = pubkey_decrypt (module_key->mod_id, &plain, data, skey, flags); + if (rc) + goto leave; + + if (gcry_sexp_build (r_plain, NULL, modern? "(value %m)" : "%m", plain)) + BUG (); + + leave: + if (skey) + { + release_mpi_array (skey); + gcry_free (skey); + } + + if (plain) + mpi_free (plain); + + if (data) + { + release_mpi_array (data); + gcry_free (data); + } + + if (module_key || module_enc) + { + ath_mutex_lock (&pubkeys_registered_lock); + if (module_key) + _gcry_module_release (module_key); + if (module_enc) + _gcry_module_release (module_enc); + ath_mutex_unlock (&pubkeys_registered_lock); + } + + return gcry_error (rc); +} + + + +/* + Create a signature. + + Caller has to provide a secret key as the SEXP skey and data + expressed as a SEXP list hash with only one element which should + instantly be available as a MPI. Alternatively the structure given + below may be used for S_HASH, it provides the abiliy to pass flags + to the operation; the only flag defined by now is "pkcs1" which + does PKCS#1 block type 1 style padding. + + Returns: 0 or an errorcode. + In case of 0 the function returns a new SEXP with the + signature value; the structure of this signature depends on the + other arguments but is always suitable to be passed to + gcry_pk_verify + + s_hash = See comment for sexp_data_to_mpi + + s_skey = + r_sig = (sig-val + ( + ( ) + ... + ( )) + [(hash algo)]) + + Note that (hash algo) in R_SIG is not used. +*/ +gcry_error_t +gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) +{ + gcry_mpi_t *skey = NULL, hash = NULL, *result = NULL; + gcry_pk_spec_t *pubkey = NULL; + gcry_module_t module = NULL; + const char *algo_name, *algo_elems; + int i; + gcry_err_code_t rc; + + *r_sig = NULL; + + REGISTER_DEFAULT_PUBKEYS; + + rc = sexp_to_key (s_skey, 1, &skey, &module); + if (rc) + goto leave; + + gcry_assert (module); + pubkey = (gcry_pk_spec_t *) module->spec; + algo_name = pubkey->aliases? *pubkey->aliases : NULL; + if (!algo_name || !*algo_name) + algo_name = pubkey->name; + + algo_elems = pubkey->elements_sig; + + /* Get the stuff we want to sign. Note that pk_get_nbits does also + work on a private key. */ + rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_skey), + &hash, 0, NULL); + if (rc) + goto leave; + + result = gcry_calloc (strlen (algo_elems) + 1, sizeof (*result)); + if (!result) + { + rc = gpg_err_code_from_errno (errno); + goto leave; + } + rc = pubkey_sign (module->mod_id, result, hash, skey); + if (rc) + goto leave; + + { + char *string, *p; + size_t nelem, needed = strlen (algo_name) + 20; + void **arg_list; + + nelem = strlen (algo_elems); + + /* Count elements, so that we can allocate enough space. */ + needed += 10 * nelem; + + /* Build the string. */ + string = p = gcry_malloc (needed); + if (!string) + { + rc = gpg_err_code_from_errno (errno); + goto leave; + } + p = stpcpy (p, "(sig-val("); + p = stpcpy (p, algo_name); + for (i = 0; algo_elems[i]; i++) + { + *p++ = '('; + *p++ = algo_elems[i]; + p = stpcpy (p, "%m)"); + } + strcpy (p, "))"); + + arg_list = malloc (nelem * sizeof *arg_list); + if (!arg_list) + { + rc = gpg_err_code_from_errno (errno); + goto leave; + } + + for (i = 0; i < nelem; i++) + arg_list[i] = result + i; + + rc = gcry_sexp_build_array (r_sig, NULL, string, arg_list); + free (arg_list); + if (rc) + BUG (); + gcry_free (string); + } + + leave: + if (skey) + { + release_mpi_array (skey); + gcry_free (skey); + } + + if (hash) + mpi_free (hash); + + if (result) + { + release_mpi_array (result); + gcry_free (result); + } + + return gcry_error (rc); +} + + +/* + Verify a signature. + + Caller has to supply the public key pkey, the signature sig and his + hashvalue data. Public key has to be a standard public key given + as an S-Exp, sig is a S-Exp as returned from gcry_pk_sign and data + must be an S-Exp like the one in sign too. */ +gcry_error_t +gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey) +{ + gcry_module_t module_key = NULL, module_sig = NULL; + gcry_mpi_t *pkey = NULL, hash = NULL, *sig = NULL; + gcry_err_code_t rc; + + REGISTER_DEFAULT_PUBKEYS; + + rc = sexp_to_key (s_pkey, 0, &pkey, &module_key); + if (rc) + goto leave; + + rc = sexp_to_sig (s_sig, &sig, &module_sig); + if (rc) + goto leave; + + /* Fixme: Check that the algorithm of S_SIG is compatible to the one + of S_PKEY. */ + + if (module_key->mod_id != module_sig->mod_id) + { + rc = GPG_ERR_CONFLICT; + goto leave; + } + + rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_pkey), &hash, 0, 0); + if (rc) + goto leave; + + rc = pubkey_verify (module_key->mod_id, hash, sig, pkey, NULL, NULL); + + leave: + if (pkey) + { + release_mpi_array (pkey); + gcry_free (pkey); + } + if (sig) + { + release_mpi_array (sig); + gcry_free (sig); + } + if (hash) + mpi_free (hash); + + if (module_key || module_sig) + { + ath_mutex_lock (&pubkeys_registered_lock); + if (module_key) + _gcry_module_release (module_key); + if (module_sig) + _gcry_module_release (module_sig); + ath_mutex_unlock (&pubkeys_registered_lock); + } + + return gcry_error (rc); +} + + +/* + Test a key. + + This may be used either for a public or a secret key to see whether + the internal structure is okay. + + Returns: 0 or an errorcode. + + s_key = */ +gcry_error_t +gcry_pk_testkey (gcry_sexp_t s_key) +{ + gcry_module_t module = NULL; + gcry_mpi_t *key = NULL; + gcry_err_code_t rc; + + REGISTER_DEFAULT_PUBKEYS; + + /* Note we currently support only secret key checking. */ + rc = sexp_to_key (s_key, 1, &key, &module); + if (! rc) + { + rc = pubkey_check_secret_key (module->mod_id, key); + release_mpi_array (key); + gcry_free (key); + } + return gcry_error (rc); +} + + +/* + Create a public key pair and return it in r_key. + How the key is created depends on s_parms: + (genkey + (algo + (parameter_name_1 ....) + .... + (parameter_name_n ....) + )) + The key is returned in a format depending on the + algorithm. Both, private and secret keys are returned + and optionally some additional informatin. + For elgamal we return this structure: + (key-data + (public-key + (elg + (p ) + (g ) + (y ) + ) + ) + (private-key + (elg + (p ) + (g ) + (y ) + (x ) + ) + ) + (misc-key-info + (pm1-factors n1 n2 ... nn) + )) + */ +gcry_error_t +gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) +{ + gcry_pk_spec_t *pubkey = NULL; + gcry_module_t module = NULL; + gcry_sexp_t list = NULL; + gcry_sexp_t l2 = NULL; + gcry_sexp_t l3 = NULL; + char *name = NULL; + size_t n; + gcry_err_code_t rc = GPG_ERR_NO_ERROR; + int i; + const char *algo_name = NULL; + int algo; + const char *sec_elems = NULL, *pub_elems = NULL; + gcry_mpi_t skey[12]; + gcry_mpi_t *factors = NULL; + gcry_sexp_t extrainfo = NULL; + unsigned int nbits = 0; + unsigned long use_e = 0; + + skey[0] = NULL; + *r_key = NULL; + + REGISTER_DEFAULT_PUBKEYS; + + list = gcry_sexp_find_token (s_parms, "genkey", 0); + if (!list) + { + rc = GPG_ERR_INV_OBJ; /* Does not contain genkey data. */ + goto leave; + } + + l2 = gcry_sexp_cadr (list); + gcry_sexp_release (list); + list = l2; + l2 = NULL; + if (! list) + { + rc = GPG_ERR_NO_OBJ; /* No cdr for the genkey. */ + goto leave; + } + + name = _gcry_sexp_nth_string (list, 0); + if (!name) + { + rc = GPG_ERR_INV_OBJ; /* Algo string missing. */ + goto leave; + } + + ath_mutex_lock (&pubkeys_registered_lock); + module = gcry_pk_lookup_name (name); + ath_mutex_unlock (&pubkeys_registered_lock); + gcry_free (name); + name = NULL; + if (!module) + { + rc = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ + goto leave; + } + + pubkey = (gcry_pk_spec_t *) module->spec; + algo = module->mod_id; + algo_name = pubkey->aliases? *pubkey->aliases : NULL; + if (!algo_name || !*algo_name) + algo_name = pubkey->name; + pub_elems = pubkey->elements_pkey; + sec_elems = pubkey->elements_skey; + if (strlen (sec_elems) >= DIM(skey)) + BUG (); + + /* Handle the optional rsa-use-e element. Actually this belong into + the algorithm module but we have this parameter in the public + module API, so we need to parse it right here. */ + l2 = gcry_sexp_find_token (list, "rsa-use-e", 0); + if (l2) + { + char buf[50]; + const char *s; + + s = gcry_sexp_nth_data (l2, 1, &n); + if ( !s || n >= DIM (buf) - 1 ) + { + rc = GPG_ERR_INV_OBJ; /* No value or value too large. */ + goto leave; + } + memcpy (buf, s, n); + buf[n] = 0; + use_e = strtoul (buf, NULL, 0); + gcry_sexp_release (l2); + l2 = NULL; + } + else + use_e = 65537; /* Not given, use the value generated by old versions. */ + + + /* Get the "nbits" parameter. */ + l2 = gcry_sexp_find_token (list, "nbits", 0); + if (l2) + { + char buf[50]; + const char *s; + + s = gcry_sexp_nth_data (l2, 1, &n); + if (!s || n >= DIM (buf) - 1 ) + { + rc = GPG_ERR_INV_OBJ; /* NBITS given without a cdr. */ + goto leave; + } + memcpy (buf, s, n); + buf[n] = 0; + nbits = (unsigned int)strtoul (buf, NULL, 0); + gcry_sexp_release (l2); l2 = NULL; + } + else + nbits = 0; + + /* Pass control to the algorithm module. */ + rc = pubkey_generate (module->mod_id, nbits, use_e, list, skey, + &factors, &extrainfo); + gcry_sexp_release (list); list = NULL; + if (rc) + goto leave; + + /* Key generation succeeded: Build an S-expression. */ + { + char *string, *p; + size_t nelem=0, nelem_cp = 0, needed=0; + gcry_mpi_t mpis[30]; + + /* Estimate size of format string. */ + nelem = strlen (pub_elems) + strlen (sec_elems); + if (factors) + { + for (i = 0; factors[i]; i++) + nelem++; + } + nelem_cp = nelem; + + needed += nelem * 10; + /* (+5 is for EXTRAINFO ("%S")). */ + needed += 2 * strlen (algo_name) + 300 + 5; + if (nelem > DIM (mpis)) + BUG (); + + /* Build the string. */ + nelem = 0; + string = p = gcry_malloc (needed); + if (!string) + { + rc = gpg_err_code_from_errno (errno); + goto leave; + } + p = stpcpy (p, "(key-data"); + p = stpcpy (p, "(public-key("); + p = stpcpy (p, algo_name); + for(i = 0; pub_elems[i]; i++) + { + *p++ = '('; + *p++ = pub_elems[i]; + p = stpcpy (p, "%m)"); + mpis[nelem++] = skey[i]; + } + p = stpcpy (p, "))"); + p = stpcpy (p, "(private-key("); + p = stpcpy (p, algo_name); + for (i = 0; sec_elems[i]; i++) + { + *p++ = '('; + *p++ = sec_elems[i]; + p = stpcpy (p, "%m)"); + mpis[nelem++] = skey[i]; + } + p = stpcpy (p, "))"); + + /* Hack to make release_mpi_array() work. */ + skey[i] = NULL; + + if (extrainfo) + { + /* If we have extrainfo we should not have any factors. */ + p = stpcpy (p, "%S"); + } + else if (factors && factors[0]) + { + p = stpcpy (p, "(misc-key-info(pm1-factors"); + for(i = 0; factors[i]; i++) + { + p = stpcpy (p, "%m"); + mpis[nelem++] = factors[i]; + } + p = stpcpy (p, "))"); + } + strcpy (p, ")"); + gcry_assert (p - string < needed); + + while (nelem < DIM (mpis)) + mpis[nelem++] = NULL; + + { + int elem_n = strlen (pub_elems) + strlen (sec_elems); + void **arg_list; + + /* Allocate one extra for EXTRAINFO ("%S"). */ + arg_list = gcry_calloc (nelem_cp+1, sizeof *arg_list); + if (!arg_list) + { + rc = gpg_err_code_from_errno (errno); + goto leave; + } + for (i = 0; i < elem_n; i++) + arg_list[i] = mpis + i; + if (extrainfo) + arg_list[i] = &extrainfo; + else if (factors && factors[0]) + { + for (; i < nelem_cp; i++) + arg_list[i] = factors + i - elem_n; + } + + rc = gcry_sexp_build_array (r_key, NULL, string, arg_list); + gcry_free (arg_list); + if (rc) + BUG (); + gcry_assert (DIM (mpis) == 30); /* Reminder to make sure that + the array gets increased if + new parameters are added. */ + } + gcry_free (string); + } + + leave: + gcry_free (name); + gcry_sexp_release (extrainfo); + release_mpi_array (skey); + /* Don't free SKEY itself, it is an stack allocated array. */ + + if (factors) + { + release_mpi_array ( factors ); + gcry_free (factors); + } + + gcry_sexp_release (l3); + gcry_sexp_release (l2); + gcry_sexp_release (list); + + if (module) + { + ath_mutex_lock (&pubkeys_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&pubkeys_registered_lock); + } + + return gcry_error (rc); +} + + +/* + Get the number of nbits from the public key. + + Hmmm: Should we have really this function or is it better to have a + more general function to retrieve different properties of the key? */ +unsigned int +gcry_pk_get_nbits (gcry_sexp_t key) +{ + gcry_module_t module = NULL; + gcry_pk_spec_t *pubkey; + gcry_mpi_t *keyarr = NULL; + unsigned int nbits = 0; + gcry_err_code_t rc; + + REGISTER_DEFAULT_PUBKEYS; + + rc = sexp_to_key (key, 0, &keyarr, &module); + if (rc == GPG_ERR_INV_OBJ) + rc = sexp_to_key (key, 1, &keyarr, &module); + if (rc) + return 0; /* Error - 0 is a suitable indication for that. */ + + pubkey = (gcry_pk_spec_t *) module->spec; + nbits = (*pubkey->get_nbits) (module->mod_id, keyarr); + + ath_mutex_lock (&pubkeys_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&pubkeys_registered_lock); + + release_mpi_array (keyarr); + gcry_free (keyarr); + + return nbits; +} + + +/* Return the so called KEYGRIP which is the SHA-1 hash of the public + key parameters expressed in a way depending on the algorithm. + + ARRAY must either be 20 bytes long or NULL; in the latter case a + newly allocated array of that size is returned, otherwise ARRAY or + NULL is returned to indicate an error which is most likely an + unknown algorithm. The function accepts public or secret keys. */ +unsigned char * +gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array) +{ + gcry_sexp_t list = NULL, l2 = NULL; + gcry_pk_spec_t *pubkey = NULL; + gcry_module_t module = NULL; + pk_extra_spec_t *extraspec; + const char *s; + char *name = NULL; + int idx; + const char *elems; + gcry_md_hd_t md = NULL; + + REGISTER_DEFAULT_PUBKEYS; + + /* Check that the first element is valid. */ + list = gcry_sexp_find_token (key, "public-key", 0); + if (! list) + list = gcry_sexp_find_token (key, "private-key", 0); + if (! list) + list = gcry_sexp_find_token (key, "protected-private-key", 0); + if (! list) + list = gcry_sexp_find_token (key, "shadowed-private-key", 0); + if (! list) + return NULL; /* No public- or private-key object. */ + + l2 = gcry_sexp_cadr (list); + gcry_sexp_release (list); + list = l2; + l2 = NULL; + + name = _gcry_sexp_nth_string (list, 0); + if (!name) + goto fail; /* Invalid structure of object. */ + + ath_mutex_lock (&pubkeys_registered_lock); + module = gcry_pk_lookup_name (name); + ath_mutex_unlock (&pubkeys_registered_lock); + + if (!module) + goto fail; /* Unknown algorithm. */ + + pubkey = (gcry_pk_spec_t *) module->spec; + extraspec = module->extraspec; + + elems = pubkey->elements_grip; + if (!elems) + goto fail; /* No grip parameter. */ + + if (gcry_md_open (&md, GCRY_MD_SHA1, 0)) + goto fail; + + if (extraspec && extraspec->comp_keygrip) + { + /* Module specific method to compute a keygrip. */ + if (extraspec->comp_keygrip (md, list)) + goto fail; + } + else + { + /* Generic method to compute a keygrip. */ + for (idx = 0, s = elems; *s; s++, idx++) + { + const char *data; + size_t datalen; + char buf[30]; + + l2 = gcry_sexp_find_token (list, s, 1); + if (! l2) + goto fail; + data = gcry_sexp_nth_data (l2, 1, &datalen); + if (! data) + goto fail; + + snprintf (buf, sizeof buf, "(1:%c%u:", *s, (unsigned int)datalen); + gcry_md_write (md, buf, strlen (buf)); + gcry_md_write (md, data, datalen); + gcry_sexp_release (l2); + gcry_md_write (md, ")", 1); + } + } + + if (!array) + { + array = gcry_malloc (20); + if (! array) + goto fail; + } + + memcpy (array, gcry_md_read (md, GCRY_MD_SHA1), 20); + gcry_md_close (md); + gcry_sexp_release (list); + return array; + + fail: + gcry_free (name); + gcry_sexp_release (l2); + gcry_md_close (md); + gcry_sexp_release (list); + return NULL; +} + + +gcry_error_t +gcry_pk_ctl (int cmd, void *buffer, size_t buflen) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + REGISTER_DEFAULT_PUBKEYS; + + switch (cmd) + { + case GCRYCTL_DISABLE_ALGO: + /* This one expects a buffer pointing to an integer with the + algo number. */ + if ((! buffer) || (buflen != sizeof (int))) + err = GPG_ERR_INV_ARG; + else + disable_pubkey_algo (*((int *) buffer)); + break; + + default: + err = GPG_ERR_INV_OP; + } + + return gcry_error (err); +} + + +/* Return information about the given algorithm + + WHAT selects the kind of information returned: + + GCRYCTL_TEST_ALGO: + Returns 0 when the specified algorithm is available for use. + Buffer must be NULL, nbytes may have the address of a variable + with the required usage of the algorithm. It may be 0 for don't + care or a combination of the GCRY_PK_USAGE_xxx flags; + + GCRYCTL_GET_ALGO_USAGE: + Return the usage glafs for the give algo. An invalid alog + does return 0. Disabled algos are ignored here because we + only want to know whether the algo is at all capable of + the usage. + + Note: Because this function is in most cases used to return an + integer value, we can make it easier for the caller to just look at + the return value. The caller will in all cases consult the value + and thereby detecting whether a error occurred or not (i.e. while + checking the block size) */ +gcry_error_t +gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + switch (what) + { + case GCRYCTL_TEST_ALGO: + { + int use = nbytes ? *nbytes : 0; + if (buffer) + err = GPG_ERR_INV_ARG; + else if (check_pubkey_algo (algorithm, use)) + err = GPG_ERR_PUBKEY_ALGO; + break; + } + + case GCRYCTL_GET_ALGO_USAGE: + { + gcry_module_t pubkey; + int use = 0; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (pubkey) + { + use = ((gcry_pk_spec_t *) pubkey->spec)->use; + _gcry_module_release (pubkey); + } + ath_mutex_unlock (&pubkeys_registered_lock); + + /* FIXME? */ + *nbytes = use; + + break; + } + + case GCRYCTL_GET_ALGO_NPKEY: + { + /* FIXME? */ + int npkey = pubkey_get_npkey (algorithm); + *nbytes = npkey; + break; + } + case GCRYCTL_GET_ALGO_NSKEY: + { + /* FIXME? */ + int nskey = pubkey_get_nskey (algorithm); + *nbytes = nskey; + break; + } + case GCRYCTL_GET_ALGO_NSIGN: + { + /* FIXME? */ + int nsign = pubkey_get_nsig (algorithm); + *nbytes = nsign; + break; + } + case GCRYCTL_GET_ALGO_NENCR: + { + /* FIXME? */ + int nencr = pubkey_get_nenc (algorithm); + *nbytes = nencr; + break; + } + + default: + err = GPG_ERR_INV_OP; + } + + return gcry_error (err); +} + + +/* Explicitly initialize this module. */ +gcry_err_code_t +_gcry_pk_init (void) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + REGISTER_DEFAULT_PUBKEYS; + + return err; +} + + +gcry_err_code_t +_gcry_pk_module_lookup (int algorithm, gcry_module_t *module) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_module_t pubkey; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); + if (pubkey) + *module = pubkey; + else + err = GPG_ERR_PUBKEY_ALGO; + ath_mutex_unlock (&pubkeys_registered_lock); + + return err; +} + + +void +_gcry_pk_module_release (gcry_module_t module) +{ + ath_mutex_lock (&pubkeys_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&pubkeys_registered_lock); +} + +/* Get a list consisting of the IDs of the loaded pubkey modules. If + LIST is zero, write the number of loaded pubkey modules to + LIST_LENGTH and return. If LIST is non-zero, the first + *LIST_LENGTH algorithm IDs are stored in LIST, which must be of + according size. In case there are less pubkey modules than + *LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */ +gcry_error_t +gcry_pk_list (int *list, int *list_length) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + ath_mutex_lock (&pubkeys_registered_lock); + err = _gcry_module_list (pubkeys_registered, list, list_length); + ath_mutex_unlock (&pubkeys_registered_lock); + + return err; +} + + +/* Run the selftests for pubkey algorithm ALGO with optional reporting + function REPORT. */ +gpg_error_t +_gcry_pk_selftest (int algo, int extended, selftest_report_func_t report) +{ + gcry_module_t module = NULL; + pk_extra_spec_t *extraspec = NULL; + gcry_err_code_t ec = 0; + + REGISTER_DEFAULT_PUBKEYS; + + ath_mutex_lock (&pubkeys_registered_lock); + module = _gcry_module_lookup_id (pubkeys_registered, algo); + if (module && !(module->flags & FLAG_MODULE_DISABLED)) + extraspec = module->extraspec; + ath_mutex_unlock (&pubkeys_registered_lock); + if (extraspec && extraspec->selftest) + ec = extraspec->selftest (algo, extended, report); + else + { + ec = GPG_ERR_PUBKEY_ALGO; + if (report) + report ("pubkey", algo, "module", + module && !(module->flags & FLAG_MODULE_DISABLED)? + "no selftest available" : + module? "algorithm disabled" : "algorithm not found"); + } + + if (module) + { + ath_mutex_lock (&pubkeys_registered_lock); + _gcry_module_release (module); + ath_mutex_unlock (&pubkeys_registered_lock); + } + return gpg_error (ec); +} + + +/* This function is only used by ac.c! */ +gcry_err_code_t +_gcry_pk_get_elements (int algo, char **enc, char **sig) +{ + gcry_module_t pubkey; + gcry_pk_spec_t *spec; + gcry_err_code_t err; + char *enc_cp; + char *sig_cp; + + REGISTER_DEFAULT_PUBKEYS; + + enc_cp = NULL; + sig_cp = NULL; + spec = NULL; + + pubkey = _gcry_module_lookup_id (pubkeys_registered, algo); + if (! pubkey) + { + err = GPG_ERR_INTERNAL; + goto out; + } + spec = pubkey->spec; + + if (enc) + { + enc_cp = _strdup (spec->elements_enc); + if (! enc_cp) + { + err = gpg_err_code_from_errno (errno); + goto out; + } + } + + if (sig) + { + sig_cp = strdup (spec->elements_sig); + if (! sig_cp) + { + err = gpg_err_code_from_errno (errno); + goto out; + } + } + + if (enc) + *enc = enc_cp; + if (sig) + *sig = sig_cp; + err = 0; + + out: + + _gcry_module_release (pubkey); + if (err) + { + free (enc_cp); + free (sig_cp); + } + + return err; +} diff --git a/libgcrypt-1.4.6/cipher/rijndael.c b/libgcrypt-1.4.6/cipher/rijndael.c index d43b349..1df703a 100644 --- a/libgcrypt-1.4.6/cipher/rijndael.c +++ b/libgcrypt-1.4.6/cipher/rijndael.c @@ -1,1253 +1,1253 @@ -/* Rijndael (AES) for GnuPG - * Copyright (C) 2000, 2001, 2002, 2003, 2007, - * 2008 Free Software Foundation, Inc. - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see . - ******************************************************************* - * The code here is based on the optimized implementation taken from - * http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ on Oct 2, 2000, - * which carries this notice: - *------------------------------------------ - * rijndael-alg-fst.c v2.3 April '2000 - * - * Optimised ANSI C code - * - * authors: v1.0: Antoon Bosselaers - * v2.0: Vincent Rijmen - * v2.3: Paulo Barreto - * - * This code is placed in the public domain. - *------------------------------------------ - * - * The SP800-38a document is available at: - * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - * - */ - -#include -#include -#include -#include /* for memcmp() */ - -#include "types.h" /* for byte and u32 typedefs */ -#include "g10lib.h" -#include "cipher.h" - -#define MAXKC (256/32) -#define MAXROUNDS 14 -#define BLOCKSIZE (128/8) - - -/* USE_PADLOCK indicates whether to compile the padlock specific - code. */ -#undef USE_PADLOCK -#ifdef ENABLE_PADLOCK_SUPPORT -# if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__) -# define USE_PADLOCK -# endif -#endif /*ENABLE_PADLOCK_SUPPORT*/ - -static const char *selftest(void); - -typedef struct -{ - int ROUNDS; /* Key-length-dependent number of rounds. */ - int decryption_prepared; /* The decryption key schedule is available. */ -#ifdef USE_PADLOCK - int use_padlock; /* Padlock shall be used. */ - /* The key as passed to the padlock engine. */ - unsigned char padlock_key[16] __attribute__ ((aligned (16))); -#endif - union - { - PROPERLY_ALIGNED_TYPE dummy; - byte keyschedule[MAXROUNDS+1][4][4]; - } u1; - union - { - PROPERLY_ALIGNED_TYPE dummy; - byte keyschedule[MAXROUNDS+1][4][4]; - } u2; -} RIJNDAEL_context; - -#define keySched u1.keyschedule -#define keySched2 u2.keyschedule - -/* All the numbers. */ -#include "rijndael-tables.h" - - -/* Perform the key setup. */ -static gcry_err_code_t -do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen) -{ - static int initialized = 0; - static const char *selftest_failed=0; - int ROUNDS; - int i,j, r, t, rconpointer = 0; - int KC; - union - { - PROPERLY_ALIGNED_TYPE dummy; - byte k[MAXKC][4]; - } k; -#define k k.k - union - { - PROPERLY_ALIGNED_TYPE dummy; - byte tk[MAXKC][4]; - } tk; -#define tk tk.tk - - /* The on-the-fly self tests are only run in non-fips mode. In fips - mode explicit self-tests are required. Actually the on-the-fly - self-tests are not fully thread-safe and it might happen that a - failed self-test won't get noticed in another thread. - - FIXME: We might want to have a central registry of succeeded - self-tests. */ - if (!fips_mode () && !initialized) - { - initialized = 1; - selftest_failed = selftest (); - if (selftest_failed) - log_error ("%s\n", selftest_failed ); - } - if (selftest_failed) - return GPG_ERR_SELFTEST_FAILED; - - ctx->decryption_prepared = 0; -#ifdef USE_PADLOCK - ctx->use_padlock = 0; -#endif - - if( keylen == 128/8 ) - { - ROUNDS = 10; - KC = 4; -#ifdef USE_PADLOCK - if ((_gcry_get_hw_features () & HWF_PADLOCK_AES)) - { - ctx->use_padlock = 1; - memcpy (ctx->padlock_key, key, keylen); - } -#endif - } - else if ( keylen == 192/8 ) - { - ROUNDS = 12; - KC = 6; - } - else if ( keylen == 256/8 ) - { - ROUNDS = 14; - KC = 8; - } - else - return GPG_ERR_INV_KEYLEN; - - ctx->ROUNDS = ROUNDS; - -#ifdef USE_PADLOCK - if (ctx->use_padlock) - { - /* Nothing to do as we support only hardware key generation for - now. */ - } - else -#endif /*USE_PADLOCK*/ - { -#define W (ctx->keySched) - for (i = 0; i < keylen; i++) - { - k[i >> 2][i & 3] = key[i]; - } - - for (j = KC-1; j >= 0; j--) - { - *((u32*)tk[j]) = *((u32*)k[j]); - } - r = 0; - t = 0; - /* Copy values into round key array. */ - for (j = 0; (j < KC) && (r < ROUNDS + 1); ) - { - for (; (j < KC) && (t < 4); j++, t++) - { - *((u32*)W[r][t]) = *((u32*)tk[j]); - } - if (t == 4) - { - r++; - t = 0; - } - } - - while (r < ROUNDS + 1) - { - /* While not enough round key material calculated calculate - new values. */ - tk[0][0] ^= S[tk[KC-1][1]]; - tk[0][1] ^= S[tk[KC-1][2]]; - tk[0][2] ^= S[tk[KC-1][3]]; - tk[0][3] ^= S[tk[KC-1][0]]; - tk[0][0] ^= rcon[rconpointer++]; - - if (KC != 8) - { - for (j = 1; j < KC; j++) - { - *((u32*)tk[j]) ^= *((u32*)tk[j-1]); - } - } - else - { - for (j = 1; j < KC/2; j++) - { - *((u32*)tk[j]) ^= *((u32*)tk[j-1]); - } - tk[KC/2][0] ^= S[tk[KC/2 - 1][0]]; - tk[KC/2][1] ^= S[tk[KC/2 - 1][1]]; - tk[KC/2][2] ^= S[tk[KC/2 - 1][2]]; - tk[KC/2][3] ^= S[tk[KC/2 - 1][3]]; - for (j = KC/2 + 1; j < KC; j++) - { - *((u32*)tk[j]) ^= *((u32*)tk[j-1]); - } - } - - /* Copy values into round key array. */ - for (j = 0; (j < KC) && (r < ROUNDS + 1); ) - { - for (; (j < KC) && (t < 4); j++, t++) - { - *((u32*)W[r][t]) = *((u32*)tk[j]); - } - if (t == 4) - { - r++; - t = 0; - } - } - } -#undef W - } - - return 0; -#undef tk -#undef k -} - - -static gcry_err_code_t -rijndael_setkey (void *context, const byte *key, const unsigned keylen) -{ - RIJNDAEL_context *ctx = context; - - int rc = do_setkey (ctx, key, keylen); - _gcry_burn_stack ( 100 + 16*sizeof(int)); - return rc; -} - - -/* Make a decryption key from an encryption key. */ -static void -prepare_decryption( RIJNDAEL_context *ctx ) -{ - int r; - union - { - PROPERLY_ALIGNED_TYPE dummy; - byte *w; - } w; -#define w w.w - - for (r=0; r < MAXROUNDS+1; r++ ) - { - *((u32*)ctx->keySched2[r][0]) = *((u32*)ctx->keySched[r][0]); - *((u32*)ctx->keySched2[r][1]) = *((u32*)ctx->keySched[r][1]); - *((u32*)ctx->keySched2[r][2]) = *((u32*)ctx->keySched[r][2]); - *((u32*)ctx->keySched2[r][3]) = *((u32*)ctx->keySched[r][3]); - } -#define W (ctx->keySched2) - for (r = 1; r < ctx->ROUNDS; r++) - { - w = W[r][0]; - *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) - ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); - - w = W[r][1]; - *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) - ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); - - w = W[r][2]; - *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) - ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); - - w = W[r][3]; - *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) - ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); - } -#undef W -#undef w -} - - - -/* Encrypt one block. A and B need to be aligned on a 4 byte - boundary. A and B may be the same. */ -static void -do_encrypt_aligned (const RIJNDAEL_context *ctx, - unsigned char *b, const unsigned char *a) -{ -#define rk (ctx->keySched) - int ROUNDS = ctx->ROUNDS; - int r; - union - { - u32 tempu32[4]; /* Force correct alignment. */ - byte temp[4][4]; - } u; - - *((u32*)u.temp[0]) = *((u32*)(a )) ^ *((u32*)rk[0][0]); - *((u32*)u.temp[1]) = *((u32*)(a+ 4)) ^ *((u32*)rk[0][1]); - *((u32*)u.temp[2]) = *((u32*)(a+ 8)) ^ *((u32*)rk[0][2]); - *((u32*)u.temp[3]) = *((u32*)(a+12)) ^ *((u32*)rk[0][3]); - *((u32*)(b )) = (*((u32*)T1[u.temp[0][0]]) - ^ *((u32*)T2[u.temp[1][1]]) - ^ *((u32*)T3[u.temp[2][2]]) - ^ *((u32*)T4[u.temp[3][3]])); - *((u32*)(b + 4)) = (*((u32*)T1[u.temp[1][0]]) - ^ *((u32*)T2[u.temp[2][1]]) - ^ *((u32*)T3[u.temp[3][2]]) - ^ *((u32*)T4[u.temp[0][3]])); - *((u32*)(b + 8)) = (*((u32*)T1[u.temp[2][0]]) - ^ *((u32*)T2[u.temp[3][1]]) - ^ *((u32*)T3[u.temp[0][2]]) - ^ *((u32*)T4[u.temp[1][3]])); - *((u32*)(b +12)) = (*((u32*)T1[u.temp[3][0]]) - ^ *((u32*)T2[u.temp[0][1]]) - ^ *((u32*)T3[u.temp[1][2]]) - ^ *((u32*)T4[u.temp[2][3]])); - - for (r = 1; r < ROUNDS-1; r++) - { - *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[r][0]); - *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[r][1]); - *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[r][2]); - *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[r][3]); - - *((u32*)(b )) = (*((u32*)T1[u.temp[0][0]]) - ^ *((u32*)T2[u.temp[1][1]]) - ^ *((u32*)T3[u.temp[2][2]]) - ^ *((u32*)T4[u.temp[3][3]])); - *((u32*)(b + 4)) = (*((u32*)T1[u.temp[1][0]]) - ^ *((u32*)T2[u.temp[2][1]]) - ^ *((u32*)T3[u.temp[3][2]]) - ^ *((u32*)T4[u.temp[0][3]])); - *((u32*)(b + 8)) = (*((u32*)T1[u.temp[2][0]]) - ^ *((u32*)T2[u.temp[3][1]]) - ^ *((u32*)T3[u.temp[0][2]]) - ^ *((u32*)T4[u.temp[1][3]])); - *((u32*)(b +12)) = (*((u32*)T1[u.temp[3][0]]) - ^ *((u32*)T2[u.temp[0][1]]) - ^ *((u32*)T3[u.temp[1][2]]) - ^ *((u32*)T4[u.temp[2][3]])); - } - - /* Last round is special. */ - *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[ROUNDS-1][0]); - *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[ROUNDS-1][1]); - *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[ROUNDS-1][2]); - *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[ROUNDS-1][3]); - b[ 0] = T1[u.temp[0][0]][1]; - b[ 1] = T1[u.temp[1][1]][1]; - b[ 2] = T1[u.temp[2][2]][1]; - b[ 3] = T1[u.temp[3][3]][1]; - b[ 4] = T1[u.temp[1][0]][1]; - b[ 5] = T1[u.temp[2][1]][1]; - b[ 6] = T1[u.temp[3][2]][1]; - b[ 7] = T1[u.temp[0][3]][1]; - b[ 8] = T1[u.temp[2][0]][1]; - b[ 9] = T1[u.temp[3][1]][1]; - b[10] = T1[u.temp[0][2]][1]; - b[11] = T1[u.temp[1][3]][1]; - b[12] = T1[u.temp[3][0]][1]; - b[13] = T1[u.temp[0][1]][1]; - b[14] = T1[u.temp[1][2]][1]; - b[15] = T1[u.temp[2][3]][1]; - *((u32*)(b )) ^= *((u32*)rk[ROUNDS][0]); - *((u32*)(b+ 4)) ^= *((u32*)rk[ROUNDS][1]); - *((u32*)(b+ 8)) ^= *((u32*)rk[ROUNDS][2]); - *((u32*)(b+12)) ^= *((u32*)rk[ROUNDS][3]); -#undef rk -} - - -static void -do_encrypt (const RIJNDAEL_context *ctx, - unsigned char *bx, const unsigned char *ax) -{ - /* BX and AX are not necessary correctly aligned. Thus we need to - copy them here. */ - union - { - u32 dummy[4]; - byte a[16]; - } a; - union - { - u32 dummy[4]; - byte b[16]; - } b; - - memcpy (a.a, ax, 16); - do_encrypt_aligned (ctx, b.b, a.a); - memcpy (bx, b.b, 16); -} - - -/* Encrypt or decrypt one block using the padlock engine. A and B may - be the same. */ -#ifdef USE_PADLOCK -static void -do_padlock (const RIJNDAEL_context *ctx, int decrypt_flag, - unsigned char *bx, const unsigned char *ax) -{ - /* BX and AX are not necessary correctly aligned. Thus we need to - copy them here. */ - unsigned char a[16] __attribute__ ((aligned (16))); - unsigned char b[16] __attribute__ ((aligned (16))); - unsigned int cword[4] __attribute__ ((aligned (16))); - - /* The control word fields are: - 127:12 11:10 9 8 7 6 5 4 3:0 - RESERVED KSIZE CRYPT INTER KEYGN CIPHR ALIGN DGEST ROUND */ - cword[0] = (ctx->ROUNDS & 15); /* (The mask is just a safeguard.) */ - cword[1] = 0; - cword[2] = 0; - cword[3] = 0; - if (decrypt_flag) - cword[0] |= 0x00000200; - - memcpy (a, ax, 16); - - asm volatile - ("pushfl\n\t" /* Force key reload. */ - "popfl\n\t" - "xchg %3, %%ebx\n\t" /* Load key. */ - "movl $1, %%ecx\n\t" /* Init counter for just one block. */ - ".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t" /* REP XSTORE ECB. */ - "xchg %3, %%ebx\n" /* Restore GOT register. */ - : /* No output */ - : "S" (a), "D" (b), "d" (cword), "r" (ctx->padlock_key) - : "%ecx", "cc", "memory" - ); - - memcpy (bx, b, 16); - -} -#endif /*USE_PADLOCK*/ - - -static void -rijndael_encrypt (void *context, byte *b, const byte *a) -{ - RIJNDAEL_context *ctx = context; - -#ifdef USE_PADLOCK - if (ctx->use_padlock) - { - do_padlock (ctx, 0, b, a); - _gcry_burn_stack (48 + 15 /* possible padding for alignment */); - } - else -#endif /*USE_PADLOCK*/ - { - do_encrypt (ctx, b, a); - _gcry_burn_stack (48 + 2*sizeof(int)); - } -} - - -/* Bulk encryption of complete blocks in CFB mode. Caller needs to - make sure that IV is aligned on an unsigned long boundary. This - function is only intended for the bulk encryption feature of - cipher.c. */ -void -_gcry_aes_cfb_enc (void *context, unsigned char *iv, - void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks) -{ - RIJNDAEL_context *ctx = context; - unsigned char *outbuf = outbuf_arg; - const unsigned char *inbuf = inbuf_arg; - unsigned char *ivp; - int i; - -#ifdef USE_PADLOCK - if (ctx->use_padlock) - { - /* Fixme: Let Padlock do the CFBing. */ - for ( ;nblocks; nblocks-- ) - { - /* Encrypt the IV. */ - do_padlock (ctx, 0, iv, iv); - /* XOR the input with the IV and store input into IV. */ - for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) - *outbuf++ = (*ivp++ ^= *inbuf++); - } - } - else -#endif /* USE_PADLOCK*/ - { - for ( ;nblocks; nblocks-- ) - { - /* Encrypt the IV. */ - do_encrypt_aligned (ctx, iv, iv); - /* XOR the input with the IV and store input into IV. */ - for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) - *outbuf++ = (*ivp++ ^= *inbuf++); - } - } - - _gcry_burn_stack (48 + 2*sizeof(int)); -} - - -/* Bulk encryption of complete blocks in CBC mode. Caller needs to - make sure that IV is aligned on an unsigned long boundary. This - function is only intended for the bulk encryption feature of - cipher.c. */ -void -_gcry_aes_cbc_enc (void *context, unsigned char *iv, - void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks, int cbc_mac) -{ - RIJNDAEL_context *ctx = context; - unsigned char *outbuf = outbuf_arg; - const unsigned char *inbuf = inbuf_arg; - unsigned char *ivp; - int i; - - for ( ;nblocks; nblocks-- ) - { - for (ivp=iv, i=0; i < BLOCKSIZE; i++ ) - outbuf[i] = inbuf[i] ^ *ivp++; - -#ifdef USE_PADLOCK - if (ctx->use_padlock) - do_padlock (ctx, 0, outbuf, outbuf); - else -#endif /*USE_PADLOCK*/ - do_encrypt (ctx, outbuf, outbuf ); - - memcpy (iv, outbuf, BLOCKSIZE); - inbuf += BLOCKSIZE; - if (!cbc_mac) - outbuf += BLOCKSIZE; - } - - _gcry_burn_stack (48 + 2*sizeof(int)); -} - - - -/* Decrypt one block. A and B need to be aligned on a 4 byte boundary - and the decryption must have been prepared. A and B may be the - same. */ -static void -do_decrypt_aligned (RIJNDAEL_context *ctx, - unsigned char *b, const unsigned char *a) -{ -#define rk (ctx->keySched2) - int ROUNDS = ctx->ROUNDS; - int r; - union - { - u32 tempu32[4]; /* Force correct alignment. */ - byte temp[4][4]; - } u; - - - *((u32*)u.temp[0]) = *((u32*)(a )) ^ *((u32*)rk[ROUNDS][0]); - *((u32*)u.temp[1]) = *((u32*)(a+ 4)) ^ *((u32*)rk[ROUNDS][1]); - *((u32*)u.temp[2]) = *((u32*)(a+ 8)) ^ *((u32*)rk[ROUNDS][2]); - *((u32*)u.temp[3]) = *((u32*)(a+12)) ^ *((u32*)rk[ROUNDS][3]); - - *((u32*)(b )) = (*((u32*)T5[u.temp[0][0]]) - ^ *((u32*)T6[u.temp[3][1]]) - ^ *((u32*)T7[u.temp[2][2]]) - ^ *((u32*)T8[u.temp[1][3]])); - *((u32*)(b+ 4)) = (*((u32*)T5[u.temp[1][0]]) - ^ *((u32*)T6[u.temp[0][1]]) - ^ *((u32*)T7[u.temp[3][2]]) - ^ *((u32*)T8[u.temp[2][3]])); - *((u32*)(b+ 8)) = (*((u32*)T5[u.temp[2][0]]) - ^ *((u32*)T6[u.temp[1][1]]) - ^ *((u32*)T7[u.temp[0][2]]) - ^ *((u32*)T8[u.temp[3][3]])); - *((u32*)(b+12)) = (*((u32*)T5[u.temp[3][0]]) - ^ *((u32*)T6[u.temp[2][1]]) - ^ *((u32*)T7[u.temp[1][2]]) - ^ *((u32*)T8[u.temp[0][3]])); - - for (r = ROUNDS-1; r > 1; r--) - { - *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[r][0]); - *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[r][1]); - *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[r][2]); - *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[r][3]); - *((u32*)(b )) = (*((u32*)T5[u.temp[0][0]]) - ^ *((u32*)T6[u.temp[3][1]]) - ^ *((u32*)T7[u.temp[2][2]]) - ^ *((u32*)T8[u.temp[1][3]])); - *((u32*)(b+ 4)) = (*((u32*)T5[u.temp[1][0]]) - ^ *((u32*)T6[u.temp[0][1]]) - ^ *((u32*)T7[u.temp[3][2]]) - ^ *((u32*)T8[u.temp[2][3]])); - *((u32*)(b+ 8)) = (*((u32*)T5[u.temp[2][0]]) - ^ *((u32*)T6[u.temp[1][1]]) - ^ *((u32*)T7[u.temp[0][2]]) - ^ *((u32*)T8[u.temp[3][3]])); - *((u32*)(b+12)) = (*((u32*)T5[u.temp[3][0]]) - ^ *((u32*)T6[u.temp[2][1]]) - ^ *((u32*)T7[u.temp[1][2]]) - ^ *((u32*)T8[u.temp[0][3]])); - } - - /* Last round is special. */ - *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[1][0]); - *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[1][1]); - *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[1][2]); - *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[1][3]); - b[ 0] = S5[u.temp[0][0]]; - b[ 1] = S5[u.temp[3][1]]; - b[ 2] = S5[u.temp[2][2]]; - b[ 3] = S5[u.temp[1][3]]; - b[ 4] = S5[u.temp[1][0]]; - b[ 5] = S5[u.temp[0][1]]; - b[ 6] = S5[u.temp[3][2]]; - b[ 7] = S5[u.temp[2][3]]; - b[ 8] = S5[u.temp[2][0]]; - b[ 9] = S5[u.temp[1][1]]; - b[10] = S5[u.temp[0][2]]; - b[11] = S5[u.temp[3][3]]; - b[12] = S5[u.temp[3][0]]; - b[13] = S5[u.temp[2][1]]; - b[14] = S5[u.temp[1][2]]; - b[15] = S5[u.temp[0][3]]; - *((u32*)(b )) ^= *((u32*)rk[0][0]); - *((u32*)(b+ 4)) ^= *((u32*)rk[0][1]); - *((u32*)(b+ 8)) ^= *((u32*)rk[0][2]); - *((u32*)(b+12)) ^= *((u32*)rk[0][3]); -#undef rk -} - - -/* Decrypt one block. AX and BX may be the same. */ -static void -do_decrypt (RIJNDAEL_context *ctx, byte *bx, const byte *ax) -{ - /* BX and AX are not necessary correctly aligned. Thus we need to - copy them here. */ - union - { - u32 dummy[4]; - byte a[16]; - } a; - union - { - u32 dummy[4]; - byte b[16]; - } b; - - if ( !ctx->decryption_prepared ) - { - prepare_decryption ( ctx ); - _gcry_burn_stack (64); - ctx->decryption_prepared = 1; - } - - memcpy (a.a, ax, 16); - do_decrypt_aligned (ctx, b.b, a.a); - memcpy (bx, b.b, 16); -#undef rk -} - - - - -static void -rijndael_decrypt (void *context, byte *b, const byte *a) -{ - RIJNDAEL_context *ctx = context; - -#ifdef USE_PADLOCK - if (ctx->use_padlock) - { - do_padlock (ctx, 1, b, a); - _gcry_burn_stack (48 + 2*sizeof(int) /* FIXME */); - } - else -#endif /*USE_PADLOCK*/ - { - do_decrypt (ctx, b, a); - _gcry_burn_stack (48+2*sizeof(int)); - } -} - - -/* Bulk decryption of complete blocks in CFB mode. Caller needs to - make sure that IV is aligned on an unisgned lonhg boundary. This - function is only intended for the bulk encryption feature of - cipher.c. */ -void -_gcry_aes_cfb_dec (void *context, unsigned char *iv, - void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks) -{ - RIJNDAEL_context *ctx = context; - unsigned char *outbuf = outbuf_arg; - const unsigned char *inbuf = inbuf_arg; - unsigned char *ivp; - unsigned char temp; - int i; - -#ifdef USE_PADLOCK - if (ctx->use_padlock) - { - /* Fixme: Let Padlock do the CFBing. */ - for ( ;nblocks; nblocks-- ) - { - do_padlock (ctx, 0, iv, iv); - for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } - } - } - else -#endif /*USE_PADLOCK*/ - { - for ( ;nblocks; nblocks-- ) - { - do_encrypt_aligned (ctx, iv, iv); - for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } - } - } - - _gcry_burn_stack (48 + 2*sizeof(int)); -} - - -/* Bulk decryption of complete blocks in CBC mode. Caller needs to - make sure that IV is aligned on an unsigned long boundary. This - function is only intended for the bulk encryption feature of - cipher.c. */ -void -_gcry_aes_cbc_dec (void *context, unsigned char *iv, - void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks) -{ - RIJNDAEL_context *ctx = context; - unsigned char *outbuf = outbuf_arg; - const unsigned char *inbuf = inbuf_arg; - unsigned char *ivp; - int i; - unsigned char savebuf[BLOCKSIZE]; - - for ( ;nblocks; nblocks-- ) - { - /* We need to save INBUF away because it may be identical to - OUTBUF. */ - memcpy (savebuf, inbuf, BLOCKSIZE); - -#ifdef USE_PADLOCK - if (ctx->use_padlock) - do_padlock (ctx, 1, outbuf, inbuf); - else -#endif /*USE_PADLOCK*/ - do_decrypt (ctx, outbuf, inbuf); - - for (ivp=iv, i=0; i < BLOCKSIZE; i++ ) - outbuf[i] ^= *ivp++; - memcpy (iv, savebuf, BLOCKSIZE); - inbuf += BLOCKSIZE; - outbuf += BLOCKSIZE; - } - - _gcry_burn_stack (48 + 2*sizeof(int) + BLOCKSIZE + 4*sizeof (char*)); -} - - - - -/* Run the self-tests for AES 128. Returns NULL on success. */ -static const char* -selftest_basic_128 (void) -{ - RIJNDAEL_context ctx; - unsigned char scratch[16]; - - /* The test vectors are from the AES supplied ones; more or less - randomly taken from ecb_tbl.txt (I=42,81,14) */ - static const unsigned char plaintext_128[16] = - { - 0x01,0x4B,0xAF,0x22,0x78,0xA6,0x9D,0x33, - 0x1D,0x51,0x80,0x10,0x36,0x43,0xE9,0x9A - }; - static const unsigned char key_128[16] = - { - 0xE8,0xE9,0xEA,0xEB,0xED,0xEE,0xEF,0xF0, - 0xF2,0xF3,0xF4,0xF5,0xF7,0xF8,0xF9,0xFA - }; - static const unsigned char ciphertext_128[16] = - { - 0x67,0x43,0xC3,0xD1,0x51,0x9A,0xB4,0xF2, - 0xCD,0x9A,0x78,0xAB,0x09,0xA5,0x11,0xBD - }; - - rijndael_setkey (&ctx, key_128, sizeof (key_128)); - rijndael_encrypt (&ctx, scratch, plaintext_128); - if (memcmp (scratch, ciphertext_128, sizeof (ciphertext_128))) - return "AES-128 test encryption failed."; - rijndael_decrypt (&ctx, scratch, scratch); - if (memcmp (scratch, plaintext_128, sizeof (plaintext_128))) - return "AES-128 test decryption failed."; - - return NULL; -} - -/* Run the self-tests for AES 192. Returns NULL on success. */ -static const char* -selftest_basic_192 (void) -{ - RIJNDAEL_context ctx; - unsigned char scratch[16]; - - static unsigned char plaintext_192[16] = - { - 0x76,0x77,0x74,0x75,0xF1,0xF2,0xF3,0xF4, - 0xF8,0xF9,0xE6,0xE7,0x77,0x70,0x71,0x72 - }; - static unsigned char key_192[24] = - { - 0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C, - 0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16, - 0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20 - }; - static const unsigned char ciphertext_192[16] = - { - 0x5D,0x1E,0xF2,0x0D,0xCE,0xD6,0xBC,0xBC, - 0x12,0x13,0x1A,0xC7,0xC5,0x47,0x88,0xAA - }; - - rijndael_setkey (&ctx, key_192, sizeof(key_192)); - rijndael_encrypt (&ctx, scratch, plaintext_192); - if (memcmp (scratch, ciphertext_192, sizeof (ciphertext_192))) - return "AES-192 test encryption failed."; - rijndael_decrypt (&ctx, scratch, scratch); - if (memcmp (scratch, plaintext_192, sizeof (plaintext_192))) - return "AES-192 test decryption failed."; - - return NULL; -} - - -/* Run the self-tests for AES 256. Returns NULL on success. */ -static const char* -selftest_basic_256 (void) -{ - RIJNDAEL_context ctx; - unsigned char scratch[16]; - - static unsigned char plaintext_256[16] = - { - 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, - 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21 - }; - static unsigned char key_256[32] = - { - 0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10, - 0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A, - 0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24, - 0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E - }; - static const unsigned char ciphertext_256[16] = - { - 0x08,0x0E,0x95,0x17,0xEB,0x16,0x77,0x71, - 0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3 - }; - - rijndael_setkey (&ctx, key_256, sizeof(key_256)); - rijndael_encrypt (&ctx, scratch, plaintext_256); - if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256))) - return "AES-256 test encryption failed."; - rijndael_decrypt (&ctx, scratch, scratch); - if (memcmp (scratch, plaintext_256, sizeof (plaintext_256))) - return "AES-256 test decryption failed."; - - return NULL; -} - -/* Run all the self-tests and return NULL on success. This function - is used for the on-the-fly self-tests. */ -static const char * -selftest (void) -{ - const char *r; - - if ( (r = selftest_basic_128 ()) - || (r = selftest_basic_192 ()) - || (r = selftest_basic_256 ()) ) - return r; - - return r; -} - - -/* SP800-38a.pdf for AES-128. */ -static const char * -selftest_fips_128_38a (int requested_mode) -{ - struct tv - { - int mode; - const unsigned char key[16]; - const unsigned char iv[16]; - struct - { - const unsigned char input[16]; - const unsigned char output[16]; - } data[4]; - } tv[2] = - { - { - GCRY_CIPHER_MODE_CFB, /* F.3.13, CFB128-AES128 */ - { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, - { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, - { - { { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, - 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a }, - { 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, - 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a } }, - - { { 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, - 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 }, - { 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, - 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b } }, - - { { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, - 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef }, - { 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, - 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf } }, - - { { 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, - 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, - { 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, - 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6 } } - } - }, - { - GCRY_CIPHER_MODE_OFB, - { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, - { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, - { - { { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, - 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a }, - { 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, - 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a } }, - - { { 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, - 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 }, - { 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, - 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25 } }, - - { { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, - 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef }, - { 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, - 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc } }, - - { { 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, - 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, - { 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, - 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e } }, - } - } - }; - unsigned char scratch[16]; - gpg_error_t err; - int tvi, idx; - gcry_cipher_hd_t hdenc = NULL; - gcry_cipher_hd_t hddec = NULL; - -#define Fail(a) do { \ - _gcry_cipher_close (hdenc); \ - _gcry_cipher_close (hddec); \ - return a; \ - } while (0) - - gcry_assert (sizeof tv[0].data[0].input == sizeof scratch); - gcry_assert (sizeof tv[0].data[0].output == sizeof scratch); - - for (tvi=0; tvi < DIM (tv); tvi++) - if (tv[tvi].mode == requested_mode) - break; - if (tvi == DIM (tv)) - Fail ("no test data for this mode"); - - err = _gcry_cipher_open (&hdenc, GCRY_CIPHER_AES, tv[tvi].mode, 0); - if (err) - Fail ("open"); - err = _gcry_cipher_open (&hddec, GCRY_CIPHER_AES, tv[tvi].mode, 0); - if (err) - Fail ("open"); - err = _gcry_cipher_setkey (hdenc, tv[tvi].key, sizeof tv[tvi].key); - if (!err) - err = _gcry_cipher_setkey (hddec, tv[tvi].key, sizeof tv[tvi].key); - if (err) - Fail ("set key"); - err = _gcry_cipher_setiv (hdenc, tv[tvi].iv, sizeof tv[tvi].iv); - if (!err) - err = _gcry_cipher_setiv (hddec, tv[tvi].iv, sizeof tv[tvi].iv); - if (err) - Fail ("set IV"); - for (idx=0; idx < DIM (tv[tvi].data); idx++) - { - err = _gcry_cipher_encrypt (hdenc, scratch, sizeof scratch, - tv[tvi].data[idx].input, - sizeof tv[tvi].data[idx].input); - if (err) - Fail ("encrypt command"); - if (memcmp (scratch, tv[tvi].data[idx].output, sizeof scratch)) - Fail ("encrypt mismatch"); - err = _gcry_cipher_decrypt (hddec, scratch, sizeof scratch, - tv[tvi].data[idx].output, - sizeof tv[tvi].data[idx].output); - if (err) - Fail ("decrypt command"); - if (memcmp (scratch, tv[tvi].data[idx].input, sizeof scratch)) - Fail ("decrypt mismatch"); - } - -#undef Fail - _gcry_cipher_close (hdenc); - _gcry_cipher_close (hddec); - return NULL; -} - - -/* Complete selftest for AES-128 with all modes and driver code. */ -static gpg_err_code_t -selftest_fips_128 (int extended, selftest_report_func_t report) -{ - const char *what; - const char *errtxt; - - what = "low-level"; - errtxt = selftest_basic_128 (); - if (errtxt) - goto failed; - - if (extended) - { - what = "cfb"; - errtxt = selftest_fips_128_38a (GCRY_CIPHER_MODE_CFB); - if (errtxt) - goto failed; - - what = "ofb"; - errtxt = selftest_fips_128_38a (GCRY_CIPHER_MODE_OFB); - if (errtxt) - goto failed; - } - - return 0; /* Succeeded. */ - - failed: - if (report) - report ("cipher", GCRY_CIPHER_AES128, what, errtxt); - return GPG_ERR_SELFTEST_FAILED; -} - -/* Complete selftest for AES-192. */ -static gpg_err_code_t -selftest_fips_192 (int extended, selftest_report_func_t report) -{ - const char *what; - const char *errtxt; - - (void)extended; /* No extended tests available. */ - - what = "low-level"; - errtxt = selftest_basic_192 (); - if (errtxt) - goto failed; - - - return 0; /* Succeeded. */ - - failed: - if (report) - report ("cipher", GCRY_CIPHER_AES192, what, errtxt); - return GPG_ERR_SELFTEST_FAILED; -} - - -/* Complete selftest for AES-256. */ -static gpg_err_code_t -selftest_fips_256 (int extended, selftest_report_func_t report) -{ - const char *what; - const char *errtxt; - - (void)extended; /* No extended tests available. */ - - what = "low-level"; - errtxt = selftest_basic_256 (); - if (errtxt) - goto failed; - - return 0; /* Succeeded. */ - - failed: - if (report) - report ("cipher", GCRY_CIPHER_AES256, what, errtxt); - return GPG_ERR_SELFTEST_FAILED; -} - - - -/* Run a full self-test for ALGO and return 0 on success. */ -static gpg_err_code_t -run_selftests (int algo, int extended, selftest_report_func_t report) -{ - gpg_err_code_t ec; - - switch (algo) - { - case GCRY_CIPHER_AES128: - ec = selftest_fips_128 (extended, report); - break; - case GCRY_CIPHER_AES192: - ec = selftest_fips_192 (extended, report); - break; - case GCRY_CIPHER_AES256: - ec = selftest_fips_256 (extended, report); - break; - default: - ec = GPG_ERR_CIPHER_ALGO; - break; - - } - return ec; -} - - - - -static const char *rijndael_names[] = - { - "RIJNDAEL", - "AES128", - "AES-128", - NULL - }; - -static gcry_cipher_oid_spec_t rijndael_oids[] = - { - { "2.16.840.1.101.3.4.1.1", GCRY_CIPHER_MODE_ECB }, - { "2.16.840.1.101.3.4.1.2", GCRY_CIPHER_MODE_CBC }, - { "2.16.840.1.101.3.4.1.3", GCRY_CIPHER_MODE_OFB }, - { "2.16.840.1.101.3.4.1.4", GCRY_CIPHER_MODE_CFB }, - { NULL } - }; - -gcry_cipher_spec_t _gcry_cipher_spec_aes = - { - "AES", rijndael_names, rijndael_oids, 16, 128, sizeof (RIJNDAEL_context), - rijndael_setkey, rijndael_encrypt, rijndael_decrypt - }; -cipher_extra_spec_t _gcry_cipher_extraspec_aes = - { - run_selftests - }; - -static const char *rijndael192_names[] = - { - "RIJNDAEL192", - "AES-192", - NULL - }; - -static gcry_cipher_oid_spec_t rijndael192_oids[] = - { - { "2.16.840.1.101.3.4.1.21", GCRY_CIPHER_MODE_ECB }, - { "2.16.840.1.101.3.4.1.22", GCRY_CIPHER_MODE_CBC }, - { "2.16.840.1.101.3.4.1.23", GCRY_CIPHER_MODE_OFB }, - { "2.16.840.1.101.3.4.1.24", GCRY_CIPHER_MODE_CFB }, - { NULL } - }; - -gcry_cipher_spec_t _gcry_cipher_spec_aes192 = - { - "AES192", rijndael192_names, rijndael192_oids, 16, 192, sizeof (RIJNDAEL_context), - rijndael_setkey, rijndael_encrypt, rijndael_decrypt - }; -cipher_extra_spec_t _gcry_cipher_extraspec_aes192 = - { - run_selftests - }; - -static const char *rijndael256_names[] = - { - "RIJNDAEL256", - "AES-256", - NULL - }; - -static gcry_cipher_oid_spec_t rijndael256_oids[] = - { - { "2.16.840.1.101.3.4.1.41", GCRY_CIPHER_MODE_ECB }, - { "2.16.840.1.101.3.4.1.42", GCRY_CIPHER_MODE_CBC }, - { "2.16.840.1.101.3.4.1.43", GCRY_CIPHER_MODE_OFB }, - { "2.16.840.1.101.3.4.1.44", GCRY_CIPHER_MODE_CFB }, - { NULL } - }; - -gcry_cipher_spec_t _gcry_cipher_spec_aes256 = - { - "AES256", rijndael256_names, rijndael256_oids, 16, 256, - sizeof (RIJNDAEL_context), - rijndael_setkey, rijndael_encrypt, rijndael_decrypt - }; - -cipher_extra_spec_t _gcry_cipher_extraspec_aes256 = - { - run_selftests - }; +/* Rijndael (AES) for GnuPG + * Copyright (C) 2000, 2001, 2002, 2003, 2007, + * 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + ******************************************************************* + * The code here is based on the optimized implementation taken from + * http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ on Oct 2, 2000, + * which carries this notice: + *------------------------------------------ + * rijndael-alg-fst.c v2.3 April '2000 + * + * Optimised ANSI C code + * + * authors: v1.0: Antoon Bosselaers + * v2.0: Vincent Rijmen + * v2.3: Paulo Barreto + * + * This code is placed in the public domain. + *------------------------------------------ + * + * The SP800-38a document is available at: + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + * + */ + +#include +#include +#include +#include /* for memcmp() */ + +#include "types.h" /* for byte and u32 typedefs */ +#include "g10lib.h" +#include "cipher.h" + +#define MAXKC (256/32) +#define MAXROUNDS 14 +#define BLOCKSIZE (128/8) + + +/* USE_PADLOCK indicates whether to compile the padlock specific + code. */ +#undef USE_PADLOCK +#ifdef ENABLE_PADLOCK_SUPPORT +# if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__) +# define USE_PADLOCK +# endif +#endif /*ENABLE_PADLOCK_SUPPORT*/ + +static const char *selftest(void); + +typedef struct +{ + int ROUNDS; /* Key-length-dependent number of rounds. */ + int decryption_prepared; /* The decryption key schedule is available. */ +#ifdef USE_PADLOCK + int use_padlock; /* Padlock shall be used. */ + /* The key as passed to the padlock engine. */ + unsigned char padlock_key[16] __attribute__ ((aligned (16))); +#endif + union + { + PROPERLY_ALIGNED_TYPE dummy; + byte keyschedule[MAXROUNDS+1][4][4]; + } u1; + union + { + PROPERLY_ALIGNED_TYPE dummy; + byte keyschedule[MAXROUNDS+1][4][4]; + } u2; +} RIJNDAEL_context; + +#define keySched u1.keyschedule +#define keySched2 u2.keyschedule + +/* All the numbers. */ +#include "rijndael-tables.h" + + +/* Perform the key setup. */ +static gcry_err_code_t +do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen) +{ + static int initialized = 0; + static const char *selftest_failed=0; + int ROUNDS; + int i,j, r, t, rconpointer = 0; + int KC; + union + { + PROPERLY_ALIGNED_TYPE dummy; + byte k[MAXKC][4]; + } k; +#define k k.k + union + { + PROPERLY_ALIGNED_TYPE dummy; + byte tk[MAXKC][4]; + } tk; +#define tk tk.tk + + /* The on-the-fly self tests are only run in non-fips mode. In fips + mode explicit self-tests are required. Actually the on-the-fly + self-tests are not fully thread-safe and it might happen that a + failed self-test won't get noticed in another thread. + + FIXME: We might want to have a central registry of succeeded + self-tests. */ + if (!fips_mode () && !initialized) + { + initialized = 1; + selftest_failed = selftest (); + if (selftest_failed) + log_error ("%s\n", selftest_failed ); + } + if (selftest_failed) + return GPG_ERR_SELFTEST_FAILED; + + ctx->decryption_prepared = 0; +#ifdef USE_PADLOCK + ctx->use_padlock = 0; +#endif + + if( keylen == 128/8 ) + { + ROUNDS = 10; + KC = 4; +#ifdef USE_PADLOCK + if ((_gcry_get_hw_features () & HWF_PADLOCK_AES)) + { + ctx->use_padlock = 1; + memcpy (ctx->padlock_key, key, keylen); + } +#endif + } + else if ( keylen == 192/8 ) + { + ROUNDS = 12; + KC = 6; + } + else if ( keylen == 256/8 ) + { + ROUNDS = 14; + KC = 8; + } + else + return GPG_ERR_INV_KEYLEN; + + ctx->ROUNDS = ROUNDS; + +#ifdef USE_PADLOCK + if (ctx->use_padlock) + { + /* Nothing to do as we support only hardware key generation for + now. */ + } + else +#endif /*USE_PADLOCK*/ + { +#define W (ctx->keySched) + for (i = 0; i < keylen; i++) + { + k[i >> 2][i & 3] = key[i]; + } + + for (j = KC-1; j >= 0; j--) + { + *((u32*)tk[j]) = *((u32*)k[j]); + } + r = 0; + t = 0; + /* Copy values into round key array. */ + for (j = 0; (j < KC) && (r < ROUNDS + 1); ) + { + for (; (j < KC) && (t < 4); j++, t++) + { + *((u32*)W[r][t]) = *((u32*)tk[j]); + } + if (t == 4) + { + r++; + t = 0; + } + } + + while (r < ROUNDS + 1) + { + /* While not enough round key material calculated calculate + new values. */ + tk[0][0] ^= S[tk[KC-1][1]]; + tk[0][1] ^= S[tk[KC-1][2]]; + tk[0][2] ^= S[tk[KC-1][3]]; + tk[0][3] ^= S[tk[KC-1][0]]; + tk[0][0] ^= rcon[rconpointer++]; + + if (KC != 8) + { + for (j = 1; j < KC; j++) + { + *((u32*)tk[j]) ^= *((u32*)tk[j-1]); + } + } + else + { + for (j = 1; j < KC/2; j++) + { + *((u32*)tk[j]) ^= *((u32*)tk[j-1]); + } + tk[KC/2][0] ^= S[tk[KC/2 - 1][0]]; + tk[KC/2][1] ^= S[tk[KC/2 - 1][1]]; + tk[KC/2][2] ^= S[tk[KC/2 - 1][2]]; + tk[KC/2][3] ^= S[tk[KC/2 - 1][3]]; + for (j = KC/2 + 1; j < KC; j++) + { + *((u32*)tk[j]) ^= *((u32*)tk[j-1]); + } + } + + /* Copy values into round key array. */ + for (j = 0; (j < KC) && (r < ROUNDS + 1); ) + { + for (; (j < KC) && (t < 4); j++, t++) + { + *((u32*)W[r][t]) = *((u32*)tk[j]); + } + if (t == 4) + { + r++; + t = 0; + } + } + } +#undef W + } + + return 0; +#undef tk +#undef k +} + + +static gcry_err_code_t +rijndael_setkey (void *context, const byte *key, const unsigned keylen) +{ + RIJNDAEL_context *ctx = context; + + int rc = do_setkey (ctx, key, keylen); + _gcry_burn_stack ( 100 + 16*sizeof(int)); + return rc; +} + + +/* Make a decryption key from an encryption key. */ +static void +prepare_decryption( RIJNDAEL_context *ctx ) +{ + int r; + union + { + PROPERLY_ALIGNED_TYPE dummy; + byte *w; + } w; +#define w w.w + + for (r=0; r < MAXROUNDS+1; r++ ) + { + *((u32*)ctx->keySched2[r][0]) = *((u32*)ctx->keySched[r][0]); + *((u32*)ctx->keySched2[r][1]) = *((u32*)ctx->keySched[r][1]); + *((u32*)ctx->keySched2[r][2]) = *((u32*)ctx->keySched[r][2]); + *((u32*)ctx->keySched2[r][3]) = *((u32*)ctx->keySched[r][3]); + } +#define W (ctx->keySched2) + for (r = 1; r < ctx->ROUNDS; r++) + { + w = W[r][0]; + *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) + ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); + + w = W[r][1]; + *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) + ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); + + w = W[r][2]; + *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) + ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); + + w = W[r][3]; + *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) + ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); + } +#undef W +#undef w +} + + + +/* Encrypt one block. A and B need to be aligned on a 4 byte + boundary. A and B may be the same. */ +static void +do_encrypt_aligned (const RIJNDAEL_context *ctx, + unsigned char *b, const unsigned char *a) +{ +#define rk (ctx->keySched) + int ROUNDS = ctx->ROUNDS; + int r; + union + { + u32 tempu32[4]; /* Force correct alignment. */ + byte temp[4][4]; + } u; + + *((u32*)u.temp[0]) = *((u32*)(a )) ^ *((u32*)rk[0][0]); + *((u32*)u.temp[1]) = *((u32*)(a+ 4)) ^ *((u32*)rk[0][1]); + *((u32*)u.temp[2]) = *((u32*)(a+ 8)) ^ *((u32*)rk[0][2]); + *((u32*)u.temp[3]) = *((u32*)(a+12)) ^ *((u32*)rk[0][3]); + *((u32*)(b )) = (*((u32*)T1[u.temp[0][0]]) + ^ *((u32*)T2[u.temp[1][1]]) + ^ *((u32*)T3[u.temp[2][2]]) + ^ *((u32*)T4[u.temp[3][3]])); + *((u32*)(b + 4)) = (*((u32*)T1[u.temp[1][0]]) + ^ *((u32*)T2[u.temp[2][1]]) + ^ *((u32*)T3[u.temp[3][2]]) + ^ *((u32*)T4[u.temp[0][3]])); + *((u32*)(b + 8)) = (*((u32*)T1[u.temp[2][0]]) + ^ *((u32*)T2[u.temp[3][1]]) + ^ *((u32*)T3[u.temp[0][2]]) + ^ *((u32*)T4[u.temp[1][3]])); + *((u32*)(b +12)) = (*((u32*)T1[u.temp[3][0]]) + ^ *((u32*)T2[u.temp[0][1]]) + ^ *((u32*)T3[u.temp[1][2]]) + ^ *((u32*)T4[u.temp[2][3]])); + + for (r = 1; r < ROUNDS-1; r++) + { + *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[r][0]); + *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[r][1]); + *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[r][2]); + *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[r][3]); + + *((u32*)(b )) = (*((u32*)T1[u.temp[0][0]]) + ^ *((u32*)T2[u.temp[1][1]]) + ^ *((u32*)T3[u.temp[2][2]]) + ^ *((u32*)T4[u.temp[3][3]])); + *((u32*)(b + 4)) = (*((u32*)T1[u.temp[1][0]]) + ^ *((u32*)T2[u.temp[2][1]]) + ^ *((u32*)T3[u.temp[3][2]]) + ^ *((u32*)T4[u.temp[0][3]])); + *((u32*)(b + 8)) = (*((u32*)T1[u.temp[2][0]]) + ^ *((u32*)T2[u.temp[3][1]]) + ^ *((u32*)T3[u.temp[0][2]]) + ^ *((u32*)T4[u.temp[1][3]])); + *((u32*)(b +12)) = (*((u32*)T1[u.temp[3][0]]) + ^ *((u32*)T2[u.temp[0][1]]) + ^ *((u32*)T3[u.temp[1][2]]) + ^ *((u32*)T4[u.temp[2][3]])); + } + + /* Last round is special. */ + *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[ROUNDS-1][0]); + *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[ROUNDS-1][1]); + *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[ROUNDS-1][2]); + *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[ROUNDS-1][3]); + b[ 0] = T1[u.temp[0][0]][1]; + b[ 1] = T1[u.temp[1][1]][1]; + b[ 2] = T1[u.temp[2][2]][1]; + b[ 3] = T1[u.temp[3][3]][1]; + b[ 4] = T1[u.temp[1][0]][1]; + b[ 5] = T1[u.temp[2][1]][1]; + b[ 6] = T1[u.temp[3][2]][1]; + b[ 7] = T1[u.temp[0][3]][1]; + b[ 8] = T1[u.temp[2][0]][1]; + b[ 9] = T1[u.temp[3][1]][1]; + b[10] = T1[u.temp[0][2]][1]; + b[11] = T1[u.temp[1][3]][1]; + b[12] = T1[u.temp[3][0]][1]; + b[13] = T1[u.temp[0][1]][1]; + b[14] = T1[u.temp[1][2]][1]; + b[15] = T1[u.temp[2][3]][1]; + *((u32*)(b )) ^= *((u32*)rk[ROUNDS][0]); + *((u32*)(b+ 4)) ^= *((u32*)rk[ROUNDS][1]); + *((u32*)(b+ 8)) ^= *((u32*)rk[ROUNDS][2]); + *((u32*)(b+12)) ^= *((u32*)rk[ROUNDS][3]); +#undef rk +} + + +static void +do_encrypt (const RIJNDAEL_context *ctx, + unsigned char *bx, const unsigned char *ax) +{ + /* BX and AX are not necessary correctly aligned. Thus we need to + copy them here. */ + union + { + u32 dummy[4]; + byte a[16]; + } a; + union + { + u32 dummy[4]; + byte b[16]; + } b; + + memcpy (a.a, ax, 16); + do_encrypt_aligned (ctx, b.b, a.a); + memcpy (bx, b.b, 16); +} + + +/* Encrypt or decrypt one block using the padlock engine. A and B may + be the same. */ +#ifdef USE_PADLOCK +static void +do_padlock (const RIJNDAEL_context *ctx, int decrypt_flag, + unsigned char *bx, const unsigned char *ax) +{ + /* BX and AX are not necessary correctly aligned. Thus we need to + copy them here. */ + unsigned char a[16] __attribute__ ((aligned (16))); + unsigned char b[16] __attribute__ ((aligned (16))); + unsigned int cword[4] __attribute__ ((aligned (16))); + + /* The control word fields are: + 127:12 11:10 9 8 7 6 5 4 3:0 + RESERVED KSIZE CRYPT INTER KEYGN CIPHR ALIGN DGEST ROUND */ + cword[0] = (ctx->ROUNDS & 15); /* (The mask is just a safeguard.) */ + cword[1] = 0; + cword[2] = 0; + cword[3] = 0; + if (decrypt_flag) + cword[0] |= 0x00000200; + + memcpy (a, ax, 16); + + asm volatile + ("pushfl\n\t" /* Force key reload. */ + "popfl\n\t" + "xchg %3, %%ebx\n\t" /* Load key. */ + "movl $1, %%ecx\n\t" /* Init counter for just one block. */ + ".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t" /* REP XSTORE ECB. */ + "xchg %3, %%ebx\n" /* Restore GOT register. */ + : /* No output */ + : "S" (a), "D" (b), "d" (cword), "r" (ctx->padlock_key) + : "%ecx", "cc", "memory" + ); + + memcpy (bx, b, 16); + +} +#endif /*USE_PADLOCK*/ + + +static void +rijndael_encrypt (void *context, byte *b, const byte *a) +{ + RIJNDAEL_context *ctx = context; + +#ifdef USE_PADLOCK + if (ctx->use_padlock) + { + do_padlock (ctx, 0, b, a); + _gcry_burn_stack (48 + 15 /* possible padding for alignment */); + } + else +#endif /*USE_PADLOCK*/ + { + do_encrypt (ctx, b, a); + _gcry_burn_stack (48 + 2*sizeof(int)); + } +} + + +/* Bulk encryption of complete blocks in CFB mode. Caller needs to + make sure that IV is aligned on an unsigned long boundary. This + function is only intended for the bulk encryption feature of + cipher.c. */ +void +_gcry_aes_cfb_enc (void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + unsigned int nblocks) +{ + RIJNDAEL_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char *ivp; + int i; + +#ifdef USE_PADLOCK + if (ctx->use_padlock) + { + /* Fixme: Let Padlock do the CFBing. */ + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the IV. */ + do_padlock (ctx, 0, iv, iv); + /* XOR the input with the IV and store input into IV. */ + for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) + *outbuf++ = (*ivp++ ^= *inbuf++); + } + } + else +#endif /* USE_PADLOCK*/ + { + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the IV. */ + do_encrypt_aligned (ctx, iv, iv); + /* XOR the input with the IV and store input into IV. */ + for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) + *outbuf++ = (*ivp++ ^= *inbuf++); + } + } + + _gcry_burn_stack (48 + 2*sizeof(int)); +} + + +/* Bulk encryption of complete blocks in CBC mode. Caller needs to + make sure that IV is aligned on an unsigned long boundary. This + function is only intended for the bulk encryption feature of + cipher.c. */ +void +_gcry_aes_cbc_enc (void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + unsigned int nblocks, int cbc_mac) +{ + RIJNDAEL_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char *ivp; + int i; + + for ( ;nblocks; nblocks-- ) + { + for (ivp=iv, i=0; i < BLOCKSIZE; i++ ) + outbuf[i] = inbuf[i] ^ *ivp++; + +#ifdef USE_PADLOCK + if (ctx->use_padlock) + do_padlock (ctx, 0, outbuf, outbuf); + else +#endif /*USE_PADLOCK*/ + do_encrypt (ctx, outbuf, outbuf ); + + memcpy (iv, outbuf, BLOCKSIZE); + inbuf += BLOCKSIZE; + if (!cbc_mac) + outbuf += BLOCKSIZE; + } + + _gcry_burn_stack (48 + 2*sizeof(int)); +} + + + +/* Decrypt one block. A and B need to be aligned on a 4 byte boundary + and the decryption must have been prepared. A and B may be the + same. */ +static void +do_decrypt_aligned (RIJNDAEL_context *ctx, + unsigned char *b, const unsigned char *a) +{ +#define rk (ctx->keySched2) + int ROUNDS = ctx->ROUNDS; + int r; + union + { + u32 tempu32[4]; /* Force correct alignment. */ + byte temp[4][4]; + } u; + + + *((u32*)u.temp[0]) = *((u32*)(a )) ^ *((u32*)rk[ROUNDS][0]); + *((u32*)u.temp[1]) = *((u32*)(a+ 4)) ^ *((u32*)rk[ROUNDS][1]); + *((u32*)u.temp[2]) = *((u32*)(a+ 8)) ^ *((u32*)rk[ROUNDS][2]); + *((u32*)u.temp[3]) = *((u32*)(a+12)) ^ *((u32*)rk[ROUNDS][3]); + + *((u32*)(b )) = (*((u32*)T5[u.temp[0][0]]) + ^ *((u32*)T6[u.temp[3][1]]) + ^ *((u32*)T7[u.temp[2][2]]) + ^ *((u32*)T8[u.temp[1][3]])); + *((u32*)(b+ 4)) = (*((u32*)T5[u.temp[1][0]]) + ^ *((u32*)T6[u.temp[0][1]]) + ^ *((u32*)T7[u.temp[3][2]]) + ^ *((u32*)T8[u.temp[2][3]])); + *((u32*)(b+ 8)) = (*((u32*)T5[u.temp[2][0]]) + ^ *((u32*)T6[u.temp[1][1]]) + ^ *((u32*)T7[u.temp[0][2]]) + ^ *((u32*)T8[u.temp[3][3]])); + *((u32*)(b+12)) = (*((u32*)T5[u.temp[3][0]]) + ^ *((u32*)T6[u.temp[2][1]]) + ^ *((u32*)T7[u.temp[1][2]]) + ^ *((u32*)T8[u.temp[0][3]])); + + for (r = ROUNDS-1; r > 1; r--) + { + *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[r][0]); + *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[r][1]); + *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[r][2]); + *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[r][3]); + *((u32*)(b )) = (*((u32*)T5[u.temp[0][0]]) + ^ *((u32*)T6[u.temp[3][1]]) + ^ *((u32*)T7[u.temp[2][2]]) + ^ *((u32*)T8[u.temp[1][3]])); + *((u32*)(b+ 4)) = (*((u32*)T5[u.temp[1][0]]) + ^ *((u32*)T6[u.temp[0][1]]) + ^ *((u32*)T7[u.temp[3][2]]) + ^ *((u32*)T8[u.temp[2][3]])); + *((u32*)(b+ 8)) = (*((u32*)T5[u.temp[2][0]]) + ^ *((u32*)T6[u.temp[1][1]]) + ^ *((u32*)T7[u.temp[0][2]]) + ^ *((u32*)T8[u.temp[3][3]])); + *((u32*)(b+12)) = (*((u32*)T5[u.temp[3][0]]) + ^ *((u32*)T6[u.temp[2][1]]) + ^ *((u32*)T7[u.temp[1][2]]) + ^ *((u32*)T8[u.temp[0][3]])); + } + + /* Last round is special. */ + *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[1][0]); + *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[1][1]); + *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[1][2]); + *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[1][3]); + b[ 0] = S5[u.temp[0][0]]; + b[ 1] = S5[u.temp[3][1]]; + b[ 2] = S5[u.temp[2][2]]; + b[ 3] = S5[u.temp[1][3]]; + b[ 4] = S5[u.temp[1][0]]; + b[ 5] = S5[u.temp[0][1]]; + b[ 6] = S5[u.temp[3][2]]; + b[ 7] = S5[u.temp[2][3]]; + b[ 8] = S5[u.temp[2][0]]; + b[ 9] = S5[u.temp[1][1]]; + b[10] = S5[u.temp[0][2]]; + b[11] = S5[u.temp[3][3]]; + b[12] = S5[u.temp[3][0]]; + b[13] = S5[u.temp[2][1]]; + b[14] = S5[u.temp[1][2]]; + b[15] = S5[u.temp[0][3]]; + *((u32*)(b )) ^= *((u32*)rk[0][0]); + *((u32*)(b+ 4)) ^= *((u32*)rk[0][1]); + *((u32*)(b+ 8)) ^= *((u32*)rk[0][2]); + *((u32*)(b+12)) ^= *((u32*)rk[0][3]); +#undef rk +} + + +/* Decrypt one block. AX and BX may be the same. */ +static void +do_decrypt (RIJNDAEL_context *ctx, byte *bx, const byte *ax) +{ + /* BX and AX are not necessary correctly aligned. Thus we need to + copy them here. */ + union + { + u32 dummy[4]; + byte a[16]; + } a; + union + { + u32 dummy[4]; + byte b[16]; + } b; + + if ( !ctx->decryption_prepared ) + { + prepare_decryption ( ctx ); + _gcry_burn_stack (64); + ctx->decryption_prepared = 1; + } + + memcpy (a.a, ax, 16); + do_decrypt_aligned (ctx, b.b, a.a); + memcpy (bx, b.b, 16); +#undef rk +} + + + + +static void +rijndael_decrypt (void *context, byte *b, const byte *a) +{ + RIJNDAEL_context *ctx = context; + +#ifdef USE_PADLOCK + if (ctx->use_padlock) + { + do_padlock (ctx, 1, b, a); + _gcry_burn_stack (48 + 2*sizeof(int) /* FIXME */); + } + else +#endif /*USE_PADLOCK*/ + { + do_decrypt (ctx, b, a); + _gcry_burn_stack (48+2*sizeof(int)); + } +} + + +/* Bulk decryption of complete blocks in CFB mode. Caller needs to + make sure that IV is aligned on an unisgned lonhg boundary. This + function is only intended for the bulk encryption feature of + cipher.c. */ +void +_gcry_aes_cfb_dec (void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + unsigned int nblocks) +{ + RIJNDAEL_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char *ivp; + unsigned char temp; + int i; + +#ifdef USE_PADLOCK + if (ctx->use_padlock) + { + /* Fixme: Let Padlock do the CFBing. */ + for ( ;nblocks; nblocks-- ) + { + do_padlock (ctx, 0, iv, iv); + for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) + { + temp = *inbuf++; + *outbuf++ = *ivp ^ temp; + *ivp++ = temp; + } + } + } + else +#endif /*USE_PADLOCK*/ + { + for ( ;nblocks; nblocks-- ) + { + do_encrypt_aligned (ctx, iv, iv); + for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) + { + temp = *inbuf++; + *outbuf++ = *ivp ^ temp; + *ivp++ = temp; + } + } + } + + _gcry_burn_stack (48 + 2*sizeof(int)); +} + + +/* Bulk decryption of complete blocks in CBC mode. Caller needs to + make sure that IV is aligned on an unsigned long boundary. This + function is only intended for the bulk encryption feature of + cipher.c. */ +void +_gcry_aes_cbc_dec (void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + unsigned int nblocks) +{ + RIJNDAEL_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char *ivp; + int i; + unsigned char savebuf[BLOCKSIZE]; + + for ( ;nblocks; nblocks-- ) + { + /* We need to save INBUF away because it may be identical to + OUTBUF. */ + memcpy (savebuf, inbuf, BLOCKSIZE); + +#ifdef USE_PADLOCK + if (ctx->use_padlock) + do_padlock (ctx, 1, outbuf, inbuf); + else +#endif /*USE_PADLOCK*/ + do_decrypt (ctx, outbuf, inbuf); + + for (ivp=iv, i=0; i < BLOCKSIZE; i++ ) + outbuf[i] ^= *ivp++; + memcpy (iv, savebuf, BLOCKSIZE); + inbuf += BLOCKSIZE; + outbuf += BLOCKSIZE; + } + + _gcry_burn_stack (48 + 2*sizeof(int) + BLOCKSIZE + 4*sizeof (char*)); +} + + + + +/* Run the self-tests for AES 128. Returns NULL on success. */ +static const char* +selftest_basic_128 (void) +{ + RIJNDAEL_context ctx; + unsigned char scratch[16]; + + /* The test vectors are from the AES supplied ones; more or less + randomly taken from ecb_tbl.txt (I=42,81,14) */ + static const unsigned char plaintext_128[16] = + { + 0x01,0x4B,0xAF,0x22,0x78,0xA6,0x9D,0x33, + 0x1D,0x51,0x80,0x10,0x36,0x43,0xE9,0x9A + }; + static const unsigned char key_128[16] = + { + 0xE8,0xE9,0xEA,0xEB,0xED,0xEE,0xEF,0xF0, + 0xF2,0xF3,0xF4,0xF5,0xF7,0xF8,0xF9,0xFA + }; + static const unsigned char ciphertext_128[16] = + { + 0x67,0x43,0xC3,0xD1,0x51,0x9A,0xB4,0xF2, + 0xCD,0x9A,0x78,0xAB,0x09,0xA5,0x11,0xBD + }; + + rijndael_setkey (&ctx, key_128, sizeof (key_128)); + rijndael_encrypt (&ctx, scratch, plaintext_128); + if (memcmp (scratch, ciphertext_128, sizeof (ciphertext_128))) + return "AES-128 test encryption failed."; + rijndael_decrypt (&ctx, scratch, scratch); + if (memcmp (scratch, plaintext_128, sizeof (plaintext_128))) + return "AES-128 test decryption failed."; + + return NULL; +} + +/* Run the self-tests for AES 192. Returns NULL on success. */ +static const char* +selftest_basic_192 (void) +{ + RIJNDAEL_context ctx; + unsigned char scratch[16]; + + static unsigned char plaintext_192[16] = + { + 0x76,0x77,0x74,0x75,0xF1,0xF2,0xF3,0xF4, + 0xF8,0xF9,0xE6,0xE7,0x77,0x70,0x71,0x72 + }; + static unsigned char key_192[24] = + { + 0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C, + 0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16, + 0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20 + }; + static const unsigned char ciphertext_192[16] = + { + 0x5D,0x1E,0xF2,0x0D,0xCE,0xD6,0xBC,0xBC, + 0x12,0x13,0x1A,0xC7,0xC5,0x47,0x88,0xAA + }; + + rijndael_setkey (&ctx, key_192, sizeof(key_192)); + rijndael_encrypt (&ctx, scratch, plaintext_192); + if (memcmp (scratch, ciphertext_192, sizeof (ciphertext_192))) + return "AES-192 test encryption failed."; + rijndael_decrypt (&ctx, scratch, scratch); + if (memcmp (scratch, plaintext_192, sizeof (plaintext_192))) + return "AES-192 test decryption failed."; + + return NULL; +} + + +/* Run the self-tests for AES 256. Returns NULL on success. */ +static const char* +selftest_basic_256 (void) +{ + RIJNDAEL_context ctx; + unsigned char scratch[16]; + + static unsigned char plaintext_256[16] = + { + 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21 + }; + static unsigned char key_256[32] = + { + 0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10, + 0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A, + 0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24, + 0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E + }; + static const unsigned char ciphertext_256[16] = + { + 0x08,0x0E,0x95,0x17,0xEB,0x16,0x77,0x71, + 0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3 + }; + + rijndael_setkey (&ctx, key_256, sizeof(key_256)); + rijndael_encrypt (&ctx, scratch, plaintext_256); + if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256))) + return "AES-256 test encryption failed."; + rijndael_decrypt (&ctx, scratch, scratch); + if (memcmp (scratch, plaintext_256, sizeof (plaintext_256))) + return "AES-256 test decryption failed."; + + return NULL; +} + +/* Run all the self-tests and return NULL on success. This function + is used for the on-the-fly self-tests. */ +static const char * +selftest (void) +{ + const char *r; + + if ( (r = selftest_basic_128 ()) + || (r = selftest_basic_192 ()) + || (r = selftest_basic_256 ()) ) + return r; + + return r; +} + + +/* SP800-38a.pdf for AES-128. */ +static const char * +selftest_fips_128_38a (int requested_mode) +{ + struct tv + { + int mode; + const unsigned char key[16]; + const unsigned char iv[16]; + struct + { + const unsigned char input[16]; + const unsigned char output[16]; + } data[4]; + } tv[2] = + { + { + GCRY_CIPHER_MODE_CFB, /* F.3.13, CFB128-AES128 */ + { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { + { { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a }, + { 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, + 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a } }, + + { { 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 }, + { 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, + 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b } }, + + { { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef }, + { 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, + 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf } }, + + { { 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, + { 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, + 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6 } } + } + }, + { + GCRY_CIPHER_MODE_OFB, + { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { + { { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a }, + { 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, + 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a } }, + + { { 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 }, + { 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, + 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25 } }, + + { { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef }, + { 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, + 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc } }, + + { { 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, + { 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, + 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e } }, + } + } + }; + unsigned char scratch[16]; + gpg_error_t err; + int tvi, idx; + gcry_cipher_hd_t hdenc = NULL; + gcry_cipher_hd_t hddec = NULL; + +#define Fail(a) do { \ + _gcry_cipher_close (hdenc); \ + _gcry_cipher_close (hddec); \ + return a; \ + } while (0) + + gcry_assert (sizeof tv[0].data[0].input == sizeof scratch); + gcry_assert (sizeof tv[0].data[0].output == sizeof scratch); + + for (tvi=0; tvi < DIM (tv); tvi++) + if (tv[tvi].mode == requested_mode) + break; + if (tvi == DIM (tv)) + Fail ("no test data for this mode"); + + err = _gcry_cipher_open (&hdenc, GCRY_CIPHER_AES, tv[tvi].mode, 0); + if (err) + Fail ("open"); + err = _gcry_cipher_open (&hddec, GCRY_CIPHER_AES, tv[tvi].mode, 0); + if (err) + Fail ("open"); + err = _gcry_cipher_setkey (hdenc, tv[tvi].key, sizeof tv[tvi].key); + if (!err) + err = _gcry_cipher_setkey (hddec, tv[tvi].key, sizeof tv[tvi].key); + if (err) + Fail ("set key"); + err = _gcry_cipher_setiv (hdenc, tv[tvi].iv, sizeof tv[tvi].iv); + if (!err) + err = _gcry_cipher_setiv (hddec, tv[tvi].iv, sizeof tv[tvi].iv); + if (err) + Fail ("set IV"); + for (idx=0; idx < DIM (tv[tvi].data); idx++) + { + err = _gcry_cipher_encrypt (hdenc, scratch, sizeof scratch, + tv[tvi].data[idx].input, + sizeof tv[tvi].data[idx].input); + if (err) + Fail ("encrypt command"); + if (memcmp (scratch, tv[tvi].data[idx].output, sizeof scratch)) + Fail ("encrypt mismatch"); + err = _gcry_cipher_decrypt (hddec, scratch, sizeof scratch, + tv[tvi].data[idx].output, + sizeof tv[tvi].data[idx].output); + if (err) + Fail ("decrypt command"); + if (memcmp (scratch, tv[tvi].data[idx].input, sizeof scratch)) + Fail ("decrypt mismatch"); + } + +#undef Fail + _gcry_cipher_close (hdenc); + _gcry_cipher_close (hddec); + return NULL; +} + + +/* Complete selftest for AES-128 with all modes and driver code. */ +static gpg_err_code_t +selftest_fips_128 (int extended, selftest_report_func_t report) +{ + const char *what; + const char *errtxt; + + what = "low-level"; + errtxt = selftest_basic_128 (); + if (errtxt) + goto failed; + + if (extended) + { + what = "cfb"; + errtxt = selftest_fips_128_38a (GCRY_CIPHER_MODE_CFB); + if (errtxt) + goto failed; + + what = "ofb"; + errtxt = selftest_fips_128_38a (GCRY_CIPHER_MODE_OFB); + if (errtxt) + goto failed; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("cipher", GCRY_CIPHER_AES128, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + +/* Complete selftest for AES-192. */ +static gpg_err_code_t +selftest_fips_192 (int extended, selftest_report_func_t report) +{ + const char *what; + const char *errtxt; + + (void)extended; /* No extended tests available. */ + + what = "low-level"; + errtxt = selftest_basic_192 (); + if (errtxt) + goto failed; + + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("cipher", GCRY_CIPHER_AES192, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + +/* Complete selftest for AES-256. */ +static gpg_err_code_t +selftest_fips_256 (int extended, selftest_report_func_t report) +{ + const char *what; + const char *errtxt; + + (void)extended; /* No extended tests available. */ + + what = "low-level"; + errtxt = selftest_basic_256 (); + if (errtxt) + goto failed; + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("cipher", GCRY_CIPHER_AES256, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + + +/* Run a full self-test for ALGO and return 0 on success. */ +static gpg_err_code_t +run_selftests (int algo, int extended, selftest_report_func_t report) +{ + gpg_err_code_t ec; + + switch (algo) + { + case GCRY_CIPHER_AES128: + ec = selftest_fips_128 (extended, report); + break; + case GCRY_CIPHER_AES192: + ec = selftest_fips_192 (extended, report); + break; + case GCRY_CIPHER_AES256: + ec = selftest_fips_256 (extended, report); + break; + default: + ec = GPG_ERR_CIPHER_ALGO; + break; + + } + return ec; +} + + + + +static const char *rijndael_names[] = + { + "RIJNDAEL", + "AES128", + "AES-128", + NULL + }; + +static gcry_cipher_oid_spec_t rijndael_oids[] = + { + { "2.16.840.1.101.3.4.1.1", GCRY_CIPHER_MODE_ECB }, + { "2.16.840.1.101.3.4.1.2", GCRY_CIPHER_MODE_CBC }, + { "2.16.840.1.101.3.4.1.3", GCRY_CIPHER_MODE_OFB }, + { "2.16.840.1.101.3.4.1.4", GCRY_CIPHER_MODE_CFB }, + { NULL } + }; + +gcry_cipher_spec_t _gcry_cipher_spec_aes = + { + "AES", rijndael_names, rijndael_oids, 16, 128, sizeof (RIJNDAEL_context), + rijndael_setkey, rijndael_encrypt, rijndael_decrypt + }; +cipher_extra_spec_t _gcry_cipher_extraspec_aes = + { + run_selftests + }; + +static const char *rijndael192_names[] = + { + "RIJNDAEL192", + "AES-192", + NULL + }; + +static gcry_cipher_oid_spec_t rijndael192_oids[] = + { + { "2.16.840.1.101.3.4.1.21", GCRY_CIPHER_MODE_ECB }, + { "2.16.840.1.101.3.4.1.22", GCRY_CIPHER_MODE_CBC }, + { "2.16.840.1.101.3.4.1.23", GCRY_CIPHER_MODE_OFB }, + { "2.16.840.1.101.3.4.1.24", GCRY_CIPHER_MODE_CFB }, + { NULL } + }; + +gcry_cipher_spec_t _gcry_cipher_spec_aes192 = + { + "AES192", rijndael192_names, rijndael192_oids, 16, 192, sizeof (RIJNDAEL_context), + rijndael_setkey, rijndael_encrypt, rijndael_decrypt + }; +cipher_extra_spec_t _gcry_cipher_extraspec_aes192 = + { + run_selftests + }; + +static const char *rijndael256_names[] = + { + "RIJNDAEL256", + "AES-256", + NULL + }; + +static gcry_cipher_oid_spec_t rijndael256_oids[] = + { + { "2.16.840.1.101.3.4.1.41", GCRY_CIPHER_MODE_ECB }, + { "2.16.840.1.101.3.4.1.42", GCRY_CIPHER_MODE_CBC }, + { "2.16.840.1.101.3.4.1.43", GCRY_CIPHER_MODE_OFB }, + { "2.16.840.1.101.3.4.1.44", GCRY_CIPHER_MODE_CFB }, + { NULL } + }; + +gcry_cipher_spec_t _gcry_cipher_spec_aes256 = + { + "AES256", rijndael256_names, rijndael256_oids, 16, 256, + sizeof (RIJNDAEL_context), + rijndael_setkey, rijndael_encrypt, rijndael_decrypt + }; + +cipher_extra_spec_t _gcry_cipher_extraspec_aes256 = + { + run_selftests + }; diff --git a/libgcrypt-1.4.6/cipher/serpent.c b/libgcrypt-1.4.6/cipher/serpent.c index 6b7e655..0ac0b5b 100644 --- a/libgcrypt-1.4.6/cipher/serpent.c +++ b/libgcrypt-1.4.6/cipher/serpent.c @@ -1,978 +1,978 @@ -/* serpent.c - Implementation of the Serpent encryption algorithm. - * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser general Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include - -#include -#include - -#include "types.h" -#include "g10lib.h" -#include "cipher.h" -#include "bithelp.h" - -/* Number of rounds per Serpent encrypt/decrypt operation. */ -#define ROUNDS 32 - -/* Magic number, used during generating of the subkeys. */ -#define PHI 0x9E3779B9 - -/* Serpent works on 128 bit blocks. */ -typedef u32 serpent_block_t[4]; - -/* Serpent key, provided by the user. If the original key is shorter - than 256 bits, it is padded. */ -typedef u32 serpent_key_t[8]; - -/* The key schedule consists of 33 128 bit subkeys. */ -typedef u32 serpent_subkeys_t[ROUNDS + 1][4]; - -/* A Serpent context. */ -typedef struct serpent_context -{ - serpent_subkeys_t keys; /* Generated subkeys. */ -} serpent_context_t; - - -/* A prototype. */ -static const char *serpent_test (void); - - -#define byte_swap_32(x) \ - (0 \ - | (((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) \ - | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) - -/* These are the S-Boxes of Serpent. They are copied from Serpents - reference implementation (the optimized one, contained in - `floppy2') and are therefore: - - Copyright (C) 1998 Ross Anderson, Eli Biham, Lars Knudsen. - - To quote the Serpent homepage - (http://www.cl.cam.ac.uk/~rja14/serpent.html): - - "Serpent is now completely in the public domain, and we impose no - restrictions on its use. This was announced on the 21st August at - the First AES Candidate Conference. The optimised implementations - in the submission package are now under the GNU PUBLIC LICENSE - (GPL), although some comments in the code still say otherwise. You - are welcome to use Serpent for any application." */ - -#define SBOX0(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t05, t06, t07, t08, t09; \ - u32 t11, t12, t13, t14, t15, t17, t01; \ - t01 = b ^ c ; \ - t02 = a | d ; \ - t03 = a ^ b ; \ - z = t02 ^ t01; \ - t05 = c | z ; \ - t06 = a ^ d ; \ - t07 = b | c ; \ - t08 = d & t05; \ - t09 = t03 & t07; \ - y = t09 ^ t08; \ - t11 = t09 & y ; \ - t12 = c ^ d ; \ - t13 = t07 ^ t11; \ - t14 = b & t06; \ - t15 = t06 ^ t13; \ - w = ~ t15; \ - t17 = w ^ t14; \ - x = t12 ^ t17; \ - } - -#define SBOX0_INVERSE(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t05, t06, t08, t09, t10; \ - u32 t12, t13, t14, t15, t17, t18, t01; \ - t01 = c ^ d ; \ - t02 = a | b ; \ - t03 = b | c ; \ - t04 = c & t01; \ - t05 = t02 ^ t01; \ - t06 = a | t04; \ - y = ~ t05; \ - t08 = b ^ d ; \ - t09 = t03 & t08; \ - t10 = d | y ; \ - x = t09 ^ t06; \ - t12 = a | t05; \ - t13 = x ^ t12; \ - t14 = t03 ^ t10; \ - t15 = a ^ c ; \ - z = t14 ^ t13; \ - t17 = t05 & t13; \ - t18 = t14 | t17; \ - w = t15 ^ t18; \ - } - -#define SBOX1(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t05, t06, t07, t08; \ - u32 t10, t11, t12, t13, t16, t17, t01; \ - t01 = a | d ; \ - t02 = c ^ d ; \ - t03 = ~ b ; \ - t04 = a ^ c ; \ - t05 = a | t03; \ - t06 = d & t04; \ - t07 = t01 & t02; \ - t08 = b | t06; \ - y = t02 ^ t05; \ - t10 = t07 ^ t08; \ - t11 = t01 ^ t10; \ - t12 = y ^ t11; \ - t13 = b & d ; \ - z = ~ t10; \ - x = t13 ^ t12; \ - t16 = t10 | x ; \ - t17 = t05 & t16; \ - w = c ^ t17; \ - } - -#define SBOX1_INVERSE(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t05, t06, t07, t08; \ - u32 t09, t10, t11, t14, t15, t17, t01; \ - t01 = a ^ b ; \ - t02 = b | d ; \ - t03 = a & c ; \ - t04 = c ^ t02; \ - t05 = a | t04; \ - t06 = t01 & t05; \ - t07 = d | t03; \ - t08 = b ^ t06; \ - t09 = t07 ^ t06; \ - t10 = t04 | t03; \ - t11 = d & t08; \ - y = ~ t09; \ - x = t10 ^ t11; \ - t14 = a | y ; \ - t15 = t06 ^ x ; \ - z = t01 ^ t04; \ - t17 = c ^ t15; \ - w = t14 ^ t17; \ - } - -#define SBOX2(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t05, t06, t07, t08; \ - u32 t09, t10, t12, t13, t14, t01; \ - t01 = a | c ; \ - t02 = a ^ b ; \ - t03 = d ^ t01; \ - w = t02 ^ t03; \ - t05 = c ^ w ; \ - t06 = b ^ t05; \ - t07 = b | t05; \ - t08 = t01 & t06; \ - t09 = t03 ^ t07; \ - t10 = t02 | t09; \ - x = t10 ^ t08; \ - t12 = a | d ; \ - t13 = t09 ^ x ; \ - t14 = b ^ t13; \ - z = ~ t09; \ - y = t12 ^ t14; \ - } - -#define SBOX2_INVERSE(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t06, t07, t08, t09; \ - u32 t10, t11, t12, t15, t16, t17, t01; \ - t01 = a ^ d ; \ - t02 = c ^ d ; \ - t03 = a & c ; \ - t04 = b | t02; \ - w = t01 ^ t04; \ - t06 = a | c ; \ - t07 = d | w ; \ - t08 = ~ d ; \ - t09 = b & t06; \ - t10 = t08 | t03; \ - t11 = b & t07; \ - t12 = t06 & t02; \ - z = t09 ^ t10; \ - x = t12 ^ t11; \ - t15 = c & z ; \ - t16 = w ^ x ; \ - t17 = t10 ^ t15; \ - y = t16 ^ t17; \ - } - -#define SBOX3(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t05, t06, t07, t08; \ - u32 t09, t10, t11, t13, t14, t15, t01; \ - t01 = a ^ c ; \ - t02 = a | d ; \ - t03 = a & d ; \ - t04 = t01 & t02; \ - t05 = b | t03; \ - t06 = a & b ; \ - t07 = d ^ t04; \ - t08 = c | t06; \ - t09 = b ^ t07; \ - t10 = d & t05; \ - t11 = t02 ^ t10; \ - z = t08 ^ t09; \ - t13 = d | z ; \ - t14 = a | t07; \ - t15 = b & t13; \ - y = t08 ^ t11; \ - w = t14 ^ t15; \ - x = t05 ^ t04; \ - } - -#define SBOX3_INVERSE(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t05, t06, t07, t09; \ - u32 t11, t12, t13, t14, t16, t01; \ - t01 = c | d ; \ - t02 = a | d ; \ - t03 = c ^ t02; \ - t04 = b ^ t02; \ - t05 = a ^ d ; \ - t06 = t04 & t03; \ - t07 = b & t01; \ - y = t05 ^ t06; \ - t09 = a ^ t03; \ - w = t07 ^ t03; \ - t11 = w | t05; \ - t12 = t09 & t11; \ - t13 = a & y ; \ - t14 = t01 ^ t05; \ - x = b ^ t12; \ - t16 = b | t13; \ - z = t14 ^ t16; \ - } - -#define SBOX4(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t05, t06, t08, t09; \ - u32 t10, t11, t12, t13, t14, t15, t16, t01; \ - t01 = a | b ; \ - t02 = b | c ; \ - t03 = a ^ t02; \ - t04 = b ^ d ; \ - t05 = d | t03; \ - t06 = d & t01; \ - z = t03 ^ t06; \ - t08 = z & t04; \ - t09 = t04 & t05; \ - t10 = c ^ t06; \ - t11 = b & c ; \ - t12 = t04 ^ t08; \ - t13 = t11 | t03; \ - t14 = t10 ^ t09; \ - t15 = a & t05; \ - t16 = t11 | t12; \ - y = t13 ^ t08; \ - x = t15 ^ t16; \ - w = ~ t14; \ - } - -#define SBOX4_INVERSE(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t05, t06, t07, t09; \ - u32 t10, t11, t12, t13, t15, t01; \ - t01 = b | d ; \ - t02 = c | d ; \ - t03 = a & t01; \ - t04 = b ^ t02; \ - t05 = c ^ d ; \ - t06 = ~ t03; \ - t07 = a & t04; \ - x = t05 ^ t07; \ - t09 = x | t06; \ - t10 = a ^ t07; \ - t11 = t01 ^ t09; \ - t12 = d ^ t04; \ - t13 = c | t10; \ - z = t03 ^ t12; \ - t15 = a ^ t04; \ - y = t11 ^ t13; \ - w = t15 ^ t09; \ - } - -#define SBOX5(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t05, t07, t08, t09; \ - u32 t10, t11, t12, t13, t14, t01; \ - t01 = b ^ d ; \ - t02 = b | d ; \ - t03 = a & t01; \ - t04 = c ^ t02; \ - t05 = t03 ^ t04; \ - w = ~ t05; \ - t07 = a ^ t01; \ - t08 = d | w ; \ - t09 = b | t05; \ - t10 = d ^ t08; \ - t11 = b | t07; \ - t12 = t03 | w ; \ - t13 = t07 | t10; \ - t14 = t01 ^ t11; \ - y = t09 ^ t13; \ - x = t07 ^ t08; \ - z = t12 ^ t14; \ - } - -#define SBOX5_INVERSE(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t05, t07, t08, t09; \ - u32 t10, t12, t13, t15, t16, t01; \ - t01 = a & d ; \ - t02 = c ^ t01; \ - t03 = a ^ d ; \ - t04 = b & t02; \ - t05 = a & c ; \ - w = t03 ^ t04; \ - t07 = a & w ; \ - t08 = t01 ^ w ; \ - t09 = b | t05; \ - t10 = ~ b ; \ - x = t08 ^ t09; \ - t12 = t10 | t07; \ - t13 = w | x ; \ - z = t02 ^ t12; \ - t15 = t02 ^ t13; \ - t16 = b ^ d ; \ - y = t16 ^ t15; \ - } - -#define SBOX6(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t05, t07, t08, t09, t10; \ - u32 t11, t12, t13, t15, t17, t18, t01; \ - t01 = a & d ; \ - t02 = b ^ c ; \ - t03 = a ^ d ; \ - t04 = t01 ^ t02; \ - t05 = b | c ; \ - x = ~ t04; \ - t07 = t03 & t05; \ - t08 = b & x ; \ - t09 = a | c ; \ - t10 = t07 ^ t08; \ - t11 = b | d ; \ - t12 = c ^ t11; \ - t13 = t09 ^ t10; \ - y = ~ t13; \ - t15 = x & t03; \ - z = t12 ^ t07; \ - t17 = a ^ b ; \ - t18 = y ^ t15; \ - w = t17 ^ t18; \ - } - -#define SBOX6_INVERSE(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t05, t06, t07, t08, t09; \ - u32 t12, t13, t14, t15, t16, t17, t01; \ - t01 = a ^ c ; \ - t02 = ~ c ; \ - t03 = b & t01; \ - t04 = b | t02; \ - t05 = d | t03; \ - t06 = b ^ d ; \ - t07 = a & t04; \ - t08 = a | t02; \ - t09 = t07 ^ t05; \ - x = t06 ^ t08; \ - w = ~ t09; \ - t12 = b & w ; \ - t13 = t01 & t05; \ - t14 = t01 ^ t12; \ - t15 = t07 ^ t13; \ - t16 = d | t02; \ - t17 = a ^ x ; \ - z = t17 ^ t15; \ - y = t16 ^ t14; \ - } - -#define SBOX7(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t05, t06, t08, t09, t10; \ - u32 t11, t13, t14, t15, t16, t17, t01; \ - t01 = a & c ; \ - t02 = ~ d ; \ - t03 = a & t02; \ - t04 = b | t01; \ - t05 = a & b ; \ - t06 = c ^ t04; \ - z = t03 ^ t06; \ - t08 = c | z ; \ - t09 = d | t05; \ - t10 = a ^ t08; \ - t11 = t04 & z ; \ - x = t09 ^ t10; \ - t13 = b ^ x ; \ - t14 = t01 ^ x ; \ - t15 = c ^ t05; \ - t16 = t11 | t13; \ - t17 = t02 | t14; \ - w = t15 ^ t17; \ - y = a ^ t16; \ - } - -#define SBOX7_INVERSE(a, b, c, d, w, x, y, z) \ - { \ - u32 t02, t03, t04, t06, t07, t08, t09; \ - u32 t10, t11, t13, t14, t15, t16, t01; \ - t01 = a & b ; \ - t02 = a | b ; \ - t03 = c | t01; \ - t04 = d & t02; \ - z = t03 ^ t04; \ - t06 = b ^ t04; \ - t07 = d ^ z ; \ - t08 = ~ t07; \ - t09 = t06 | t08; \ - t10 = b ^ d ; \ - t11 = a | d ; \ - x = a ^ t09; \ - t13 = c ^ t06; \ - t14 = c & t11; \ - t15 = d | x ; \ - t16 = t01 | t10; \ - w = t13 ^ t15; \ - y = t14 ^ t16; \ - } - -/* XOR BLOCK1 into BLOCK0. */ -#define BLOCK_XOR(block0, block1) \ - { \ - block0[0] ^= block1[0]; \ - block0[1] ^= block1[1]; \ - block0[2] ^= block1[2]; \ - block0[3] ^= block1[3]; \ - } - -/* Copy BLOCK_SRC to BLOCK_DST. */ -#define BLOCK_COPY(block_dst, block_src) \ - { \ - block_dst[0] = block_src[0]; \ - block_dst[1] = block_src[1]; \ - block_dst[2] = block_src[2]; \ - block_dst[3] = block_src[3]; \ - } - -/* Apply SBOX number WHICH to to the block found in ARRAY0 at index - INDEX, writing the output to the block found in ARRAY1 at index - INDEX. */ -#define SBOX(which, array0, array1, index) \ - SBOX##which (array0[index + 0], array0[index + 1], \ - array0[index + 2], array0[index + 3], \ - array1[index + 0], array1[index + 1], \ - array1[index + 2], array1[index + 3]); - -/* Apply inverse SBOX number WHICH to to the block found in ARRAY0 at - index INDEX, writing the output to the block found in ARRAY1 at - index INDEX. */ -#define SBOX_INVERSE(which, array0, array1, index) \ - SBOX##which##_INVERSE (array0[index + 0], array0[index + 1], \ - array0[index + 2], array0[index + 3], \ - array1[index + 0], array1[index + 1], \ - array1[index + 2], array1[index + 3]); - -/* Apply the linear transformation to BLOCK. */ -#define LINEAR_TRANSFORMATION(block) \ - { \ - block[0] = rol (block[0], 13); \ - block[2] = rol (block[2], 3); \ - block[1] = block[1] ^ block[0] ^ block[2]; \ - block[3] = block[3] ^ block[2] ^ (block[0] << 3); \ - block[1] = rol (block[1], 1); \ - block[3] = rol (block[3], 7); \ - block[0] = block[0] ^ block[1] ^ block[3]; \ - block[2] = block[2] ^ block[3] ^ (block[1] << 7); \ - block[0] = rol (block[0], 5); \ - block[2] = rol (block[2], 22); \ - } - -/* Apply the inverse linear transformation to BLOCK. */ -#define LINEAR_TRANSFORMATION_INVERSE(block) \ - { \ - block[2] = ror (block[2], 22); \ - block[0] = ror (block[0] , 5); \ - block[2] = block[2] ^ block[3] ^ (block[1] << 7); \ - block[0] = block[0] ^ block[1] ^ block[3]; \ - block[3] = ror (block[3], 7); \ - block[1] = ror (block[1], 1); \ - block[3] = block[3] ^ block[2] ^ (block[0] << 3); \ - block[1] = block[1] ^ block[0] ^ block[2]; \ - block[2] = ror (block[2], 3); \ - block[0] = ror (block[0], 13); \ - } - -/* Apply a Serpent round to BLOCK, using the SBOX number WHICH and the - subkeys contained in SUBKEYS. Use BLOCK_TMP as temporary storage. - This macro increments `round'. */ -#define ROUND(which, subkeys, block, block_tmp) \ - { \ - BLOCK_XOR (block, subkeys[round]); \ - round++; \ - SBOX (which, block, block_tmp, 0); \ - LINEAR_TRANSFORMATION (block_tmp); \ - BLOCK_COPY (block, block_tmp); \ - } - -/* Apply the last Serpent round to BLOCK, using the SBOX number WHICH - and the subkeys contained in SUBKEYS. Use BLOCK_TMP as temporary - storage. The result will be stored in BLOCK_TMP. This macro - increments `round'. */ -#define ROUND_LAST(which, subkeys, block, block_tmp) \ - { \ - BLOCK_XOR (block, subkeys[round]); \ - round++; \ - SBOX (which, block, block_tmp, 0); \ - BLOCK_XOR (block_tmp, subkeys[round]); \ - round++; \ - } - -/* Apply an inverse Serpent round to BLOCK, using the SBOX number - WHICH and the subkeys contained in SUBKEYS. Use BLOCK_TMP as - temporary storage. This macro increments `round'. */ -#define ROUND_INVERSE(which, subkey, block, block_tmp) \ - { \ - LINEAR_TRANSFORMATION_INVERSE (block); \ - SBOX_INVERSE (which, block, block_tmp, 0); \ - BLOCK_XOR (block_tmp, subkey[round]); \ - round--; \ - BLOCK_COPY (block, block_tmp); \ - } - -/* Apply the first Serpent round to BLOCK, using the SBOX number WHICH - and the subkeys contained in SUBKEYS. Use BLOCK_TMP as temporary - storage. The result will be stored in BLOCK_TMP. This macro - increments `round'. */ -#define ROUND_FIRST_INVERSE(which, subkeys, block, block_tmp) \ - { \ - BLOCK_XOR (block, subkeys[round]); \ - round--; \ - SBOX_INVERSE (which, block, block_tmp, 0); \ - BLOCK_XOR (block_tmp, subkeys[round]); \ - round--; \ - } - -/* Convert the user provided key KEY of KEY_LENGTH bytes into the - internally used format. */ -static void -serpent_key_prepare (const byte *key, unsigned int key_length, - serpent_key_t key_prepared) -{ - int i; - - /* Copy key. */ - for (i = 0; i < key_length / 4; i++) - { -#ifdef WORDS_BIGENDIAN - key_prepared[i] = byte_swap_32 (((u32 *) key)[i]); -#else - key_prepared[i] = ((u32 *) key)[i]; -#endif - } - - if (i < 8) - { - /* Key must be padded according to the Serpent - specification. */ - key_prepared[i] = 0x00000001; - - for (i++; i < 8; i++) - key_prepared[i] = 0; - } -} - -/* Derive the 33 subkeys from KEY and store them in SUBKEYS. */ -static void -serpent_subkeys_generate (serpent_key_t key, serpent_subkeys_t subkeys) -{ - u32 w_real[140]; /* The `prekey'. */ - u32 k[132]; - u32 *w = &w_real[8]; - int i, j; - - /* Initialize with key values. */ - for (i = 0; i < 8; i++) - w[i - 8] = key[i]; - - /* Expand to intermediate key using the affine recurrence. */ - for (i = 0; i < 132; i++) - w[i] = rol (w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11); - - /* Calculate subkeys via S-Boxes, in bitslice mode. */ - SBOX (3, w, k, 0); - SBOX (2, w, k, 4); - SBOX (1, w, k, 8); - SBOX (0, w, k, 12); - SBOX (7, w, k, 16); - SBOX (6, w, k, 20); - SBOX (5, w, k, 24); - SBOX (4, w, k, 28); - SBOX (3, w, k, 32); - SBOX (2, w, k, 36); - SBOX (1, w, k, 40); - SBOX (0, w, k, 44); - SBOX (7, w, k, 48); - SBOX (6, w, k, 52); - SBOX (5, w, k, 56); - SBOX (4, w, k, 60); - SBOX (3, w, k, 64); - SBOX (2, w, k, 68); - SBOX (1, w, k, 72); - SBOX (0, w, k, 76); - SBOX (7, w, k, 80); - SBOX (6, w, k, 84); - SBOX (5, w, k, 88); - SBOX (4, w, k, 92); - SBOX (3, w, k, 96); - SBOX (2, w, k, 100); - SBOX (1, w, k, 104); - SBOX (0, w, k, 108); - SBOX (7, w, k, 112); - SBOX (6, w, k, 116); - SBOX (5, w, k, 120); - SBOX (4, w, k, 124); - SBOX (3, w, k, 128); - - /* Renumber subkeys. */ - for (i = 0; i < ROUNDS + 1; i++) - for (j = 0; j < 4; j++) - subkeys[i][j] = k[4 * i + j]; -} - -/* Initialize CONTEXT with the key KEY of KEY_LENGTH bits. */ -static void -serpent_setkey_internal (serpent_context_t *context, - const byte *key, unsigned int key_length) -{ - serpent_key_t key_prepared; - - serpent_key_prepare (key, key_length, key_prepared); - serpent_subkeys_generate (key_prepared, context->keys); - _gcry_burn_stack (272 * sizeof (u32)); -} - -/* Initialize CTX with the key KEY of KEY_LENGTH bytes. */ -static gcry_err_code_t -serpent_setkey (void *ctx, - const byte *key, unsigned int key_length) -{ - serpent_context_t *context = ctx; - static const char *serpent_test_ret; - static int serpent_init_done; - gcry_err_code_t ret = GPG_ERR_NO_ERROR; - - if (! serpent_init_done) - { - /* Execute a self-test the first time, Serpent is used. */ - serpent_test_ret = serpent_test (); - if (serpent_test_ret) - log_error ("Serpent test failure: %s\n", serpent_test_ret); - serpent_init_done = 1; - } - - if (serpent_test_ret) - ret = GPG_ERR_SELFTEST_FAILED; - else - { - serpent_setkey_internal (context, key, key_length); - _gcry_burn_stack (sizeof (serpent_key_t)); - } - - return ret; -} - -static void -serpent_encrypt_internal (serpent_context_t *context, - const serpent_block_t input, serpent_block_t output) -{ - serpent_block_t b, b_next; - int round = 0; - -#ifdef WORDS_BIGENDIAN - b[0] = byte_swap_32 (input[0]); - b[1] = byte_swap_32 (input[1]); - b[2] = byte_swap_32 (input[2]); - b[3] = byte_swap_32 (input[3]); -#else - b[0] = input[0]; - b[1] = input[1]; - b[2] = input[2]; - b[3] = input[3]; -#endif - - ROUND (0, context->keys, b, b_next); - ROUND (1, context->keys, b, b_next); - ROUND (2, context->keys, b, b_next); - ROUND (3, context->keys, b, b_next); - ROUND (4, context->keys, b, b_next); - ROUND (5, context->keys, b, b_next); - ROUND (6, context->keys, b, b_next); - ROUND (7, context->keys, b, b_next); - ROUND (0, context->keys, b, b_next); - ROUND (1, context->keys, b, b_next); - ROUND (2, context->keys, b, b_next); - ROUND (3, context->keys, b, b_next); - ROUND (4, context->keys, b, b_next); - ROUND (5, context->keys, b, b_next); - ROUND (6, context->keys, b, b_next); - ROUND (7, context->keys, b, b_next); - ROUND (0, context->keys, b, b_next); - ROUND (1, context->keys, b, b_next); - ROUND (2, context->keys, b, b_next); - ROUND (3, context->keys, b, b_next); - ROUND (4, context->keys, b, b_next); - ROUND (5, context->keys, b, b_next); - ROUND (6, context->keys, b, b_next); - ROUND (7, context->keys, b, b_next); - ROUND (0, context->keys, b, b_next); - ROUND (1, context->keys, b, b_next); - ROUND (2, context->keys, b, b_next); - ROUND (3, context->keys, b, b_next); - ROUND (4, context->keys, b, b_next); - ROUND (5, context->keys, b, b_next); - ROUND (6, context->keys, b, b_next); - - ROUND_LAST (7, context->keys, b, b_next); - -#ifdef WORDS_BIGENDIAN - output[0] = byte_swap_32 (b_next[0]); - output[1] = byte_swap_32 (b_next[1]); - output[2] = byte_swap_32 (b_next[2]); - output[3] = byte_swap_32 (b_next[3]); -#else - output[0] = b_next[0]; - output[1] = b_next[1]; - output[2] = b_next[2]; - output[3] = b_next[3]; -#endif -} - -static void -serpent_decrypt_internal (serpent_context_t *context, - const serpent_block_t input, serpent_block_t output) -{ - serpent_block_t b, b_next; - int round = ROUNDS; - -#ifdef WORDS_BIGENDIAN - b_next[0] = byte_swap_32 (input[0]); - b_next[1] = byte_swap_32 (input[1]); - b_next[2] = byte_swap_32 (input[2]); - b_next[3] = byte_swap_32 (input[3]); -#else - b_next[0] = input[0]; - b_next[1] = input[1]; - b_next[2] = input[2]; - b_next[3] = input[3]; -#endif - - ROUND_FIRST_INVERSE (7, context->keys, b_next, b); - - ROUND_INVERSE (6, context->keys, b, b_next); - ROUND_INVERSE (5, context->keys, b, b_next); - ROUND_INVERSE (4, context->keys, b, b_next); - ROUND_INVERSE (3, context->keys, b, b_next); - ROUND_INVERSE (2, context->keys, b, b_next); - ROUND_INVERSE (1, context->keys, b, b_next); - ROUND_INVERSE (0, context->keys, b, b_next); - ROUND_INVERSE (7, context->keys, b, b_next); - ROUND_INVERSE (6, context->keys, b, b_next); - ROUND_INVERSE (5, context->keys, b, b_next); - ROUND_INVERSE (4, context->keys, b, b_next); - ROUND_INVERSE (3, context->keys, b, b_next); - ROUND_INVERSE (2, context->keys, b, b_next); - ROUND_INVERSE (1, context->keys, b, b_next); - ROUND_INVERSE (0, context->keys, b, b_next); - ROUND_INVERSE (7, context->keys, b, b_next); - ROUND_INVERSE (6, context->keys, b, b_next); - ROUND_INVERSE (5, context->keys, b, b_next); - ROUND_INVERSE (4, context->keys, b, b_next); - ROUND_INVERSE (3, context->keys, b, b_next); - ROUND_INVERSE (2, context->keys, b, b_next); - ROUND_INVERSE (1, context->keys, b, b_next); - ROUND_INVERSE (0, context->keys, b, b_next); - ROUND_INVERSE (7, context->keys, b, b_next); - ROUND_INVERSE (6, context->keys, b, b_next); - ROUND_INVERSE (5, context->keys, b, b_next); - ROUND_INVERSE (4, context->keys, b, b_next); - ROUND_INVERSE (3, context->keys, b, b_next); - ROUND_INVERSE (2, context->keys, b, b_next); - ROUND_INVERSE (1, context->keys, b, b_next); - ROUND_INVERSE (0, context->keys, b, b_next); - - -#ifdef WORDS_BIGENDIAN - output[0] = byte_swap_32 (b_next[0]); - output[1] = byte_swap_32 (b_next[1]); - output[2] = byte_swap_32 (b_next[2]); - output[3] = byte_swap_32 (b_next[3]); -#else - output[0] = b_next[0]; - output[1] = b_next[1]; - output[2] = b_next[2]; - output[3] = b_next[3]; -#endif -} - -static void -serpent_encrypt (void *ctx, byte *buffer_out, const byte *buffer_in) -{ - serpent_context_t *context = ctx; - - serpent_encrypt_internal (context, - (const u32 *) buffer_in, (u32 *) buffer_out); - _gcry_burn_stack (2 * sizeof (serpent_block_t)); -} - -static void -serpent_decrypt (void *ctx, byte *buffer_out, const byte *buffer_in) -{ - serpent_context_t *context = ctx; - - serpent_decrypt_internal (context, - (const u32 *) buffer_in, - (u32 *) buffer_out); - _gcry_burn_stack (2 * sizeof (serpent_block_t)); -} - - - -/* Serpent test. */ - -static const char * -serpent_test (void) -{ - serpent_context_t context; - unsigned char scratch[16]; - unsigned int i; - - static struct test - { - int key_length; - unsigned char key[32]; - unsigned char text_plain[16]; - unsigned char text_cipher[16]; - } test_data[] = - { - { - 16, - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - "\xD2\x9D\x57\x6F\xCE\xA3\xA3\xA7\xED\x90\x99\xF2\x92\x73\xD7\x8E", - "\xB2\x28\x8B\x96\x8A\xE8\xB0\x86\x48\xD1\xCE\x96\x06\xFD\x99\x2D" - }, - { - 24, - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - "\xD2\x9D\x57\x6F\xCE\xAB\xA3\xA7\xED\x98\x99\xF2\x92\x7B\xD7\x8E", - "\x13\x0E\x35\x3E\x10\x37\xC2\x24\x05\xE8\xFA\xEF\xB2\xC3\xC3\xE9" - }, - { - 32, - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - "\xD0\x95\x57\x6F\xCE\xA3\xE3\xA7\xED\x98\xD9\xF2\x90\x73\xD7\x8E", - "\xB9\x0E\xE5\x86\x2D\xE6\x91\x68\xF2\xBD\xD5\x12\x5B\x45\x47\x2B" - }, - { - 32, - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - "\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00", - "\x20\x61\xA4\x27\x82\xBD\x52\xEC\x69\x1E\xC3\x83\xB0\x3B\xA7\x7C" - }, - { - 0 - }, - }; - - for (i = 0; test_data[i].key_length; i++) - { - serpent_setkey_internal (&context, test_data[i].key, - test_data[i].key_length); - serpent_encrypt_internal (&context, - (const u32 *) test_data[i].text_plain, - (u32 *) scratch); - - if (memcmp (scratch, test_data[i].text_cipher, sizeof (serpent_block_t))) - switch (test_data[i].key_length) - { - case 16: - return "Serpent-128 test encryption failed."; - case 24: - return "Serpent-192 test encryption failed."; - case 32: - return "Serpent-256 test encryption failed."; - } - - serpent_decrypt_internal (&context, - (const u32 *) test_data[i].text_cipher, - (u32 *) scratch); - if (memcmp (scratch, test_data[i].text_plain, sizeof (serpent_block_t))) - switch (test_data[i].key_length) - { - case 16: - return "Serpent-128 test decryption failed."; - case 24: - return "Serpent-192 test decryption failed."; - case 32: - return "Serpent-256 test decryption failed."; - } - } - - return NULL; -} - - - -/* "SERPENT" is an alias for "SERPENT128". */ -static const char *cipher_spec_serpent128_aliases[] = - { - "SERPENT", - NULL - }; - -gcry_cipher_spec_t _gcry_cipher_spec_serpent128 = - { - "SERPENT128", cipher_spec_serpent128_aliases, NULL, 16, 128, - sizeof (serpent_context_t), - serpent_setkey, serpent_encrypt, serpent_decrypt - }; - -gcry_cipher_spec_t _gcry_cipher_spec_serpent192 = - { - "SERPENT192", NULL, NULL, 16, 192, - sizeof (serpent_context_t), - serpent_setkey, serpent_encrypt, serpent_decrypt - }; - -gcry_cipher_spec_t _gcry_cipher_spec_serpent256 = - { - "SERPENT256", NULL, NULL, 16, 256, - sizeof (serpent_context_t), - serpent_setkey, serpent_encrypt, serpent_decrypt - }; +/* serpent.c - Implementation of the Serpent encryption algorithm. + * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include +#include + +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "bithelp.h" + +/* Number of rounds per Serpent encrypt/decrypt operation. */ +#define ROUNDS 32 + +/* Magic number, used during generating of the subkeys. */ +#define PHI 0x9E3779B9 + +/* Serpent works on 128 bit blocks. */ +typedef u32 serpent_block_t[4]; + +/* Serpent key, provided by the user. If the original key is shorter + than 256 bits, it is padded. */ +typedef u32 serpent_key_t[8]; + +/* The key schedule consists of 33 128 bit subkeys. */ +typedef u32 serpent_subkeys_t[ROUNDS + 1][4]; + +/* A Serpent context. */ +typedef struct serpent_context +{ + serpent_subkeys_t keys; /* Generated subkeys. */ +} serpent_context_t; + + +/* A prototype. */ +static const char *serpent_test (void); + + +#define byte_swap_32(x) \ + (0 \ + | (((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) \ + | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +/* These are the S-Boxes of Serpent. They are copied from Serpents + reference implementation (the optimized one, contained in + `floppy2') and are therefore: + + Copyright (C) 1998 Ross Anderson, Eli Biham, Lars Knudsen. + + To quote the Serpent homepage + (http://www.cl.cam.ac.uk/~rja14/serpent.html): + + "Serpent is now completely in the public domain, and we impose no + restrictions on its use. This was announced on the 21st August at + the First AES Candidate Conference. The optimised implementations + in the submission package are now under the GNU PUBLIC LICENSE + (GPL), although some comments in the code still say otherwise. You + are welcome to use Serpent for any application." */ + +#define SBOX0(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t05, t06, t07, t08, t09; \ + u32 t11, t12, t13, t14, t15, t17, t01; \ + t01 = b ^ c ; \ + t02 = a | d ; \ + t03 = a ^ b ; \ + z = t02 ^ t01; \ + t05 = c | z ; \ + t06 = a ^ d ; \ + t07 = b | c ; \ + t08 = d & t05; \ + t09 = t03 & t07; \ + y = t09 ^ t08; \ + t11 = t09 & y ; \ + t12 = c ^ d ; \ + t13 = t07 ^ t11; \ + t14 = b & t06; \ + t15 = t06 ^ t13; \ + w = ~ t15; \ + t17 = w ^ t14; \ + x = t12 ^ t17; \ + } + +#define SBOX0_INVERSE(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t05, t06, t08, t09, t10; \ + u32 t12, t13, t14, t15, t17, t18, t01; \ + t01 = c ^ d ; \ + t02 = a | b ; \ + t03 = b | c ; \ + t04 = c & t01; \ + t05 = t02 ^ t01; \ + t06 = a | t04; \ + y = ~ t05; \ + t08 = b ^ d ; \ + t09 = t03 & t08; \ + t10 = d | y ; \ + x = t09 ^ t06; \ + t12 = a | t05; \ + t13 = x ^ t12; \ + t14 = t03 ^ t10; \ + t15 = a ^ c ; \ + z = t14 ^ t13; \ + t17 = t05 & t13; \ + t18 = t14 | t17; \ + w = t15 ^ t18; \ + } + +#define SBOX1(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t05, t06, t07, t08; \ + u32 t10, t11, t12, t13, t16, t17, t01; \ + t01 = a | d ; \ + t02 = c ^ d ; \ + t03 = ~ b ; \ + t04 = a ^ c ; \ + t05 = a | t03; \ + t06 = d & t04; \ + t07 = t01 & t02; \ + t08 = b | t06; \ + y = t02 ^ t05; \ + t10 = t07 ^ t08; \ + t11 = t01 ^ t10; \ + t12 = y ^ t11; \ + t13 = b & d ; \ + z = ~ t10; \ + x = t13 ^ t12; \ + t16 = t10 | x ; \ + t17 = t05 & t16; \ + w = c ^ t17; \ + } + +#define SBOX1_INVERSE(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t05, t06, t07, t08; \ + u32 t09, t10, t11, t14, t15, t17, t01; \ + t01 = a ^ b ; \ + t02 = b | d ; \ + t03 = a & c ; \ + t04 = c ^ t02; \ + t05 = a | t04; \ + t06 = t01 & t05; \ + t07 = d | t03; \ + t08 = b ^ t06; \ + t09 = t07 ^ t06; \ + t10 = t04 | t03; \ + t11 = d & t08; \ + y = ~ t09; \ + x = t10 ^ t11; \ + t14 = a | y ; \ + t15 = t06 ^ x ; \ + z = t01 ^ t04; \ + t17 = c ^ t15; \ + w = t14 ^ t17; \ + } + +#define SBOX2(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t05, t06, t07, t08; \ + u32 t09, t10, t12, t13, t14, t01; \ + t01 = a | c ; \ + t02 = a ^ b ; \ + t03 = d ^ t01; \ + w = t02 ^ t03; \ + t05 = c ^ w ; \ + t06 = b ^ t05; \ + t07 = b | t05; \ + t08 = t01 & t06; \ + t09 = t03 ^ t07; \ + t10 = t02 | t09; \ + x = t10 ^ t08; \ + t12 = a | d ; \ + t13 = t09 ^ x ; \ + t14 = b ^ t13; \ + z = ~ t09; \ + y = t12 ^ t14; \ + } + +#define SBOX2_INVERSE(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t06, t07, t08, t09; \ + u32 t10, t11, t12, t15, t16, t17, t01; \ + t01 = a ^ d ; \ + t02 = c ^ d ; \ + t03 = a & c ; \ + t04 = b | t02; \ + w = t01 ^ t04; \ + t06 = a | c ; \ + t07 = d | w ; \ + t08 = ~ d ; \ + t09 = b & t06; \ + t10 = t08 | t03; \ + t11 = b & t07; \ + t12 = t06 & t02; \ + z = t09 ^ t10; \ + x = t12 ^ t11; \ + t15 = c & z ; \ + t16 = w ^ x ; \ + t17 = t10 ^ t15; \ + y = t16 ^ t17; \ + } + +#define SBOX3(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t05, t06, t07, t08; \ + u32 t09, t10, t11, t13, t14, t15, t01; \ + t01 = a ^ c ; \ + t02 = a | d ; \ + t03 = a & d ; \ + t04 = t01 & t02; \ + t05 = b | t03; \ + t06 = a & b ; \ + t07 = d ^ t04; \ + t08 = c | t06; \ + t09 = b ^ t07; \ + t10 = d & t05; \ + t11 = t02 ^ t10; \ + z = t08 ^ t09; \ + t13 = d | z ; \ + t14 = a | t07; \ + t15 = b & t13; \ + y = t08 ^ t11; \ + w = t14 ^ t15; \ + x = t05 ^ t04; \ + } + +#define SBOX3_INVERSE(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t05, t06, t07, t09; \ + u32 t11, t12, t13, t14, t16, t01; \ + t01 = c | d ; \ + t02 = a | d ; \ + t03 = c ^ t02; \ + t04 = b ^ t02; \ + t05 = a ^ d ; \ + t06 = t04 & t03; \ + t07 = b & t01; \ + y = t05 ^ t06; \ + t09 = a ^ t03; \ + w = t07 ^ t03; \ + t11 = w | t05; \ + t12 = t09 & t11; \ + t13 = a & y ; \ + t14 = t01 ^ t05; \ + x = b ^ t12; \ + t16 = b | t13; \ + z = t14 ^ t16; \ + } + +#define SBOX4(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t05, t06, t08, t09; \ + u32 t10, t11, t12, t13, t14, t15, t16, t01; \ + t01 = a | b ; \ + t02 = b | c ; \ + t03 = a ^ t02; \ + t04 = b ^ d ; \ + t05 = d | t03; \ + t06 = d & t01; \ + z = t03 ^ t06; \ + t08 = z & t04; \ + t09 = t04 & t05; \ + t10 = c ^ t06; \ + t11 = b & c ; \ + t12 = t04 ^ t08; \ + t13 = t11 | t03; \ + t14 = t10 ^ t09; \ + t15 = a & t05; \ + t16 = t11 | t12; \ + y = t13 ^ t08; \ + x = t15 ^ t16; \ + w = ~ t14; \ + } + +#define SBOX4_INVERSE(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t05, t06, t07, t09; \ + u32 t10, t11, t12, t13, t15, t01; \ + t01 = b | d ; \ + t02 = c | d ; \ + t03 = a & t01; \ + t04 = b ^ t02; \ + t05 = c ^ d ; \ + t06 = ~ t03; \ + t07 = a & t04; \ + x = t05 ^ t07; \ + t09 = x | t06; \ + t10 = a ^ t07; \ + t11 = t01 ^ t09; \ + t12 = d ^ t04; \ + t13 = c | t10; \ + z = t03 ^ t12; \ + t15 = a ^ t04; \ + y = t11 ^ t13; \ + w = t15 ^ t09; \ + } + +#define SBOX5(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t05, t07, t08, t09; \ + u32 t10, t11, t12, t13, t14, t01; \ + t01 = b ^ d ; \ + t02 = b | d ; \ + t03 = a & t01; \ + t04 = c ^ t02; \ + t05 = t03 ^ t04; \ + w = ~ t05; \ + t07 = a ^ t01; \ + t08 = d | w ; \ + t09 = b | t05; \ + t10 = d ^ t08; \ + t11 = b | t07; \ + t12 = t03 | w ; \ + t13 = t07 | t10; \ + t14 = t01 ^ t11; \ + y = t09 ^ t13; \ + x = t07 ^ t08; \ + z = t12 ^ t14; \ + } + +#define SBOX5_INVERSE(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t05, t07, t08, t09; \ + u32 t10, t12, t13, t15, t16, t01; \ + t01 = a & d ; \ + t02 = c ^ t01; \ + t03 = a ^ d ; \ + t04 = b & t02; \ + t05 = a & c ; \ + w = t03 ^ t04; \ + t07 = a & w ; \ + t08 = t01 ^ w ; \ + t09 = b | t05; \ + t10 = ~ b ; \ + x = t08 ^ t09; \ + t12 = t10 | t07; \ + t13 = w | x ; \ + z = t02 ^ t12; \ + t15 = t02 ^ t13; \ + t16 = b ^ d ; \ + y = t16 ^ t15; \ + } + +#define SBOX6(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t05, t07, t08, t09, t10; \ + u32 t11, t12, t13, t15, t17, t18, t01; \ + t01 = a & d ; \ + t02 = b ^ c ; \ + t03 = a ^ d ; \ + t04 = t01 ^ t02; \ + t05 = b | c ; \ + x = ~ t04; \ + t07 = t03 & t05; \ + t08 = b & x ; \ + t09 = a | c ; \ + t10 = t07 ^ t08; \ + t11 = b | d ; \ + t12 = c ^ t11; \ + t13 = t09 ^ t10; \ + y = ~ t13; \ + t15 = x & t03; \ + z = t12 ^ t07; \ + t17 = a ^ b ; \ + t18 = y ^ t15; \ + w = t17 ^ t18; \ + } + +#define SBOX6_INVERSE(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t05, t06, t07, t08, t09; \ + u32 t12, t13, t14, t15, t16, t17, t01; \ + t01 = a ^ c ; \ + t02 = ~ c ; \ + t03 = b & t01; \ + t04 = b | t02; \ + t05 = d | t03; \ + t06 = b ^ d ; \ + t07 = a & t04; \ + t08 = a | t02; \ + t09 = t07 ^ t05; \ + x = t06 ^ t08; \ + w = ~ t09; \ + t12 = b & w ; \ + t13 = t01 & t05; \ + t14 = t01 ^ t12; \ + t15 = t07 ^ t13; \ + t16 = d | t02; \ + t17 = a ^ x ; \ + z = t17 ^ t15; \ + y = t16 ^ t14; \ + } + +#define SBOX7(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t05, t06, t08, t09, t10; \ + u32 t11, t13, t14, t15, t16, t17, t01; \ + t01 = a & c ; \ + t02 = ~ d ; \ + t03 = a & t02; \ + t04 = b | t01; \ + t05 = a & b ; \ + t06 = c ^ t04; \ + z = t03 ^ t06; \ + t08 = c | z ; \ + t09 = d | t05; \ + t10 = a ^ t08; \ + t11 = t04 & z ; \ + x = t09 ^ t10; \ + t13 = b ^ x ; \ + t14 = t01 ^ x ; \ + t15 = c ^ t05; \ + t16 = t11 | t13; \ + t17 = t02 | t14; \ + w = t15 ^ t17; \ + y = a ^ t16; \ + } + +#define SBOX7_INVERSE(a, b, c, d, w, x, y, z) \ + { \ + u32 t02, t03, t04, t06, t07, t08, t09; \ + u32 t10, t11, t13, t14, t15, t16, t01; \ + t01 = a & b ; \ + t02 = a | b ; \ + t03 = c | t01; \ + t04 = d & t02; \ + z = t03 ^ t04; \ + t06 = b ^ t04; \ + t07 = d ^ z ; \ + t08 = ~ t07; \ + t09 = t06 | t08; \ + t10 = b ^ d ; \ + t11 = a | d ; \ + x = a ^ t09; \ + t13 = c ^ t06; \ + t14 = c & t11; \ + t15 = d | x ; \ + t16 = t01 | t10; \ + w = t13 ^ t15; \ + y = t14 ^ t16; \ + } + +/* XOR BLOCK1 into BLOCK0. */ +#define BLOCK_XOR(block0, block1) \ + { \ + block0[0] ^= block1[0]; \ + block0[1] ^= block1[1]; \ + block0[2] ^= block1[2]; \ + block0[3] ^= block1[3]; \ + } + +/* Copy BLOCK_SRC to BLOCK_DST. */ +#define BLOCK_COPY(block_dst, block_src) \ + { \ + block_dst[0] = block_src[0]; \ + block_dst[1] = block_src[1]; \ + block_dst[2] = block_src[2]; \ + block_dst[3] = block_src[3]; \ + } + +/* Apply SBOX number WHICH to to the block found in ARRAY0 at index + INDEX, writing the output to the block found in ARRAY1 at index + INDEX. */ +#define SBOX(which, array0, array1, index) \ + SBOX##which (array0[index + 0], array0[index + 1], \ + array0[index + 2], array0[index + 3], \ + array1[index + 0], array1[index + 1], \ + array1[index + 2], array1[index + 3]); + +/* Apply inverse SBOX number WHICH to to the block found in ARRAY0 at + index INDEX, writing the output to the block found in ARRAY1 at + index INDEX. */ +#define SBOX_INVERSE(which, array0, array1, index) \ + SBOX##which##_INVERSE (array0[index + 0], array0[index + 1], \ + array0[index + 2], array0[index + 3], \ + array1[index + 0], array1[index + 1], \ + array1[index + 2], array1[index + 3]); + +/* Apply the linear transformation to BLOCK. */ +#define LINEAR_TRANSFORMATION(block) \ + { \ + block[0] = rol (block[0], 13); \ + block[2] = rol (block[2], 3); \ + block[1] = block[1] ^ block[0] ^ block[2]; \ + block[3] = block[3] ^ block[2] ^ (block[0] << 3); \ + block[1] = rol (block[1], 1); \ + block[3] = rol (block[3], 7); \ + block[0] = block[0] ^ block[1] ^ block[3]; \ + block[2] = block[2] ^ block[3] ^ (block[1] << 7); \ + block[0] = rol (block[0], 5); \ + block[2] = rol (block[2], 22); \ + } + +/* Apply the inverse linear transformation to BLOCK. */ +#define LINEAR_TRANSFORMATION_INVERSE(block) \ + { \ + block[2] = ror (block[2], 22); \ + block[0] = ror (block[0] , 5); \ + block[2] = block[2] ^ block[3] ^ (block[1] << 7); \ + block[0] = block[0] ^ block[1] ^ block[3]; \ + block[3] = ror (block[3], 7); \ + block[1] = ror (block[1], 1); \ + block[3] = block[3] ^ block[2] ^ (block[0] << 3); \ + block[1] = block[1] ^ block[0] ^ block[2]; \ + block[2] = ror (block[2], 3); \ + block[0] = ror (block[0], 13); \ + } + +/* Apply a Serpent round to BLOCK, using the SBOX number WHICH and the + subkeys contained in SUBKEYS. Use BLOCK_TMP as temporary storage. + This macro increments `round'. */ +#define ROUND(which, subkeys, block, block_tmp) \ + { \ + BLOCK_XOR (block, subkeys[round]); \ + round++; \ + SBOX (which, block, block_tmp, 0); \ + LINEAR_TRANSFORMATION (block_tmp); \ + BLOCK_COPY (block, block_tmp); \ + } + +/* Apply the last Serpent round to BLOCK, using the SBOX number WHICH + and the subkeys contained in SUBKEYS. Use BLOCK_TMP as temporary + storage. The result will be stored in BLOCK_TMP. This macro + increments `round'. */ +#define ROUND_LAST(which, subkeys, block, block_tmp) \ + { \ + BLOCK_XOR (block, subkeys[round]); \ + round++; \ + SBOX (which, block, block_tmp, 0); \ + BLOCK_XOR (block_tmp, subkeys[round]); \ + round++; \ + } + +/* Apply an inverse Serpent round to BLOCK, using the SBOX number + WHICH and the subkeys contained in SUBKEYS. Use BLOCK_TMP as + temporary storage. This macro increments `round'. */ +#define ROUND_INVERSE(which, subkey, block, block_tmp) \ + { \ + LINEAR_TRANSFORMATION_INVERSE (block); \ + SBOX_INVERSE (which, block, block_tmp, 0); \ + BLOCK_XOR (block_tmp, subkey[round]); \ + round--; \ + BLOCK_COPY (block, block_tmp); \ + } + +/* Apply the first Serpent round to BLOCK, using the SBOX number WHICH + and the subkeys contained in SUBKEYS. Use BLOCK_TMP as temporary + storage. The result will be stored in BLOCK_TMP. This macro + increments `round'. */ +#define ROUND_FIRST_INVERSE(which, subkeys, block, block_tmp) \ + { \ + BLOCK_XOR (block, subkeys[round]); \ + round--; \ + SBOX_INVERSE (which, block, block_tmp, 0); \ + BLOCK_XOR (block_tmp, subkeys[round]); \ + round--; \ + } + +/* Convert the user provided key KEY of KEY_LENGTH bytes into the + internally used format. */ +static void +serpent_key_prepare (const byte *key, unsigned int key_length, + serpent_key_t key_prepared) +{ + int i; + + /* Copy key. */ + for (i = 0; i < key_length / 4; i++) + { +#ifdef WORDS_BIGENDIAN + key_prepared[i] = byte_swap_32 (((u32 *) key)[i]); +#else + key_prepared[i] = ((u32 *) key)[i]; +#endif + } + + if (i < 8) + { + /* Key must be padded according to the Serpent + specification. */ + key_prepared[i] = 0x00000001; + + for (i++; i < 8; i++) + key_prepared[i] = 0; + } +} + +/* Derive the 33 subkeys from KEY and store them in SUBKEYS. */ +static void +serpent_subkeys_generate (serpent_key_t key, serpent_subkeys_t subkeys) +{ + u32 w_real[140]; /* The `prekey'. */ + u32 k[132]; + u32 *w = &w_real[8]; + int i, j; + + /* Initialize with key values. */ + for (i = 0; i < 8; i++) + w[i - 8] = key[i]; + + /* Expand to intermediate key using the affine recurrence. */ + for (i = 0; i < 132; i++) + w[i] = rol (w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11); + + /* Calculate subkeys via S-Boxes, in bitslice mode. */ + SBOX (3, w, k, 0); + SBOX (2, w, k, 4); + SBOX (1, w, k, 8); + SBOX (0, w, k, 12); + SBOX (7, w, k, 16); + SBOX (6, w, k, 20); + SBOX (5, w, k, 24); + SBOX (4, w, k, 28); + SBOX (3, w, k, 32); + SBOX (2, w, k, 36); + SBOX (1, w, k, 40); + SBOX (0, w, k, 44); + SBOX (7, w, k, 48); + SBOX (6, w, k, 52); + SBOX (5, w, k, 56); + SBOX (4, w, k, 60); + SBOX (3, w, k, 64); + SBOX (2, w, k, 68); + SBOX (1, w, k, 72); + SBOX (0, w, k, 76); + SBOX (7, w, k, 80); + SBOX (6, w, k, 84); + SBOX (5, w, k, 88); + SBOX (4, w, k, 92); + SBOX (3, w, k, 96); + SBOX (2, w, k, 100); + SBOX (1, w, k, 104); + SBOX (0, w, k, 108); + SBOX (7, w, k, 112); + SBOX (6, w, k, 116); + SBOX (5, w, k, 120); + SBOX (4, w, k, 124); + SBOX (3, w, k, 128); + + /* Renumber subkeys. */ + for (i = 0; i < ROUNDS + 1; i++) + for (j = 0; j < 4; j++) + subkeys[i][j] = k[4 * i + j]; +} + +/* Initialize CONTEXT with the key KEY of KEY_LENGTH bits. */ +static void +serpent_setkey_internal (serpent_context_t *context, + const byte *key, unsigned int key_length) +{ + serpent_key_t key_prepared; + + serpent_key_prepare (key, key_length, key_prepared); + serpent_subkeys_generate (key_prepared, context->keys); + _gcry_burn_stack (272 * sizeof (u32)); +} + +/* Initialize CTX with the key KEY of KEY_LENGTH bytes. */ +static gcry_err_code_t +serpent_setkey (void *ctx, + const byte *key, unsigned int key_length) +{ + serpent_context_t *context = ctx; + static const char *serpent_test_ret; + static int serpent_init_done; + gcry_err_code_t ret = GPG_ERR_NO_ERROR; + + if (! serpent_init_done) + { + /* Execute a self-test the first time, Serpent is used. */ + serpent_test_ret = serpent_test (); + if (serpent_test_ret) + log_error ("Serpent test failure: %s\n", serpent_test_ret); + serpent_init_done = 1; + } + + if (serpent_test_ret) + ret = GPG_ERR_SELFTEST_FAILED; + else + { + serpent_setkey_internal (context, key, key_length); + _gcry_burn_stack (sizeof (serpent_key_t)); + } + + return ret; +} + +static void +serpent_encrypt_internal (serpent_context_t *context, + const serpent_block_t input, serpent_block_t output) +{ + serpent_block_t b, b_next; + int round = 0; + +#ifdef WORDS_BIGENDIAN + b[0] = byte_swap_32 (input[0]); + b[1] = byte_swap_32 (input[1]); + b[2] = byte_swap_32 (input[2]); + b[3] = byte_swap_32 (input[3]); +#else + b[0] = input[0]; + b[1] = input[1]; + b[2] = input[2]; + b[3] = input[3]; +#endif + + ROUND (0, context->keys, b, b_next); + ROUND (1, context->keys, b, b_next); + ROUND (2, context->keys, b, b_next); + ROUND (3, context->keys, b, b_next); + ROUND (4, context->keys, b, b_next); + ROUND (5, context->keys, b, b_next); + ROUND (6, context->keys, b, b_next); + ROUND (7, context->keys, b, b_next); + ROUND (0, context->keys, b, b_next); + ROUND (1, context->keys, b, b_next); + ROUND (2, context->keys, b, b_next); + ROUND (3, context->keys, b, b_next); + ROUND (4, context->keys, b, b_next); + ROUND (5, context->keys, b, b_next); + ROUND (6, context->keys, b, b_next); + ROUND (7, context->keys, b, b_next); + ROUND (0, context->keys, b, b_next); + ROUND (1, context->keys, b, b_next); + ROUND (2, context->keys, b, b_next); + ROUND (3, context->keys, b, b_next); + ROUND (4, context->keys, b, b_next); + ROUND (5, context->keys, b, b_next); + ROUND (6, context->keys, b, b_next); + ROUND (7, context->keys, b, b_next); + ROUND (0, context->keys, b, b_next); + ROUND (1, context->keys, b, b_next); + ROUND (2, context->keys, b, b_next); + ROUND (3, context->keys, b, b_next); + ROUND (4, context->keys, b, b_next); + ROUND (5, context->keys, b, b_next); + ROUND (6, context->keys, b, b_next); + + ROUND_LAST (7, context->keys, b, b_next); + +#ifdef WORDS_BIGENDIAN + output[0] = byte_swap_32 (b_next[0]); + output[1] = byte_swap_32 (b_next[1]); + output[2] = byte_swap_32 (b_next[2]); + output[3] = byte_swap_32 (b_next[3]); +#else + output[0] = b_next[0]; + output[1] = b_next[1]; + output[2] = b_next[2]; + output[3] = b_next[3]; +#endif +} + +static void +serpent_decrypt_internal (serpent_context_t *context, + const serpent_block_t input, serpent_block_t output) +{ + serpent_block_t b, b_next; + int round = ROUNDS; + +#ifdef WORDS_BIGENDIAN + b_next[0] = byte_swap_32 (input[0]); + b_next[1] = byte_swap_32 (input[1]); + b_next[2] = byte_swap_32 (input[2]); + b_next[3] = byte_swap_32 (input[3]); +#else + b_next[0] = input[0]; + b_next[1] = input[1]; + b_next[2] = input[2]; + b_next[3] = input[3]; +#endif + + ROUND_FIRST_INVERSE (7, context->keys, b_next, b); + + ROUND_INVERSE (6, context->keys, b, b_next); + ROUND_INVERSE (5, context->keys, b, b_next); + ROUND_INVERSE (4, context->keys, b, b_next); + ROUND_INVERSE (3, context->keys, b, b_next); + ROUND_INVERSE (2, context->keys, b, b_next); + ROUND_INVERSE (1, context->keys, b, b_next); + ROUND_INVERSE (0, context->keys, b, b_next); + ROUND_INVERSE (7, context->keys, b, b_next); + ROUND_INVERSE (6, context->keys, b, b_next); + ROUND_INVERSE (5, context->keys, b, b_next); + ROUND_INVERSE (4, context->keys, b, b_next); + ROUND_INVERSE (3, context->keys, b, b_next); + ROUND_INVERSE (2, context->keys, b, b_next); + ROUND_INVERSE (1, context->keys, b, b_next); + ROUND_INVERSE (0, context->keys, b, b_next); + ROUND_INVERSE (7, context->keys, b, b_next); + ROUND_INVERSE (6, context->keys, b, b_next); + ROUND_INVERSE (5, context->keys, b, b_next); + ROUND_INVERSE (4, context->keys, b, b_next); + ROUND_INVERSE (3, context->keys, b, b_next); + ROUND_INVERSE (2, context->keys, b, b_next); + ROUND_INVERSE (1, context->keys, b, b_next); + ROUND_INVERSE (0, context->keys, b, b_next); + ROUND_INVERSE (7, context->keys, b, b_next); + ROUND_INVERSE (6, context->keys, b, b_next); + ROUND_INVERSE (5, context->keys, b, b_next); + ROUND_INVERSE (4, context->keys, b, b_next); + ROUND_INVERSE (3, context->keys, b, b_next); + ROUND_INVERSE (2, context->keys, b, b_next); + ROUND_INVERSE (1, context->keys, b, b_next); + ROUND_INVERSE (0, context->keys, b, b_next); + + +#ifdef WORDS_BIGENDIAN + output[0] = byte_swap_32 (b_next[0]); + output[1] = byte_swap_32 (b_next[1]); + output[2] = byte_swap_32 (b_next[2]); + output[3] = byte_swap_32 (b_next[3]); +#else + output[0] = b_next[0]; + output[1] = b_next[1]; + output[2] = b_next[2]; + output[3] = b_next[3]; +#endif +} + +static void +serpent_encrypt (void *ctx, byte *buffer_out, const byte *buffer_in) +{ + serpent_context_t *context = ctx; + + serpent_encrypt_internal (context, + (const u32 *) buffer_in, (u32 *) buffer_out); + _gcry_burn_stack (2 * sizeof (serpent_block_t)); +} + +static void +serpent_decrypt (void *ctx, byte *buffer_out, const byte *buffer_in) +{ + serpent_context_t *context = ctx; + + serpent_decrypt_internal (context, + (const u32 *) buffer_in, + (u32 *) buffer_out); + _gcry_burn_stack (2 * sizeof (serpent_block_t)); +} + + + +/* Serpent test. */ + +static const char * +serpent_test (void) +{ + serpent_context_t context; + unsigned char scratch[16]; + unsigned int i; + + static struct test + { + int key_length; + unsigned char key[32]; + unsigned char text_plain[16]; + unsigned char text_cipher[16]; + } test_data[] = + { + { + 16, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\xD2\x9D\x57\x6F\xCE\xA3\xA3\xA7\xED\x90\x99\xF2\x92\x73\xD7\x8E", + "\xB2\x28\x8B\x96\x8A\xE8\xB0\x86\x48\xD1\xCE\x96\x06\xFD\x99\x2D" + }, + { + 24, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + "\xD2\x9D\x57\x6F\xCE\xAB\xA3\xA7\xED\x98\x99\xF2\x92\x7B\xD7\x8E", + "\x13\x0E\x35\x3E\x10\x37\xC2\x24\x05\xE8\xFA\xEF\xB2\xC3\xC3\xE9" + }, + { + 32, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\xD0\x95\x57\x6F\xCE\xA3\xE3\xA7\xED\x98\xD9\xF2\x90\x73\xD7\x8E", + "\xB9\x0E\xE5\x86\x2D\xE6\x91\x68\xF2\xBD\xD5\x12\x5B\x45\x47\x2B" + }, + { + 32, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00", + "\x20\x61\xA4\x27\x82\xBD\x52\xEC\x69\x1E\xC3\x83\xB0\x3B\xA7\x7C" + }, + { + 0 + }, + }; + + for (i = 0; test_data[i].key_length; i++) + { + serpent_setkey_internal (&context, test_data[i].key, + test_data[i].key_length); + serpent_encrypt_internal (&context, + (const u32 *) test_data[i].text_plain, + (u32 *) scratch); + + if (memcmp (scratch, test_data[i].text_cipher, sizeof (serpent_block_t))) + switch (test_data[i].key_length) + { + case 16: + return "Serpent-128 test encryption failed."; + case 24: + return "Serpent-192 test encryption failed."; + case 32: + return "Serpent-256 test encryption failed."; + } + + serpent_decrypt_internal (&context, + (const u32 *) test_data[i].text_cipher, + (u32 *) scratch); + if (memcmp (scratch, test_data[i].text_plain, sizeof (serpent_block_t))) + switch (test_data[i].key_length) + { + case 16: + return "Serpent-128 test decryption failed."; + case 24: + return "Serpent-192 test decryption failed."; + case 32: + return "Serpent-256 test decryption failed."; + } + } + + return NULL; +} + + + +/* "SERPENT" is an alias for "SERPENT128". */ +static const char *cipher_spec_serpent128_aliases[] = + { + "SERPENT", + NULL + }; + +gcry_cipher_spec_t _gcry_cipher_spec_serpent128 = + { + "SERPENT128", cipher_spec_serpent128_aliases, NULL, 16, 128, + sizeof (serpent_context_t), + serpent_setkey, serpent_encrypt, serpent_decrypt + }; + +gcry_cipher_spec_t _gcry_cipher_spec_serpent192 = + { + "SERPENT192", NULL, NULL, 16, 192, + sizeof (serpent_context_t), + serpent_setkey, serpent_encrypt, serpent_decrypt + }; + +gcry_cipher_spec_t _gcry_cipher_spec_serpent256 = + { + "SERPENT256", NULL, NULL, 16, 256, + sizeof (serpent_context_t), + serpent_setkey, serpent_encrypt, serpent_decrypt + }; diff --git a/libgcrypt-1.4.6/cipher/sha512.c b/libgcrypt-1.4.6/cipher/sha512.c index 59c3e65..43878ef 100644 --- a/libgcrypt-1.4.6/cipher/sha512.c +++ b/libgcrypt-1.4.6/cipher/sha512.c @@ -1,629 +1,629 @@ -/* sha512.c - SHA384 and SHA512 hash functions - * Copyright (C) 2003, 2008, 2009 Free Software Foundation, Inc. - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser general Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see . - */ - - -/* Test vectors from FIPS-180-2: - * - * "abc" - * 384: - * CB00753F 45A35E8B B5A03D69 9AC65007 272C32AB 0EDED163 - * 1A8B605A 43FF5BED 8086072B A1E7CC23 58BAECA1 34C825A7 - * 512: - * DDAF35A1 93617ABA CC417349 AE204131 12E6FA4E 89A97EA2 0A9EEEE6 4B55D39A - * 2192992A 274FC1A8 36BA3C23 A3FEEBBD 454D4423 643CE80E 2A9AC94F A54CA49F - * - * "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" - * 384: - * 09330C33 F71147E8 3D192FC7 82CD1B47 53111B17 3B3B05D2 - * 2FA08086 E3B0F712 FCC7C71A 557E2DB9 66C3E9FA 91746039 - * 512: - * 8E959B75 DAE313DA 8CF4F728 14FC143F 8F7779C6 EB9F7FA1 7299AEAD B6889018 - * 501D289E 4900F7E4 331B99DE C4B5433A C7D329EE B6DD2654 5E96E55B 874BE909 - * - * "a" x 1000000 - * 384: - * 9D0E1809 716474CB 086E834E 310A4A1C ED149E9C 00F24852 - * 7972CEC5 704C2A5B 07B8B3DC 38ECC4EB AE97DDD8 7F3D8985 - * 512: - * E718483D 0CE76964 4E2E42C7 BC15B463 8E1F98B1 3B204428 5632A803 AFA973EB - * DE0FF244 877EA60A 4CB0432C E577C31B EB009C5C 2C49AA2E 4EADB217 AD8CC09B - */ - - -#include -#include -#include "g10lib.h" -#include "bithelp.h" -#include "cipher.h" -#include "hash-common.h" - -typedef struct -{ - u64 h0, h1, h2, h3, h4, h5, h6, h7; - u64 nblocks; - byte buf[128]; - int count; -} SHA512_CONTEXT; - -static void -sha512_init (void *context) -{ - SHA512_CONTEXT *hd = context; - - hd->h0 = U64_C(0x6a09e667f3bcc908); - hd->h1 = U64_C(0xbb67ae8584caa73b); - hd->h2 = U64_C(0x3c6ef372fe94f82b); - hd->h3 = U64_C(0xa54ff53a5f1d36f1); - hd->h4 = U64_C(0x510e527fade682d1); - hd->h5 = U64_C(0x9b05688c2b3e6c1f); - hd->h6 = U64_C(0x1f83d9abfb41bd6b); - hd->h7 = U64_C(0x5be0cd19137e2179); - - hd->nblocks = 0; - hd->count = 0; -} - -static void -sha384_init (void *context) -{ - SHA512_CONTEXT *hd = context; - - hd->h0 = U64_C(0xcbbb9d5dc1059ed8); - hd->h1 = U64_C(0x629a292a367cd507); - hd->h2 = U64_C(0x9159015a3070dd17); - hd->h3 = U64_C(0x152fecd8f70e5939); - hd->h4 = U64_C(0x67332667ffc00b31); - hd->h5 = U64_C(0x8eb44a8768581511); - hd->h6 = U64_C(0xdb0c2e0d64f98fa7); - hd->h7 = U64_C(0x47b5481dbefa4fa4); - - hd->nblocks = 0; - hd->count = 0; -} - - -static inline u64 -ROTR (u64 x, u64 n) -{ - return ((x >> n) | (x << (64 - n))); -} - -static inline u64 -Ch (u64 x, u64 y, u64 z) -{ - return ((x & y) ^ ( ~x & z)); -} - -static inline u64 -Maj (u64 x, u64 y, u64 z) -{ - return ((x & y) ^ (x & z) ^ (y & z)); -} - -static inline u64 -Sum0 (u64 x) -{ - return (ROTR (x, 28) ^ ROTR (x, 34) ^ ROTR (x, 39)); -} - -static inline u64 -Sum1 (u64 x) -{ - return (ROTR (x, 14) ^ ROTR (x, 18) ^ ROTR (x, 41)); -} - -/**************** - * Transform the message W which consists of 16 64-bit-words - */ -static void -transform (SHA512_CONTEXT *hd, const unsigned char *data) -{ - u64 a, b, c, d, e, f, g, h; - u64 w[80]; - int t; - static const u64 k[] = - { - U64_C(0x428a2f98d728ae22), U64_C(0x7137449123ef65cd), - U64_C(0xb5c0fbcfec4d3b2f), U64_C(0xe9b5dba58189dbbc), - U64_C(0x3956c25bf348b538), U64_C(0x59f111f1b605d019), - U64_C(0x923f82a4af194f9b), U64_C(0xab1c5ed5da6d8118), - U64_C(0xd807aa98a3030242), U64_C(0x12835b0145706fbe), - U64_C(0x243185be4ee4b28c), U64_C(0x550c7dc3d5ffb4e2), - U64_C(0x72be5d74f27b896f), U64_C(0x80deb1fe3b1696b1), - U64_C(0x9bdc06a725c71235), U64_C(0xc19bf174cf692694), - U64_C(0xe49b69c19ef14ad2), U64_C(0xefbe4786384f25e3), - U64_C(0x0fc19dc68b8cd5b5), U64_C(0x240ca1cc77ac9c65), - U64_C(0x2de92c6f592b0275), U64_C(0x4a7484aa6ea6e483), - U64_C(0x5cb0a9dcbd41fbd4), U64_C(0x76f988da831153b5), - U64_C(0x983e5152ee66dfab), U64_C(0xa831c66d2db43210), - U64_C(0xb00327c898fb213f), U64_C(0xbf597fc7beef0ee4), - U64_C(0xc6e00bf33da88fc2), U64_C(0xd5a79147930aa725), - U64_C(0x06ca6351e003826f), U64_C(0x142929670a0e6e70), - U64_C(0x27b70a8546d22ffc), U64_C(0x2e1b21385c26c926), - U64_C(0x4d2c6dfc5ac42aed), U64_C(0x53380d139d95b3df), - U64_C(0x650a73548baf63de), U64_C(0x766a0abb3c77b2a8), - U64_C(0x81c2c92e47edaee6), U64_C(0x92722c851482353b), - U64_C(0xa2bfe8a14cf10364), U64_C(0xa81a664bbc423001), - U64_C(0xc24b8b70d0f89791), U64_C(0xc76c51a30654be30), - U64_C(0xd192e819d6ef5218), U64_C(0xd69906245565a910), - U64_C(0xf40e35855771202a), U64_C(0x106aa07032bbd1b8), - U64_C(0x19a4c116b8d2d0c8), U64_C(0x1e376c085141ab53), - U64_C(0x2748774cdf8eeb99), U64_C(0x34b0bcb5e19b48a8), - U64_C(0x391c0cb3c5c95a63), U64_C(0x4ed8aa4ae3418acb), - U64_C(0x5b9cca4f7763e373), U64_C(0x682e6ff3d6b2b8a3), - U64_C(0x748f82ee5defb2fc), U64_C(0x78a5636f43172f60), - U64_C(0x84c87814a1f0ab72), U64_C(0x8cc702081a6439ec), - U64_C(0x90befffa23631e28), U64_C(0xa4506cebde82bde9), - U64_C(0xbef9a3f7b2c67915), U64_C(0xc67178f2e372532b), - U64_C(0xca273eceea26619c), U64_C(0xd186b8c721c0c207), - U64_C(0xeada7dd6cde0eb1e), U64_C(0xf57d4f7fee6ed178), - U64_C(0x06f067aa72176fba), U64_C(0x0a637dc5a2c898a6), - U64_C(0x113f9804bef90dae), U64_C(0x1b710b35131c471b), - U64_C(0x28db77f523047d84), U64_C(0x32caab7b40c72493), - U64_C(0x3c9ebe0a15c9bebc), U64_C(0x431d67c49c100d4c), - U64_C(0x4cc5d4becb3e42b6), U64_C(0x597f299cfc657e2a), - U64_C(0x5fcb6fab3ad6faec), U64_C(0x6c44198c4a475817) - }; - - /* get values from the chaining vars */ - a = hd->h0; - b = hd->h1; - c = hd->h2; - d = hd->h3; - e = hd->h4; - f = hd->h5; - g = hd->h6; - h = hd->h7; - -#ifdef WORDS_BIGENDIAN - memcpy (w, data, 128); -#else - { - int i; - byte *p2; - - for (i = 0, p2 = (byte *) w; i < 16; i++, p2 += 8) - { - p2[7] = *data++; - p2[6] = *data++; - p2[5] = *data++; - p2[4] = *data++; - p2[3] = *data++; - p2[2] = *data++; - p2[1] = *data++; - p2[0] = *data++; - } - } -#endif - -#define S0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7)) -#define S1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6)) - - for (t = 16; t < 80; t++) - w[t] = S1 (w[t - 2]) + w[t - 7] + S0 (w[t - 15]) + w[t - 16]; - - - for (t = 0; t < 80; ) - { - u64 t1, t2; - - /* Performance on a AMD Athlon(tm) Dual Core Processor 4050e - with gcc 4.3.3 using gcry_md_hash_buffer of each 10000 bytes - initialized to 0,1,2,3...255,0,... and 1000 iterations: - - Not unrolled with macros: 440ms - Unrolled with macros: 350ms - Unrolled with inline: 330ms - */ -#if 0 /* Not unrolled. */ - t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; - t2 = Sum0 (a) + Maj (a, b, c); - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - t++; -#else /* Unrolled to interweave the chain variables. */ - t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; - t2 = Sum0 (a) + Maj (a, b, c); - d += t1; - h = t1 + t2; - - t1 = g + Sum1 (d) + Ch (d, e, f) + k[t+1] + w[t+1]; - t2 = Sum0 (h) + Maj (h, a, b); - c += t1; - g = t1 + t2; - - t1 = f + Sum1 (c) + Ch (c, d, e) + k[t+2] + w[t+2]; - t2 = Sum0 (g) + Maj (g, h, a); - b += t1; - f = t1 + t2; - - t1 = e + Sum1 (b) + Ch (b, c, d) + k[t+3] + w[t+3]; - t2 = Sum0 (f) + Maj (f, g, h); - a += t1; - e = t1 + t2; - - t1 = d + Sum1 (a) + Ch (a, b, c) + k[t+4] + w[t+4]; - t2 = Sum0 (e) + Maj (e, f, g); - h += t1; - d = t1 + t2; - - t1 = c + Sum1 (h) + Ch (h, a, b) + k[t+5] + w[t+5]; - t2 = Sum0 (d) + Maj (d, e, f); - g += t1; - c = t1 + t2; - - t1 = b + Sum1 (g) + Ch (g, h, a) + k[t+6] + w[t+6]; - t2 = Sum0 (c) + Maj (c, d, e); - f += t1; - b = t1 + t2; - - t1 = a + Sum1 (f) + Ch (f, g, h) + k[t+7] + w[t+7]; - t2 = Sum0 (b) + Maj (b, c, d); - e += t1; - a = t1 + t2; - - t += 8; -#endif - } - - /* Update chaining vars. */ - hd->h0 += a; - hd->h1 += b; - hd->h2 += c; - hd->h3 += d; - hd->h4 += e; - hd->h5 += f; - hd->h6 += g; - hd->h7 += h; -} - - -/* Update the message digest with the contents - * of INBUF with length INLEN. - */ -static void -sha512_write (void *context, const void *inbuf_arg, size_t inlen) -{ - const unsigned char *inbuf = inbuf_arg; - SHA512_CONTEXT *hd = context; - - if (hd->count == 128) - { /* flush the buffer */ - transform (hd, hd->buf); - _gcry_burn_stack (768); - hd->count = 0; - hd->nblocks++; - } - if (!inbuf) - return; - if (hd->count) - { - for (; inlen && hd->count < 128; inlen--) - hd->buf[hd->count++] = *inbuf++; - sha512_write (context, NULL, 0); - if (!inlen) - return; - } - - while (inlen >= 128) - { - transform (hd, inbuf); - hd->count = 0; - hd->nblocks++; - inlen -= 128; - inbuf += 128; - } - _gcry_burn_stack (768); - for (; inlen && hd->count < 128; inlen--) - hd->buf[hd->count++] = *inbuf++; -} - - -/* The routine final terminates the computation and - * returns the digest. - * The handle is prepared for a new cycle, but adding bytes to the - * handle will the destroy the returned buffer. - * Returns: 64 bytes representing the digest. When used for sha384, - * we take the leftmost 48 of those bytes. - */ - -static void -sha512_final (void *context) -{ - SHA512_CONTEXT *hd = context; - u64 t, msb, lsb; - byte *p; - - sha512_write (context, NULL, 0); /* flush */ ; - - t = hd->nblocks; - /* multiply by 128 to make a byte count */ - lsb = t << 7; - msb = t >> 57; - /* add the count */ - t = lsb; - if ((lsb += hd->count) < t) - msb++; - /* multiply by 8 to make a bit count */ - t = lsb; - lsb <<= 3; - msb <<= 3; - msb |= t >> 61; - - if (hd->count < 112) - { /* enough room */ - hd->buf[hd->count++] = 0x80; /* pad */ - while (hd->count < 112) - hd->buf[hd->count++] = 0; /* pad */ - } - else - { /* need one extra block */ - hd->buf[hd->count++] = 0x80; /* pad character */ - while (hd->count < 128) - hd->buf[hd->count++] = 0; - sha512_write (context, NULL, 0); /* flush */ ; - memset (hd->buf, 0, 112); /* fill next block with zeroes */ - } - /* append the 128 bit count */ - hd->buf[112] = msb >> 56; - hd->buf[113] = msb >> 48; - hd->buf[114] = msb >> 40; - hd->buf[115] = msb >> 32; - hd->buf[116] = msb >> 24; - hd->buf[117] = msb >> 16; - hd->buf[118] = msb >> 8; - hd->buf[119] = msb; - - hd->buf[120] = lsb >> 56; - hd->buf[121] = lsb >> 48; - hd->buf[122] = lsb >> 40; - hd->buf[123] = lsb >> 32; - hd->buf[124] = lsb >> 24; - hd->buf[125] = lsb >> 16; - hd->buf[126] = lsb >> 8; - hd->buf[127] = lsb; - transform (hd, hd->buf); - _gcry_burn_stack (768); - - p = hd->buf; -#ifdef WORDS_BIGENDIAN -#define X(a) do { *(u64*)p = hd->h##a ; p += 8; } while (0) -#else /* little endian */ -#define X(a) do { *p++ = hd->h##a >> 56; *p++ = hd->h##a >> 48; \ - *p++ = hd->h##a >> 40; *p++ = hd->h##a >> 32; \ - *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ - *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while (0) -#endif - X (0); - X (1); - X (2); - X (3); - X (4); - X (5); - /* Note that these last two chunks are included even for SHA384. - We just ignore them. */ - X (6); - X (7); -#undef X -} - -static byte * -sha512_read (void *context) -{ - SHA512_CONTEXT *hd = (SHA512_CONTEXT *) context; - return hd->buf; -} - - - -/* - Self-test section. - */ - - -static gpg_err_code_t -selftests_sha384 (int extended, selftest_report_func_t report) -{ - const char *what; - const char *errtxt; - - what = "short string"; - errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA384, 0, - "abc", 3, - "\xcb\x00\x75\x3f\x45\xa3\x5e\x8b\xb5\xa0\x3d\x69\x9a\xc6\x50\x07" - "\x27\x2c\x32\xab\x0e\xde\xd1\x63\x1a\x8b\x60\x5a\x43\xff\x5b\xed" - "\x80\x86\x07\x2b\xa1\xe7\xcc\x23\x58\xba\xec\xa1\x34\xc8\x25\xa7", 48); - if (errtxt) - goto failed; - - if (extended) - { - what = "long string"; - errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA384, 0, - "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" - "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, - "\x09\x33\x0C\x33\xF7\x11\x47\xE8\x3D\x19\x2F\xC7\x82\xCD\x1B\x47" - "\x53\x11\x1B\x17\x3B\x3B\x05\xD2\x2F\xA0\x80\x86\xE3\xB0\xF7\x12" - "\xFC\xC7\xC7\x1A\x55\x7E\x2D\xB9\x66\xC3\xE9\xFA\x91\x74\x60\x39", - 48); - if (errtxt) - goto failed; - - what = "one million \"a\""; - errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA384, 1, - NULL, 0, - "\x9D\x0E\x18\x09\x71\x64\x74\xCB\x08\x6E\x83\x4E\x31\x0A\x4A\x1C" - "\xED\x14\x9E\x9C\x00\xF2\x48\x52\x79\x72\xCE\xC5\x70\x4C\x2A\x5B" - "\x07\xB8\xB3\xDC\x38\xEC\xC4\xEB\xAE\x97\xDD\xD8\x7F\x3D\x89\x85", - 48); - if (errtxt) - goto failed; - } - - return 0; /* Succeeded. */ - - failed: - if (report) - report ("digest", GCRY_MD_SHA384, what, errtxt); - return GPG_ERR_SELFTEST_FAILED; -} - -static gpg_err_code_t -selftests_sha512 (int extended, selftest_report_func_t report) -{ - const char *what; - const char *errtxt; - - what = "short string"; - errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA512, 0, - "abc", 3, - "\xDD\xAF\x35\xA1\x93\x61\x7A\xBA\xCC\x41\x73\x49\xAE\x20\x41\x31" - "\x12\xE6\xFA\x4E\x89\xA9\x7E\xA2\x0A\x9E\xEE\xE6\x4B\x55\xD3\x9A" - "\x21\x92\x99\x2A\x27\x4F\xC1\xA8\x36\xBA\x3C\x23\xA3\xFE\xEB\xBD" - "\x45\x4D\x44\x23\x64\x3C\xE8\x0E\x2A\x9A\xC9\x4F\xA5\x4C\xA4\x9F", 64); - if (errtxt) - goto failed; - - if (extended) - { - what = "long string"; - errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA512, 0, - "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" - "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, - "\x8E\x95\x9B\x75\xDA\xE3\x13\xDA\x8C\xF4\xF7\x28\x14\xFC\x14\x3F" - "\x8F\x77\x79\xC6\xEB\x9F\x7F\xA1\x72\x99\xAE\xAD\xB6\x88\x90\x18" - "\x50\x1D\x28\x9E\x49\x00\xF7\xE4\x33\x1B\x99\xDE\xC4\xB5\x43\x3A" - "\xC7\xD3\x29\xEE\xB6\xDD\x26\x54\x5E\x96\xE5\x5B\x87\x4B\xE9\x09", - 64); - if (errtxt) - goto failed; - - what = "one million \"a\""; - errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA512, 1, - NULL, 0, - "\xE7\x18\x48\x3D\x0C\xE7\x69\x64\x4E\x2E\x42\xC7\xBC\x15\xB4\x63" - "\x8E\x1F\x98\xB1\x3B\x20\x44\x28\x56\x32\xA8\x03\xAF\xA9\x73\xEB" - "\xDE\x0F\xF2\x44\x87\x7E\xA6\x0A\x4C\xB0\x43\x2C\xE5\x77\xC3\x1B" - "\xEB\x00\x9C\x5C\x2C\x49\xAA\x2E\x4E\xAD\xB2\x17\xAD\x8C\xC0\x9B", - 64); - if (errtxt) - goto failed; - } - - return 0; /* Succeeded. */ - - failed: - if (report) - report ("digest", GCRY_MD_SHA512, what, errtxt); - return GPG_ERR_SELFTEST_FAILED; -} - - -/* Run a full self-test for ALGO and return 0 on success. */ -static gpg_err_code_t -run_selftests (int algo, int extended, selftest_report_func_t report) -{ - gpg_err_code_t ec; - - switch (algo) - { - case GCRY_MD_SHA384: - ec = selftests_sha384 (extended, report); - break; - case GCRY_MD_SHA512: - ec = selftests_sha512 (extended, report); - break; - default: - ec = GPG_ERR_DIGEST_ALGO; - break; - - } - return ec; -} - - - - -static byte sha512_asn[] = /* Object ID is 2.16.840.1.101.3.4.2.3 */ - { - 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, - 0x00, 0x04, 0x40 - }; - -static gcry_md_oid_spec_t oid_spec_sha512[] = - { - { "2.16.840.1.101.3.4.2.3" }, - - /* PKCS#1 sha512WithRSAEncryption */ - { "1.2.840.113549.1.1.13" }, - - { NULL } - }; - -gcry_md_spec_t _gcry_digest_spec_sha512 = - { - "SHA512", sha512_asn, DIM (sha512_asn), oid_spec_sha512, 64, - sha512_init, sha512_write, sha512_final, sha512_read, - sizeof (SHA512_CONTEXT), - }; -md_extra_spec_t _gcry_digest_extraspec_sha512 = - { - run_selftests - }; - -static byte sha384_asn[] = /* Object ID is 2.16.840.1.101.3.4.2.2 */ - { - 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, - 0x00, 0x04, 0x30 - }; - -static gcry_md_oid_spec_t oid_spec_sha384[] = - { - { "2.16.840.1.101.3.4.2.2" }, - - /* PKCS#1 sha384WithRSAEncryption */ - { "1.2.840.113549.1.1.12" }, - - { NULL }, - }; - -gcry_md_spec_t _gcry_digest_spec_sha384 = - { - "SHA384", sha384_asn, DIM (sha384_asn), oid_spec_sha384, 48, - sha384_init, sha512_write, sha512_final, sha512_read, - sizeof (SHA512_CONTEXT), - }; -md_extra_spec_t _gcry_digest_extraspec_sha384 = - { - run_selftests - }; +/* sha512.c - SHA384 and SHA512 hash functions + * Copyright (C) 2003, 2008, 2009 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + + +/* Test vectors from FIPS-180-2: + * + * "abc" + * 384: + * CB00753F 45A35E8B B5A03D69 9AC65007 272C32AB 0EDED163 + * 1A8B605A 43FF5BED 8086072B A1E7CC23 58BAECA1 34C825A7 + * 512: + * DDAF35A1 93617ABA CC417349 AE204131 12E6FA4E 89A97EA2 0A9EEEE6 4B55D39A + * 2192992A 274FC1A8 36BA3C23 A3FEEBBD 454D4423 643CE80E 2A9AC94F A54CA49F + * + * "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + * 384: + * 09330C33 F71147E8 3D192FC7 82CD1B47 53111B17 3B3B05D2 + * 2FA08086 E3B0F712 FCC7C71A 557E2DB9 66C3E9FA 91746039 + * 512: + * 8E959B75 DAE313DA 8CF4F728 14FC143F 8F7779C6 EB9F7FA1 7299AEAD B6889018 + * 501D289E 4900F7E4 331B99DE C4B5433A C7D329EE B6DD2654 5E96E55B 874BE909 + * + * "a" x 1000000 + * 384: + * 9D0E1809 716474CB 086E834E 310A4A1C ED149E9C 00F24852 + * 7972CEC5 704C2A5B 07B8B3DC 38ECC4EB AE97DDD8 7F3D8985 + * 512: + * E718483D 0CE76964 4E2E42C7 BC15B463 8E1F98B1 3B204428 5632A803 AFA973EB + * DE0FF244 877EA60A 4CB0432C E577C31B EB009C5C 2C49AA2E 4EADB217 AD8CC09B + */ + + +#include +#include +#include "g10lib.h" +#include "bithelp.h" +#include "cipher.h" +#include "hash-common.h" + +typedef struct +{ + u64 h0, h1, h2, h3, h4, h5, h6, h7; + u64 nblocks; + byte buf[128]; + int count; +} SHA512_CONTEXT; + +static void +sha512_init (void *context) +{ + SHA512_CONTEXT *hd = context; + + hd->h0 = U64_C(0x6a09e667f3bcc908); + hd->h1 = U64_C(0xbb67ae8584caa73b); + hd->h2 = U64_C(0x3c6ef372fe94f82b); + hd->h3 = U64_C(0xa54ff53a5f1d36f1); + hd->h4 = U64_C(0x510e527fade682d1); + hd->h5 = U64_C(0x9b05688c2b3e6c1f); + hd->h6 = U64_C(0x1f83d9abfb41bd6b); + hd->h7 = U64_C(0x5be0cd19137e2179); + + hd->nblocks = 0; + hd->count = 0; +} + +static void +sha384_init (void *context) +{ + SHA512_CONTEXT *hd = context; + + hd->h0 = U64_C(0xcbbb9d5dc1059ed8); + hd->h1 = U64_C(0x629a292a367cd507); + hd->h2 = U64_C(0x9159015a3070dd17); + hd->h3 = U64_C(0x152fecd8f70e5939); + hd->h4 = U64_C(0x67332667ffc00b31); + hd->h5 = U64_C(0x8eb44a8768581511); + hd->h6 = U64_C(0xdb0c2e0d64f98fa7); + hd->h7 = U64_C(0x47b5481dbefa4fa4); + + hd->nblocks = 0; + hd->count = 0; +} + + +static inline u64 +ROTR (u64 x, u64 n) +{ + return ((x >> n) | (x << (64 - n))); +} + +static inline u64 +Ch (u64 x, u64 y, u64 z) +{ + return ((x & y) ^ ( ~x & z)); +} + +static inline u64 +Maj (u64 x, u64 y, u64 z) +{ + return ((x & y) ^ (x & z) ^ (y & z)); +} + +static inline u64 +Sum0 (u64 x) +{ + return (ROTR (x, 28) ^ ROTR (x, 34) ^ ROTR (x, 39)); +} + +static inline u64 +Sum1 (u64 x) +{ + return (ROTR (x, 14) ^ ROTR (x, 18) ^ ROTR (x, 41)); +} + +/**************** + * Transform the message W which consists of 16 64-bit-words + */ +static void +transform (SHA512_CONTEXT *hd, const unsigned char *data) +{ + u64 a, b, c, d, e, f, g, h; + u64 w[80]; + int t; + static const u64 k[] = + { + U64_C(0x428a2f98d728ae22), U64_C(0x7137449123ef65cd), + U64_C(0xb5c0fbcfec4d3b2f), U64_C(0xe9b5dba58189dbbc), + U64_C(0x3956c25bf348b538), U64_C(0x59f111f1b605d019), + U64_C(0x923f82a4af194f9b), U64_C(0xab1c5ed5da6d8118), + U64_C(0xd807aa98a3030242), U64_C(0x12835b0145706fbe), + U64_C(0x243185be4ee4b28c), U64_C(0x550c7dc3d5ffb4e2), + U64_C(0x72be5d74f27b896f), U64_C(0x80deb1fe3b1696b1), + U64_C(0x9bdc06a725c71235), U64_C(0xc19bf174cf692694), + U64_C(0xe49b69c19ef14ad2), U64_C(0xefbe4786384f25e3), + U64_C(0x0fc19dc68b8cd5b5), U64_C(0x240ca1cc77ac9c65), + U64_C(0x2de92c6f592b0275), U64_C(0x4a7484aa6ea6e483), + U64_C(0x5cb0a9dcbd41fbd4), U64_C(0x76f988da831153b5), + U64_C(0x983e5152ee66dfab), U64_C(0xa831c66d2db43210), + U64_C(0xb00327c898fb213f), U64_C(0xbf597fc7beef0ee4), + U64_C(0xc6e00bf33da88fc2), U64_C(0xd5a79147930aa725), + U64_C(0x06ca6351e003826f), U64_C(0x142929670a0e6e70), + U64_C(0x27b70a8546d22ffc), U64_C(0x2e1b21385c26c926), + U64_C(0x4d2c6dfc5ac42aed), U64_C(0x53380d139d95b3df), + U64_C(0x650a73548baf63de), U64_C(0x766a0abb3c77b2a8), + U64_C(0x81c2c92e47edaee6), U64_C(0x92722c851482353b), + U64_C(0xa2bfe8a14cf10364), U64_C(0xa81a664bbc423001), + U64_C(0xc24b8b70d0f89791), U64_C(0xc76c51a30654be30), + U64_C(0xd192e819d6ef5218), U64_C(0xd69906245565a910), + U64_C(0xf40e35855771202a), U64_C(0x106aa07032bbd1b8), + U64_C(0x19a4c116b8d2d0c8), U64_C(0x1e376c085141ab53), + U64_C(0x2748774cdf8eeb99), U64_C(0x34b0bcb5e19b48a8), + U64_C(0x391c0cb3c5c95a63), U64_C(0x4ed8aa4ae3418acb), + U64_C(0x5b9cca4f7763e373), U64_C(0x682e6ff3d6b2b8a3), + U64_C(0x748f82ee5defb2fc), U64_C(0x78a5636f43172f60), + U64_C(0x84c87814a1f0ab72), U64_C(0x8cc702081a6439ec), + U64_C(0x90befffa23631e28), U64_C(0xa4506cebde82bde9), + U64_C(0xbef9a3f7b2c67915), U64_C(0xc67178f2e372532b), + U64_C(0xca273eceea26619c), U64_C(0xd186b8c721c0c207), + U64_C(0xeada7dd6cde0eb1e), U64_C(0xf57d4f7fee6ed178), + U64_C(0x06f067aa72176fba), U64_C(0x0a637dc5a2c898a6), + U64_C(0x113f9804bef90dae), U64_C(0x1b710b35131c471b), + U64_C(0x28db77f523047d84), U64_C(0x32caab7b40c72493), + U64_C(0x3c9ebe0a15c9bebc), U64_C(0x431d67c49c100d4c), + U64_C(0x4cc5d4becb3e42b6), U64_C(0x597f299cfc657e2a), + U64_C(0x5fcb6fab3ad6faec), U64_C(0x6c44198c4a475817) + }; + + /* get values from the chaining vars */ + a = hd->h0; + b = hd->h1; + c = hd->h2; + d = hd->h3; + e = hd->h4; + f = hd->h5; + g = hd->h6; + h = hd->h7; + +#ifdef WORDS_BIGENDIAN + memcpy (w, data, 128); +#else + { + int i; + byte *p2; + + for (i = 0, p2 = (byte *) w; i < 16; i++, p2 += 8) + { + p2[7] = *data++; + p2[6] = *data++; + p2[5] = *data++; + p2[4] = *data++; + p2[3] = *data++; + p2[2] = *data++; + p2[1] = *data++; + p2[0] = *data++; + } + } +#endif + +#define S0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7)) +#define S1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6)) + + for (t = 16; t < 80; t++) + w[t] = S1 (w[t - 2]) + w[t - 7] + S0 (w[t - 15]) + w[t - 16]; + + + for (t = 0; t < 80; ) + { + u64 t1, t2; + + /* Performance on a AMD Athlon(tm) Dual Core Processor 4050e + with gcc 4.3.3 using gcry_md_hash_buffer of each 10000 bytes + initialized to 0,1,2,3...255,0,... and 1000 iterations: + + Not unrolled with macros: 440ms + Unrolled with macros: 350ms + Unrolled with inline: 330ms + */ +#if 0 /* Not unrolled. */ + t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; + t2 = Sum0 (a) + Maj (a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; +#else /* Unrolled to interweave the chain variables. */ + t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; + t2 = Sum0 (a) + Maj (a, b, c); + d += t1; + h = t1 + t2; + + t1 = g + Sum1 (d) + Ch (d, e, f) + k[t+1] + w[t+1]; + t2 = Sum0 (h) + Maj (h, a, b); + c += t1; + g = t1 + t2; + + t1 = f + Sum1 (c) + Ch (c, d, e) + k[t+2] + w[t+2]; + t2 = Sum0 (g) + Maj (g, h, a); + b += t1; + f = t1 + t2; + + t1 = e + Sum1 (b) + Ch (b, c, d) + k[t+3] + w[t+3]; + t2 = Sum0 (f) + Maj (f, g, h); + a += t1; + e = t1 + t2; + + t1 = d + Sum1 (a) + Ch (a, b, c) + k[t+4] + w[t+4]; + t2 = Sum0 (e) + Maj (e, f, g); + h += t1; + d = t1 + t2; + + t1 = c + Sum1 (h) + Ch (h, a, b) + k[t+5] + w[t+5]; + t2 = Sum0 (d) + Maj (d, e, f); + g += t1; + c = t1 + t2; + + t1 = b + Sum1 (g) + Ch (g, h, a) + k[t+6] + w[t+6]; + t2 = Sum0 (c) + Maj (c, d, e); + f += t1; + b = t1 + t2; + + t1 = a + Sum1 (f) + Ch (f, g, h) + k[t+7] + w[t+7]; + t2 = Sum0 (b) + Maj (b, c, d); + e += t1; + a = t1 + t2; + + t += 8; +#endif + } + + /* Update chaining vars. */ + hd->h0 += a; + hd->h1 += b; + hd->h2 += c; + hd->h3 += d; + hd->h4 += e; + hd->h5 += f; + hd->h6 += g; + hd->h7 += h; +} + + +/* Update the message digest with the contents + * of INBUF with length INLEN. + */ +static void +sha512_write (void *context, const void *inbuf_arg, size_t inlen) +{ + const unsigned char *inbuf = inbuf_arg; + SHA512_CONTEXT *hd = context; + + if (hd->count == 128) + { /* flush the buffer */ + transform (hd, hd->buf); + _gcry_burn_stack (768); + hd->count = 0; + hd->nblocks++; + } + if (!inbuf) + return; + if (hd->count) + { + for (; inlen && hd->count < 128; inlen--) + hd->buf[hd->count++] = *inbuf++; + sha512_write (context, NULL, 0); + if (!inlen) + return; + } + + while (inlen >= 128) + { + transform (hd, inbuf); + hd->count = 0; + hd->nblocks++; + inlen -= 128; + inbuf += 128; + } + _gcry_burn_stack (768); + for (; inlen && hd->count < 128; inlen--) + hd->buf[hd->count++] = *inbuf++; +} + + +/* The routine final terminates the computation and + * returns the digest. + * The handle is prepared for a new cycle, but adding bytes to the + * handle will the destroy the returned buffer. + * Returns: 64 bytes representing the digest. When used for sha384, + * we take the leftmost 48 of those bytes. + */ + +static void +sha512_final (void *context) +{ + SHA512_CONTEXT *hd = context; + u64 t, msb, lsb; + byte *p; + + sha512_write (context, NULL, 0); /* flush */ ; + + t = hd->nblocks; + /* multiply by 128 to make a byte count */ + lsb = t << 7; + msb = t >> 57; + /* add the count */ + t = lsb; + if ((lsb += hd->count) < t) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + msb |= t >> 61; + + if (hd->count < 112) + { /* enough room */ + hd->buf[hd->count++] = 0x80; /* pad */ + while (hd->count < 112) + hd->buf[hd->count++] = 0; /* pad */ + } + else + { /* need one extra block */ + hd->buf[hd->count++] = 0x80; /* pad character */ + while (hd->count < 128) + hd->buf[hd->count++] = 0; + sha512_write (context, NULL, 0); /* flush */ ; + memset (hd->buf, 0, 112); /* fill next block with zeroes */ + } + /* append the 128 bit count */ + hd->buf[112] = msb >> 56; + hd->buf[113] = msb >> 48; + hd->buf[114] = msb >> 40; + hd->buf[115] = msb >> 32; + hd->buf[116] = msb >> 24; + hd->buf[117] = msb >> 16; + hd->buf[118] = msb >> 8; + hd->buf[119] = msb; + + hd->buf[120] = lsb >> 56; + hd->buf[121] = lsb >> 48; + hd->buf[122] = lsb >> 40; + hd->buf[123] = lsb >> 32; + hd->buf[124] = lsb >> 24; + hd->buf[125] = lsb >> 16; + hd->buf[126] = lsb >> 8; + hd->buf[127] = lsb; + transform (hd, hd->buf); + _gcry_burn_stack (768); + + p = hd->buf; +#ifdef WORDS_BIGENDIAN +#define X(a) do { *(u64*)p = hd->h##a ; p += 8; } while (0) +#else /* little endian */ +#define X(a) do { *p++ = hd->h##a >> 56; *p++ = hd->h##a >> 48; \ + *p++ = hd->h##a >> 40; *p++ = hd->h##a >> 32; \ + *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ + *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while (0) +#endif + X (0); + X (1); + X (2); + X (3); + X (4); + X (5); + /* Note that these last two chunks are included even for SHA384. + We just ignore them. */ + X (6); + X (7); +#undef X +} + +static byte * +sha512_read (void *context) +{ + SHA512_CONTEXT *hd = (SHA512_CONTEXT *) context; + return hd->buf; +} + + + +/* + Self-test section. + */ + + +static gpg_err_code_t +selftests_sha384 (int extended, selftest_report_func_t report) +{ + const char *what; + const char *errtxt; + + what = "short string"; + errtxt = _gcry_hash_selftest_check_one + (GCRY_MD_SHA384, 0, + "abc", 3, + "\xcb\x00\x75\x3f\x45\xa3\x5e\x8b\xb5\xa0\x3d\x69\x9a\xc6\x50\x07" + "\x27\x2c\x32\xab\x0e\xde\xd1\x63\x1a\x8b\x60\x5a\x43\xff\x5b\xed" + "\x80\x86\x07\x2b\xa1\xe7\xcc\x23\x58\xba\xec\xa1\x34\xc8\x25\xa7", 48); + if (errtxt) + goto failed; + + if (extended) + { + what = "long string"; + errtxt = _gcry_hash_selftest_check_one + (GCRY_MD_SHA384, 0, + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, + "\x09\x33\x0C\x33\xF7\x11\x47\xE8\x3D\x19\x2F\xC7\x82\xCD\x1B\x47" + "\x53\x11\x1B\x17\x3B\x3B\x05\xD2\x2F\xA0\x80\x86\xE3\xB0\xF7\x12" + "\xFC\xC7\xC7\x1A\x55\x7E\x2D\xB9\x66\xC3\xE9\xFA\x91\x74\x60\x39", + 48); + if (errtxt) + goto failed; + + what = "one million \"a\""; + errtxt = _gcry_hash_selftest_check_one + (GCRY_MD_SHA384, 1, + NULL, 0, + "\x9D\x0E\x18\x09\x71\x64\x74\xCB\x08\x6E\x83\x4E\x31\x0A\x4A\x1C" + "\xED\x14\x9E\x9C\x00\xF2\x48\x52\x79\x72\xCE\xC5\x70\x4C\x2A\x5B" + "\x07\xB8\xB3\xDC\x38\xEC\xC4\xEB\xAE\x97\xDD\xD8\x7F\x3D\x89\x85", + 48); + if (errtxt) + goto failed; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("digest", GCRY_MD_SHA384, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + +static gpg_err_code_t +selftests_sha512 (int extended, selftest_report_func_t report) +{ + const char *what; + const char *errtxt; + + what = "short string"; + errtxt = _gcry_hash_selftest_check_one + (GCRY_MD_SHA512, 0, + "abc", 3, + "\xDD\xAF\x35\xA1\x93\x61\x7A\xBA\xCC\x41\x73\x49\xAE\x20\x41\x31" + "\x12\xE6\xFA\x4E\x89\xA9\x7E\xA2\x0A\x9E\xEE\xE6\x4B\x55\xD3\x9A" + "\x21\x92\x99\x2A\x27\x4F\xC1\xA8\x36\xBA\x3C\x23\xA3\xFE\xEB\xBD" + "\x45\x4D\x44\x23\x64\x3C\xE8\x0E\x2A\x9A\xC9\x4F\xA5\x4C\xA4\x9F", 64); + if (errtxt) + goto failed; + + if (extended) + { + what = "long string"; + errtxt = _gcry_hash_selftest_check_one + (GCRY_MD_SHA512, 0, + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, + "\x8E\x95\x9B\x75\xDA\xE3\x13\xDA\x8C\xF4\xF7\x28\x14\xFC\x14\x3F" + "\x8F\x77\x79\xC6\xEB\x9F\x7F\xA1\x72\x99\xAE\xAD\xB6\x88\x90\x18" + "\x50\x1D\x28\x9E\x49\x00\xF7\xE4\x33\x1B\x99\xDE\xC4\xB5\x43\x3A" + "\xC7\xD3\x29\xEE\xB6\xDD\x26\x54\x5E\x96\xE5\x5B\x87\x4B\xE9\x09", + 64); + if (errtxt) + goto failed; + + what = "one million \"a\""; + errtxt = _gcry_hash_selftest_check_one + (GCRY_MD_SHA512, 1, + NULL, 0, + "\xE7\x18\x48\x3D\x0C\xE7\x69\x64\x4E\x2E\x42\xC7\xBC\x15\xB4\x63" + "\x8E\x1F\x98\xB1\x3B\x20\x44\x28\x56\x32\xA8\x03\xAF\xA9\x73\xEB" + "\xDE\x0F\xF2\x44\x87\x7E\xA6\x0A\x4C\xB0\x43\x2C\xE5\x77\xC3\x1B" + "\xEB\x00\x9C\x5C\x2C\x49\xAA\x2E\x4E\xAD\xB2\x17\xAD\x8C\xC0\x9B", + 64); + if (errtxt) + goto failed; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("digest", GCRY_MD_SHA512, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + +/* Run a full self-test for ALGO and return 0 on success. */ +static gpg_err_code_t +run_selftests (int algo, int extended, selftest_report_func_t report) +{ + gpg_err_code_t ec; + + switch (algo) + { + case GCRY_MD_SHA384: + ec = selftests_sha384 (extended, report); + break; + case GCRY_MD_SHA512: + ec = selftests_sha512 (extended, report); + break; + default: + ec = GPG_ERR_DIGEST_ALGO; + break; + + } + return ec; +} + + + + +static byte sha512_asn[] = /* Object ID is 2.16.840.1.101.3.4.2.3 */ + { + 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, + 0x00, 0x04, 0x40 + }; + +static gcry_md_oid_spec_t oid_spec_sha512[] = + { + { "2.16.840.1.101.3.4.2.3" }, + + /* PKCS#1 sha512WithRSAEncryption */ + { "1.2.840.113549.1.1.13" }, + + { NULL } + }; + +gcry_md_spec_t _gcry_digest_spec_sha512 = + { + "SHA512", sha512_asn, DIM (sha512_asn), oid_spec_sha512, 64, + sha512_init, sha512_write, sha512_final, sha512_read, + sizeof (SHA512_CONTEXT), + }; +md_extra_spec_t _gcry_digest_extraspec_sha512 = + { + run_selftests + }; + +static byte sha384_asn[] = /* Object ID is 2.16.840.1.101.3.4.2.2 */ + { + 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, + 0x00, 0x04, 0x30 + }; + +static gcry_md_oid_spec_t oid_spec_sha384[] = + { + { "2.16.840.1.101.3.4.2.2" }, + + /* PKCS#1 sha384WithRSAEncryption */ + { "1.2.840.113549.1.1.12" }, + + { NULL }, + }; + +gcry_md_spec_t _gcry_digest_spec_sha384 = + { + "SHA384", sha384_asn, DIM (sha384_asn), oid_spec_sha384, 48, + sha384_init, sha512_write, sha512_final, sha512_read, + sizeof (SHA512_CONTEXT), + }; +md_extra_spec_t _gcry_digest_extraspec_sha384 = + { + run_selftests + }; -- cgit v1.2.3