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, 10991 insertions, 11042 deletions
diff --git a/libgcrypt-1.4.6/cipher/cipher.c b/libgcrypt-1.4.6/cipher/cipher.c index 8bc7aa2..8cfe54f 100644 --- a/libgcrypt-1.4.6/cipher/cipher.c +++ b/libgcrypt-1.4.6/cipher/cipher.c @@ -1,2171 +1,2133 @@ -/* 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);
-}
+/* 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); +} diff --git a/libgcrypt-1.4.6/cipher/ecc.c b/libgcrypt-1.4.6/cipher/ecc.c index bcfab05..fcbd8e3 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, 2010 Free Software Foundation, Inc. + Copyright (C) 2007, 2008 Free Software Foundation, Inc. This file is part of Libgcrypt. @@ -504,7 +504,6 @@ 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) { @@ -513,7 +512,6 @@ 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) @@ -530,11 +528,9 @@ 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%s\n", nbits, - transient_key? " (transient-key)":""); - d = gen_k (E.n, random_level); + log_debug ("choosing a random x of size %u\n", nbits); + d = gen_k (E.n, GCRY_VERY_STRONG_RANDOM); /* Compute Q. */ point_init (&Q); @@ -966,7 +962,6 @@ 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; @@ -983,14 +978,6 @@ 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. */ @@ -1001,7 +988,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, transient_key, g_x, g_y, q_x, q_y); + ec = generate_key (&sk, nbits, curve_name, g_x, g_y, q_x, q_y); gcry_free (curve_name); if (ec) return ec; @@ -1279,7 +1266,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 function later and + should not be required but we use an internal fucntion 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 5f9dbc6..84c7799 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 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);
-}
+/* 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); +} diff --git a/libgcrypt-1.4.6/cipher/primegen.c b/libgcrypt-1.4.6/cipher/primegen.c index 50dc560..b869bee 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 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;
-}
-
+/* 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; +} + diff --git a/libgcrypt-1.4.6/cipher/pubkey.c b/libgcrypt-1.4.6/cipher/pubkey.c index 1aae8ea..08abcbf 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 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;
-}
+/* 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; +} diff --git a/libgcrypt-1.4.6/cipher/rijndael.c b/libgcrypt-1.4.6/cipher/rijndael.c index 1df703a..d43b349 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 0ac0b5b..6b7e655 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 43878ef..59c3e65 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 + }; |