diff options
Diffstat (limited to 'libgcrypt-1.4.6/cipher')
-rw-r--r-- | libgcrypt-1.4.6/cipher/cipher.c | 4304 | ||||
-rw-r--r-- | libgcrypt-1.4.6/cipher/ecc.c | 23 | ||||
-rw-r--r-- | libgcrypt-1.4.6/cipher/md.c | 2764 | ||||
-rw-r--r-- | libgcrypt-1.4.6/cipher/primegen.c | 3724 | ||||
-rw-r--r-- | libgcrypt-1.4.6/cipher/pubkey.c | 5498 | ||||
-rw-r--r-- | libgcrypt-1.4.6/cipher/rijndael.c | 2506 | ||||
-rw-r--r-- | libgcrypt-1.4.6/cipher/serpent.c | 1956 | ||||
-rw-r--r-- | libgcrypt-1.4.6/cipher/sha512.c | 1258 |
8 files changed, 11042 insertions, 10991 deletions
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 <http://www.gnu.org/licenses/>. - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#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 <http://www.gnu.org/licenses/>. - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#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 <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#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 <http://www.gnu.org/licenses/>. - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#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 <mpi>) - * (g <mpi>) - * (y <mpi>) - * (x <mpi>) - * ) - * ) - * The <mpi> 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])] - * (<algo> - * (<param_name1> <mpi>) - * ... - * (<param_namen> <mpi>) - * )) - * 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. - - (<mpi>) - or - (data - [(flags [pkcs1])] - [(hash <algo> <value>)] - [(value <text>)] - ) - - 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 = <key-as-defined-in-sexp_to_key> - r_ciph = (enc-val - (<algo> - (<param_name1> <mpi>) - ... - (<param_namen> <mpi>) - )) - -*/ -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)] - (<algo> - (<param_name1> <mpi>) - ... - (<param_namen> <mpi>) - )) - s_skey = <key-as-defined-in-sexp_to_key> - 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 = <key-as-defined-in-sexp_to_key> - r_sig = (sig-val - (<algo> - (<param_name1> <mpi>) - ... - (<param_namen> <mpi>)) - [(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 = <key-as-defined-in-sexp_to_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 <mpi>) - (g <mpi>) - (y <mpi>) - ) - ) - (private-key - (elg - (p <mpi>) - (g <mpi>) - (y <mpi>) - (x <mpi>) - ) - ) - (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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#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 <mpi>)
+ * (g <mpi>)
+ * (y <mpi>)
+ * (x <mpi>)
+ * )
+ * )
+ * The <mpi> 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])]
+ * (<algo>
+ * (<param_name1> <mpi>)
+ * ...
+ * (<param_namen> <mpi>)
+ * ))
+ * 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.
+
+ (<mpi>)
+ or
+ (data
+ [(flags [pkcs1])]
+ [(hash <algo> <value>)]
+ [(value <text>)]
+ )
+
+ 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 = <key-as-defined-in-sexp_to_key>
+ r_ciph = (enc-val
+ (<algo>
+ (<param_name1> <mpi>)
+ ...
+ (<param_namen> <mpi>)
+ ))
+
+*/
+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)]
+ (<algo>
+ (<param_name1> <mpi>)
+ ...
+ (<param_namen> <mpi>)
+ ))
+ s_skey = <key-as-defined-in-sexp_to_key>
+ 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 = <key-as-defined-in-sexp_to_key>
+ r_sig = (sig-val
+ (<algo>
+ (<param_name1> <mpi>)
+ ...
+ (<param_namen> <mpi>))
+ [(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 = <key-as-defined-in-sexp_to_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 <mpi>)
+ (g <mpi>)
+ (y <mpi>)
+ )
+ )
+ (private-key
+ (elg
+ (p <mpi>)
+ (g <mpi>)
+ (y <mpi>)
+ (x <mpi>)
+ )
+ )
+ (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 <http://www.gnu.org/licenses/>. - ******************************************************************* - * 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 <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> /* 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 <http://www.gnu.org/licenses/>.
+ *******************************************************************
+ * 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 <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* 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 <config.h> - -#include <string.h> -#include <stdio.h> - -#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 <config.h>
+
+#include <string.h>
+#include <stdio.h>
+
+#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 <http://www.gnu.org/licenses/>. - */ - - -/* 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 <config.h> -#include <string.h> -#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 <http://www.gnu.org/licenses/>.
+ */
+
+
+/* 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 <config.h>
+#include <string.h>
+#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
+ };
|