summaryrefslogtreecommitdiff
path: root/libgcrypt-1.4.6/cipher
diff options
context:
space:
mode:
Diffstat (limited to 'libgcrypt-1.4.6/cipher')
-rw-r--r--libgcrypt-1.4.6/cipher/cipher.c4304
-rw-r--r--libgcrypt-1.4.6/cipher/ecc.c23
-rw-r--r--libgcrypt-1.4.6/cipher/md.c2764
-rw-r--r--libgcrypt-1.4.6/cipher/primegen.c3724
-rw-r--r--libgcrypt-1.4.6/cipher/pubkey.c5498
-rw-r--r--libgcrypt-1.4.6/cipher/rijndael.c2506
-rw-r--r--libgcrypt-1.4.6/cipher/serpent.c1956
-rw-r--r--libgcrypt-1.4.6/cipher/sha512.c1258
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
+ };