Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F25703515
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
137 KB
Subscribers
None
View Options
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 73544d23..b6cdf00e 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -1,1322 +1,1324 @@
/* cipher.c - cipher dispatcher
* Copyright (C) 1998,1999,2000,2001,2002,2003 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 <assert.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
/* This is the list of the default ciphers, which are included in
libgcrypt. */
static struct cipher_table_entry
{
gcry_cipher_spec_t *cipher;
unsigned int algorithm;
} cipher_table[] =
{
#if USE_BLOWFISH
{ &cipher_spec_blowfish, GCRY_CIPHER_BLOWFISH },
#endif
#if USE_DES
{ &cipher_spec_des, GCRY_CIPHER_DES },
{ &cipher_spec_tripledes, GCRY_CIPHER_3DES },
#endif
#if USE_ARCFOUR
{ &cipher_spec_arcfour, GCRY_CIPHER_ARCFOUR },
#endif
#if USE_CAST5
{ &cipher_spec_cast5, GCRY_CIPHER_CAST5 },
#endif
#if USE_AES
{ &cipher_spec_aes, GCRY_CIPHER_AES },
{ &cipher_spec_aes192, GCRY_CIPHER_AES192 },
{ &cipher_spec_aes256, GCRY_CIPHER_AES256 },
#endif
#if USE_TWOFISH
{ &cipher_spec_twofish, GCRY_CIPHER_TWOFISH },
{ &cipher_spec_twofish128, GCRY_CIPHER_TWOFISH128 },
#endif
#if USE_SERPENT
{ &cipher_spec_serpent128, GCRY_CIPHER_SERPENT128 },
{ &cipher_spec_serpent192, GCRY_CIPHER_SERPENT192 },
{ &cipher_spec_serpent256, GCRY_CIPHER_SERPENT256 },
#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) \
{ \
gcry_cipher_register_default (); \
default_ciphers_registered = 1; \
} \
ath_mutex_unlock (&ciphers_registered_lock); \
} \
while (0)
/* The handle structure. */
struct gcry_cipher_handle
{
int magic;
gcry_cipher_spec_t *cipher;
gcry_module_t module;
int mode;
unsigned int flags;
byte iv[MAX_BLOCKSIZE]; /* (this should be ulong aligned) */
byte lastiv[MAX_BLOCKSIZE];
int unused; /* in IV */
byte ctr[MAX_BLOCKSIZE]; /* for Counter (CTR) mode */
PROPERLY_ALIGNED_TYPE 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 keylen)
{
return GPG_ERR_NO_ERROR;
}
static void
dummy_encrypt_block (void *c,
unsigned char *outbuf, const unsigned char *inbuf)
{
BUG();
}
static void
dummy_decrypt_block (void *c,
unsigned char *outbuf, const unsigned char *inbuf)
{
BUG();
}
static void
dummy_encrypt_stream (void *c,
unsigned char *outbuf, const unsigned char *inbuf,
unsigned int n)
{
BUG();
}
static void
dummy_decrypt_stream (void *c,
unsigned char *outbuf, const unsigned char *inbuf,
unsigned int n)
{
BUG();
}
/* Internal function. Register all the ciphers included in
CIPHER_TABLE. */
static void
gcry_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;
err = _gcry_module_add (&ciphers_registered,
cipher_table[i].algorithm,
(void *) cipher_table[i].cipher,
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,
unsigned int *algorithm_id,
gcry_module_t *module)
{
gcry_err_code_t err = 0;
gcry_module_t mod;
ath_mutex_lock (&ciphers_registered_lock);
err = _gcry_module_add (&ciphers_registered, 0,
(void *) cipher, &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 */
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 a string to the cipher algo.
* Returns: The algo ID of the cipher for the gioven name or
* 0 if the name is not known.
*/
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;
}
int
gcry_cipher_mode_from_oid (const char *string)
{
gcry_cipher_oid_spec_t oid_spec;
int ret = 0, mode = 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 a cipher algo to a string
*/
static const char *
cipher_algo_to_string (int algorithm)
{
gcry_module_t cipher;
const char *name = NULL;
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);
}
ath_mutex_unlock (&ciphers_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.
*/
const char *
gcry_cipher_algo_name (int algorithm)
{
const char *s = cipher_algo_to_string (algorithm);
return s ? s : "";
}
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 algo is 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;
}
static unsigned
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;
}
static unsigned
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 algorithm ALGO, in mode MODE and
* return the handle. Put NULL into HANDLER and return and error code
* if something goes wrong. */
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;
gcry_module_t module = NULL;
gcry_cipher_hd_t h = NULL;
gcry_err_code_t err = 0;
_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;
}
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_CTR:
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:
/* FIXME: issue a warning when this mode is used */
break;
default:
err = GPG_ERR_INV_CIPHER_MODE;
}
/* ? FIXME: perform selftest here and mark this with a flag in
cipher_table ? */
if (! err)
{
size_t size = sizeof (*h)
+ 2 * cipher->contextsize
- sizeof (PROPERLY_ALIGNED_TYPE);
if (secure)
h = gcry_calloc_secure (1, size);
else
h = gcry_calloc (1, size);
if (! h)
err = gpg_err_code_from_errno (errno);
else
{
h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL;
h->cipher = cipher;
h->module = module;
h->mode = mode;
h->flags = flags;
}
}
/* 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);
}
void
gcry_cipher_close (gcry_cipher_hd_t h)
{
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);
gcry_free (h);
}
static gcry_error_t
cipher_setkey (gcry_cipher_hd_t c, byte *key, unsigned 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);
return gcry_error (ret);
}
static void
cipher_setiv( gcry_cipher_hd_t c, const byte *iv, unsigned ivlen )
{
memset( c->iv, 0, c->cipher->blocksize );
if( iv ) {
if( ivlen != c->cipher->blocksize )
log_info("WARNING: cipher_setiv: ivlen=%u blklen=%u\n",
ivlen, (unsigned) c->cipher->blocksize );
if (ivlen > c->cipher->blocksize)
ivlen = c->cipher->blocksize;
memcpy( c->iv, iv, ivlen );
}
c->unused = 0;
}
static void
cipher_reset (gcry_cipher_hd_t c)
{
memcpy ((void *) &c->context.c,
(void *) ((char *) &c->context.c + c->cipher->contextsize),
c->cipher->contextsize);
memset (c->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 nblocks )
{
unsigned 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 nblocks )
{
unsigned 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, byte *outbuf, const byte *inbuf, unsigned nbytes )
{
unsigned int n;
byte *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--;
}
for(n=0; n < nblocks; n++ ) {
/* fixme: the xor should works on words and not on
* bytes. Maybe it is a good idea to enhance the cipher backend
* API to allow for CBC handling in the backend */
for(ivp=c->iv,i=0; i < blocksize; i++ )
outbuf[i] = inbuf[i] ^ *ivp++;
(*c->cipher->encrypt)( &c->context.c, outbuf, outbuf );
memcpy(c->iv, outbuf, blocksize );
inbuf += c->cipher->blocksize;
if (!(c->flags & GCRY_CIPHER_CBC_MAC))
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(outbuf, outbuf - c->cipher->blocksize, restbytes);
outbuf -= c->cipher->blocksize;
for(ivp=c->iv,i=0; i < restbytes; i++ )
outbuf[i] = inbuf[i] ^ *ivp++;
for(; i < blocksize; i++ )
outbuf[i] = 0 ^ *ivp++;
(*c->cipher->encrypt)( &c->context.c, outbuf, outbuf );
memcpy(c->iv, outbuf, blocksize );
}
}
static void
do_cbc_decrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, unsigned nbytes )
{
unsigned int n;
byte *ivp;
int i;
size_t blocksize = c->cipher->blocksize;
unsigned nblocks = nbytes / blocksize;
if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) {
nblocks--;
if ((nbytes % blocksize) == 0)
nblocks--;
memcpy(c->lastiv, c->iv, blocksize );
}
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, (char*)/*argggg*/inbuf );
for(ivp=c->iv,i=0; i < blocksize; i++ )
outbuf[i] ^= *ivp++;
memcpy(c->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->iv, blocksize ); /* save Cn-2 */
memcpy(c->iv, inbuf + blocksize, restbytes ); /* save Cn */
(*c->cipher->decrypt)( &c->context.c, outbuf, (char*)/*argggg*/inbuf );
for(ivp=c->iv,i=0; i < restbytes; i++ )
outbuf[i] ^= *ivp++;
memcpy(outbuf + blocksize, outbuf, restbytes);
for(i=restbytes; i < blocksize; i++)
c->iv[i] = outbuf[i];
(*c->cipher->decrypt)( &c->context.c, outbuf, c->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,
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 and store input into IV */
for(ivp=c->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->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->iv, blocksize );
(*c->cipher->encrypt)( &c->context.c, c->iv, c->iv );
/* XOR the input with the IV and store input into IV */
for(ivp=c->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->iv, blocksize );
(*c->cipher->encrypt)( &c->context.c, c->iv, c->iv );
c->unused = blocksize;
/* and apply the xor */
c->unused -= nbytes;
for(ivp=c->iv; nbytes; nbytes-- )
*outbuf++ = (*ivp++ ^= *inbuf++);
}
}
static void
do_cfb_decrypt( gcry_cipher_hd_t c,
byte *outbuf, const byte *inbuf, unsigned nbytes )
{
byte *ivp;
ulong temp;
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 and store input into IV */
for(ivp=c->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->iv+blocksize - c->unused; c->unused; c->unused-- ) {
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
}
}
/* now we can process complete blocks */
while( nbytes >= blocksize ) {
int i;
/* encrypt the IV (and save the current one) */
memcpy( c->lastiv, c->iv, blocksize );
(*c->cipher->encrypt)( &c->context.c, c->iv, c->iv );
/* XOR the input with the IV and store input into IV */
for(ivp=c->iv,i=0; i < blocksize; i++ ) {
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
}
nbytes -= blocksize;
}
if( nbytes ) { /* process the remaining bytes */
/* encrypt the IV (and save the current one) */
memcpy( c->lastiv, c->iv, blocksize );
(*c->cipher->encrypt)( &c->context.c, c->iv, c->iv );
c->unused = blocksize;
/* and apply the xor */
c->unused -= nbytes;
for(ivp=c->iv; nbytes; nbytes-- ) {
temp = *inbuf++;
*outbuf++ = *ivp ^ temp;
*ivp++ = temp;
}
}
}
static void
do_ctr_encrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, unsigned 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 nbytes )
{
return do_ctr_encrypt (c, outbuf, inbuf, nbytes);
}
/****************
* 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_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( 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, byte *out, size_t outsize,
const byte *in, size_t inlen)
{
gcry_err_code_t err;
if (!in)
/* caller requested in-place encryption */
/* actullay cipher_encrypt() does not need to know about it, but
* we may change this to get better performace */
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 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_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( 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, byte *out, size_t outsize,
const byte *in, size_t inlen)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
if (! in)
/* caller requested in-place encryption */
/* actullay cipher_encrypt() does not need to know about it, but
* we may chnage this to get better performace */
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->iv + c->unused, c->iv, c->cipher->blocksize - c->unused );
memcpy(c->iv, c->lastiv + c->cipher->blocksize - c->unused, c->unused);
c->unused = 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:
rc = cipher_setkey( h, buffer, buflen );
break;
case GCRYCTL_SET_IV:
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 one expects a NULL handle and buffer pointing 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:
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;
default:
rc = GPG_ERR_INV_OP;
}
return gcry_error (rc);
}
/****************
* Return information about the cipher handle.
*/
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;
switch (cmd)
{
default:
err = GPG_ERR_INV_OP;
}
return gcry_error (err);
}
/****************
* Return information about the given cipher algorithm
* WHAT select the kind of information returned:
* GCRYCTL_GET_KEYLEN:
* Return the length of the key, if the algorithm
* supports multiple key length, the maximum supported value
* is returnd. The length is return as number of octets.
* buffer and nbytes must be zero.
* The keylength is returned in _bytes_.
* GCRYCTL_GET_BLKLEN:
* Return the blocklength of the algorithm counted in octets.
* buffer and nbytes must be zero.
* GCRYCTL_TEST_ALGO:
* Returns 0 when the specified algorithm 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);
}
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;
}
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;
}
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_cipher_list (int **list, int *list_length)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
+ REGISTER_DEFAULT_CIPHERS;
+
ath_mutex_lock (&ciphers_registered_lock);
err = _gcry_module_list (ciphers_registered, list, list_length);
ath_mutex_unlock (&ciphers_registered_lock);
return err;
}
diff --git a/cipher/md.c b/cipher/md.c
index 790ca979..58ac6e4a 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -1,1253 +1,1255 @@
/* md.c - message digest dispatcher
* Copyright (C) 1998, 1999, 2002, 2003 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 <assert.h>
#include "g10lib.h"
#include "cipher.h"
#include "ath.h"
#include "rmd.h"
static struct digest_table_entry
{
gcry_md_spec_t *digest;
unsigned int algorithm;
} digest_table[] =
{
#if USE_CRC
{ &digest_spec_crc32, GCRY_MD_CRC32 },
{ &digest_spec_crc32_rfc1510, GCRY_MD_CRC32_RFC1510 },
{ &digest_spec_crc24_rfc2440, GCRY_MD_CRC24_RFC2440 },
#endif
#if USE_MD4
{ &digest_spec_md4, GCRY_MD_MD4 },
#endif
#if USE_MD5
{ &digest_spec_md5, GCRY_MD_MD5 },
#endif
#if USE_RMD160
{ &digest_spec_rmd160, GCRY_MD_RMD160 },
#endif
#if USE_SHA1
{ &digest_spec_sha1, GCRY_MD_SHA1 },
#endif
#if USE_SHA256
{ &digest_spec_sha256, GCRY_MD_SHA256 },
#endif
#if USE_SHA512
{ &digest_spec_sha512, GCRY_MD_SHA512 },
{ &digest_spec_sha384, GCRY_MD_SHA384 },
#endif
#if USE_TIGER
{ &digest_spec_tiger, GCRY_MD_TIGER },
#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;
/* Convenient macro for registering the default digests. */
#define REGISTER_DEFAULT_DIGESTS \
do \
{ \
ath_mutex_lock (&digests_registered_lock); \
if (! default_digests_registered) \
{ \
gcry_md_register_default (); \
default_digests_registered = 1; \
} \
ath_mutex_unlock (&digests_registered_lock); \
} \
while (0)
/* Internal function. Register all the ciphers included in
CIPHER_TABLE. Returns zero on success or an error code. */
static void
gcry_md_register_default (void)
{
gcry_err_code_t err = 0;
int i;
for (i = 0; (! err) && digest_table[i].digest; i++)
err = _gcry_module_add (&digests_registered,
digest_table[i].algorithm,
(void *) digest_table[i].digest,
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,
unsigned int *algorithm_id,
gcry_module_t *module)
{
gcry_err_code_t err = 0;
gcry_module_t mod;
ath_mutex_lock (&digests_registered_lock);
err = _gcry_module_add (&digests_registered, 0,
(void *) digest, &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);
}
typedef struct gcry_md_list
{
gcry_md_spec_t *digest;
gcry_module_t module;
struct gcry_md_list *next;
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;
int secure;
FILE *debug;
int finalized;
GcryDigestEntry *list;
byte *macpads;
};
#define CTX_MAGIC_NORMAL 0x11071961
#define CTX_MAGIC_SECURE 0x16917011
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, byte *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 );
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 for an acording diget 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 sture 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->secure = secure;
if (hmac)
{
ctx->macpads = gcry_malloc_secure (128);
if (! ctx->macpads)
{
md_close (hd);
err = gpg_err_code_from_errno (errno);
}
}
}
if (! err)
{
/* FIXME: should we really do that? */
_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_err_code_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 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;
err = _gcry_md_open (h, algo, flags);
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)
{
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;
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)
{
gcry_err_code_t err = md_enable (hd, algorithm);
return gcry_error (err);
}
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 */
assert (ahd->bufsize == (n - sizeof (struct gcry_md_handle) + 1));
bhd->bufsize = ahd->bufsize;
bhd->bufpos = 0;
assert (! ahd->bufpos);
memcpy (b, a, sizeof *a);
b->list = NULL;
b->debug = NULL;
if (a->macpads)
{
b->macpads = gcry_malloc_secure (128);
if (! b->macpads)
{
md_close (bhd);
err = gpg_err_code_from_errno (errno);
}
else
memcpy (b->macpads, a->macpads, 128);
}
}
/* and now copy the complete list of algorithms */
/* I know that 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_xmalloc_secure (sizeof *br
+ ar->digest->contextsize
- sizeof(ar->context));
else
br = gcry_xmalloc (sizeof *br
+ ar->digest->contextsize
- sizeof (ar->context));
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)
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 = 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;
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, 64); /* 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);
gcry_free (r);
}
gcry_free(a->ctx->macpads);
gcry_free(a);
}
void
gcry_md_close (gcry_md_hd_t hd)
{
md_close (hd);
}
static void
md_write (gcry_md_hd_t a, byte *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, (unsigned char *) 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+64, 64);
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 byte *key, size_t keylen)
{
int i;
int algo = md_get_algo( hd );
byte *helpkey = NULL;
byte *ipad, *opad;
if( !algo )
return GPG_ERR_DIGEST_ALGO; /* i.e. no algo enabled */
if( keylen > 64 ) {
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 );
assert( keylen <= 64 );
}
memset( hd->ctx->macpads, 0, 128 );
ipad = hd->ctx->macpads;
opad = hd->ctx->macpads+64;
memcpy( ipad, key, keylen );
memcpy( opad, key, keylen );
for(i=0; i < 64; 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, byte *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);
}
/****************
* 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 && r->next)
log_debug("more than 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)
{
gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0);
return md_read (hd, algo);
}
/****************
* This function combines md_final and md_read but keeps the context
* intact. This function can be used to calculate intermediate
* digests. The digest is copied into buffer and the digestlength is
* returned. If buffer is NULL only the needed size for buffer is returned.
* buflen gives the max size of buffer. If the buffer is too shourt to
* hold the complete digest, the buffer is filled with as many bytes are
* possible and this value is returned.
*/
#if 0
static int
md_digest( gcry_md_hd_t a, int algo, byte *buffer, int buflen )
{
struct md_digest_list_s *r = NULL;
char *context;
char *digest;
if( a->bufpos )
md_write( a, NULL, 0 );
if( !algo ) { /* return digest for the first algorithm */
if( (r=a->ctx->list) && r->next )
log_debug("more than algorithm in md_digest(0)\n");
}
else {
for(r=a->ctx->list; r; r = r->next )
if( r->algo == algo )
break;
}
if( !r )
BUG();
if( !buffer )
return r->mdlen;
/* I don't want to change the interface, so I simply work on a copy
* of the context (extra overhead - should be fixed)*/
context = a->ctx->secure ? gcry_xmalloc_secure( r->contextsize )
: gcry_xmalloc( r->contextsize );
memcpy( context, r->context.c, r->contextsize );
(*r->digest->final)( context );
digest = (*r->digest->read)( context );
if( buflen > r->mdlen )
buflen = r->mdlen;
memcpy( buffer, digest, buflen );
gcry_free(context);
return buflen;
}
#endif
/****************
* Read out an intermediate digest.
*/
gcry_err_code_t
gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen)
{
/*md_digest ... */
return GPG_ERR_INTERNAL;
}
/****************
* Shortcut function to hash a buffer with a given algo. The only
* guarnteed supported algorithm is RIPE-MD. 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_RMD160)
_gcry_rmd160_hash_buffer (digest, buffer, length);
else
{
/* For the others we do not have a fast function, so we use the
normal functions to do it */
gcry_md_hd_t h;
gpg_err_code_t 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)
log_error("WARNING: more than 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 for md algo %d\n", algorithm);
ath_mutex_unlock (&digests_registered_lock);
return asnoid;
}
void
_gcry_md_info_get (gcry_md_hd_t handle,
unsigned char **md_asn, size_t *md_asn_n, size_t *md_dlen)
{
gcry_md_spec_t *digest = handle->ctx->list->digest;
*md_asn = digest->asnoid;
*md_asn_n = digest->asnlen;
*md_dlen = digest->mdlen;
}
/****************
* 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:
{
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[25];
if( md->ctx->debug ) {
log_debug("Oops: md debug already started\n");
return;
}
idx++;
sprintf(buf, "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 enanled 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);
}
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_md_list (int **list, int *list_length)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
+ REGISTER_DEFAULT_DIGESTS;
+
ath_mutex_lock (&digests_registered_lock);
err = _gcry_module_list (digests_registered, list, list_length);
ath_mutex_unlock (&digests_registered_lock);
return err;
}
diff --git a/cipher/primegen.c b/cipher/primegen.c
index e74eed93..fa76a292 100644
--- a/cipher/primegen.c
+++ b/cipher/primegen.c
@@ -1,859 +1,859 @@
/* primegen.c - prime number generator
* Copyright (C) 1998, 2000, 2001, 2002, 2003 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
*
* ***********************************************************************
* The algorithm used to generate practically save primes is due to
* Lim and Lee as described in the CRYPTO '97 proceedings (ISBN3540633847)
* page 260.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "g10lib.h"
#include "mpi.h"
#include "cipher.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 );
static int is_prime( gcry_mpi_t n, int steps, 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;
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,
int (*extra_check)(void*, gcry_mpi_t),
void *extra_check_arg)
{
gcry_mpi_t prime;
prime = gen_prime( nbits, 1, 2, extra_check, extra_check_arg);
progress('\n');
return prime;
}
gcry_mpi_t
_gcry_generate_public_prime( unsigned int nbits,
int (*extra_check)(void*, gcry_mpi_t),
void *extra_check_arg)
{
gcry_mpi_t prime;
prime = gen_prime( nbits, 0, 2, extra_check, extra_check_arg );
progress('\n');
return prime;
}
/****************
* We do not need to use the strongest RNG because we gain no extra
* security from it - The prime number is public and we could also
* offer the factors for those who are willing to check that it is
* indeed a strong prime.
*
* mode 0: Standard
* 1: Make sure that at least one factor is of size qbits.
*/
static gcry_err_code_t
prime_generate_internal (int mode,
gcry_mpi_t *prime_generated, unsigned int pbits,
unsigned int qbits, gcry_mpi_t g,
gcry_mpi_t **ret_factors,
gcry_random_level_t random, unsigned int flags)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_mpi_t *factors_new = NULL; /* Factors to return to the
caller. */
gcry_mpi_t *factors = NULL; /* Current factors. */
gcry_mpi_t *pool = NULL; /* Pool of primes. */
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; /* Prime candidate. */
+ gcry_mpi_t prime = NULL; /* Prime candidate. */
unsigned int nprime = 0; /* Bits of PRIME. */
unsigned int req_qbits = qbits; /* The original QBITS value. */
gcry_mpi_t val_2 = mpi_alloc_set_ui (2); /* For check_prime(). */
unsigned int is_secret = flags & GCRY_PRIME_FLAG_SECRET;
unsigned int count1 = 0, count2 = 0;
unsigned int i = 0, j = 0;
/* Find number of needed prime factors. */
for (n = 1; (pbits - qbits - 1) / n >= qbits; n++);
n--;
if ((! n) || ((mode == 1) && (n < 2)))
err = GPG_ERR_INV_ARG;
if (! err)
{
if (mode == 1)
{
n--;
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);
prime = gcry_mpi_new (pbits);
/* Generate first prime factor. */
q = gen_prime (qbits, is_secret, random, NULL, NULL);
if (mode == 1)
q_factor = gen_prime (req_qbits, is_secret, random, NULL, NULL);
/* Allocate an array to hold the factors + 2 for later
usage. */
factors = gcry_calloc (n + 2, sizeof (*factors));
if (! factors)
err = GPG_ERR_INTERNAL; /* FIXME. */
}
if (! err)
{
/* Make a pool of 3n+5 primes (this is an arbitrary value). */
m = n * 3 + 5;
if (mode == 1)
/* Need some more (for e.g. DSA). */
m += 5;
if (m < 25)
m = 25;
pool = gcry_calloc (m , sizeof (*pool));
if (! pool)
err = GPG_ERR_INTERNAL;
}
if (! err)
/* Permutate over the pool of primes. */
do
{
next_try:
if (! perms)
{
/* Allocate new 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_INTERNAL; /* FIXME. */
else
{
for(i = 0; i < n; i++)
{
perms[i] = 1;
pool[i] = gen_prime (fbits, is_secret, random, NULL, NULL);
factors[i] = pool[i];
}
}
if (err)
break;
}
else
{
m_out_of_n (perms, n, m);
for(i = j = 0; (i < m) && (j < n); i++)
if (perms[i])
{
if(! pool[i])
pool[i] = gen_prime (fbits, 0, 1, NULL, NULL);
factors[j++] = pool[i];
}
if (i == n)
{
gcry_free(perms);
perms = NULL;
progress('!');
goto next_try; /* Allocate new primes. */
}
}
/* 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 (mode == 1)
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, 0, 0, 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, 0, 0, NULL, NULL);
goto next_try;
}
}
else
count2 = 0;
}
while (! ((nprime == pbits) && check_prime (prime, val_2)));
if (! err)
if (DBG_CIPHER)
{
progress ('\n');
log_mpidump ("prime : ", prime);
log_mpidump ("factor q: ", q);
if (mode == 1)
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 (mode == 1)
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 (! err)
if (ret_factors)
{
/* Caller wants the factors. */
factors_new = gcry_calloc (n + 2, sizeof (*factors_new));
if (! factors_new)
err = GPG_ERR_INTERNAL; /* FIXME. */
else
{
i = 0;
if (mode == 1)
{
(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 (! err)
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 (mode == 1)
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_debug ("\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 (! err)
if (! DBG_CIPHER)
progress ('\n');
if (pool)
{
for(i = 0; i < m; i++)
mpi_free (pool[i]);
gcry_free (pool);
}
if (factors)
gcry_free (factors); /* Factors are shallow copies. */
if (perms)
gcry_free (perms);
mpi_free (val_2);
mpi_free (q);
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);
}
}
return err;
}
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, &prime, pbits, qbits, g,
ret_factors, GCRY_WEAK_RANDOM, 0);
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 x, step;
unsigned count1, count2;
int *mods;
if( 0 && DBG_CIPHER )
log_debug("generate a prime of %u bits ", nbits );
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 0. 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 keysize 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 faster Fermat test */
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
*/
static int
check_prime( gcry_mpi_t prime, gcry_mpi_t val_2 )
{
int i;
unsigned x;
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 ) ) { /* if composite */
mpi_free( result );
progress('.');
return 0;
}
mpi_free( result );
}
/* perform stronger tests */
if( is_prime(prime, 5, &count ) )
return 1; /* is probably a prime */
progress('.');
return 0;
}
/****************
* Return true if n is probably a prime
*/
static int
is_prime( gcry_mpi_t n, int steps, 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 );
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 );
}
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 );
return rc;
}
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;
if( m == 1 ) { /* special case */
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:
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 (flags & GCRY_PRIME_FLAG_SPECIAL_FACTOR)
mode = 1;
/* Generate. */
err = prime_generate_internal (mode, &prime_generated, prime_bits,
factor_bits, NULL, &factors_generated,
random_level, flags);
if (! err)
if (cb_func)
{
/* Additional check */
if (! (*cb_func) (cb_arg, 0, prime_generated))
{
/* Failed, deallocate resources. */
unsigned int i;
mpi_free (prime_generated);
for (i = 0; factors_generated[i]; i++)
mpi_free (factors_generated[i]);
gcry_free (factors_generated);
err = GPG_ERR_INTERNAL; /* FIXME. */
}
}
if (! err)
{
/* Done. */
*prime = prime_generated;
*factors = factors_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 test_value = mpi_alloc_set_ui (2); /* ? */
if (! check_prime (x, test_value))
err = GPG_ERR_NO_PRIME;
mpi_free (test_value);
return gcry_error (err);
}
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index b7c8577f..861d9f28 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -1,1685 +1,1668 @@
/* pubkey.c - S-Expression based interface for asymmetric cryptography.
Copyright (C) 1998, 1999, 2000, 2002, 2003 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. */
/* Note: This interface was rewritten to act as a wrapper-interface
for the new gcry_ac_* interface. */
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
#include "ath.h"
/* Types of cryptographic S-Expressions... */
typedef enum
{
PK_SEXP_TYPE_KEY_SECRET,
PK_SEXP_TYPE_KEY_PUBLIC,
PK_SEXP_TYPE_ENCRYPTION,
PK_SEXP_TYPE_SIGNATURE,
}
pk_sexp_type_t;
/* ... and their corresponding properties. */
static struct
{
const char *identifier; /* String identifier. */
} pk_sexp_types[] =
{
{ "private-key" },
{ "public-key" },
{ "enc-val" },
{ "sig-val" },
{ NULL, }
};
typedef enum
{
PK_KEY_TYPE_ANY,
PK_KEY_TYPE_PUBLIC,
PK_KEY_TYPE_SECRET,
}
pk_key_type_t;
/* Flags for S-Expressions... */
#define PK_SEXP_FLAG_RAW (1 << 0)
#define PK_SEXP_FLAG_PKCS1_V1_5 (1 << 1)
#define PK_SEXP_FLAG_NO_BLINDING (1 << 2)
/* ... and their corresponding properties. */
static struct
{
unsigned int flag; /* Numeric flag. */
const char *identifier; /* String identifier. */
} pk_sexp_flags[] =
{
{ PK_SEXP_FLAG_RAW, "raw" },
{ PK_SEXP_FLAG_PKCS1_V1_5, "pkcs1" },
{ PK_SEXP_FLAG_NO_BLINDING, "no-blinding" },
{ 0, NULL }
};
/* General flags specifying modes of operation. */
/* `Modern' S-Expressions are used. */
#define PK_FLAG_MODERN (1 << 0)
-/* Wrapper macros. */
-
-#define _pk_wrap(expr) gcry_err_code (expr)
-#define gcry_ac_data_get_index(args ...) _pk_wrap (gcry_ac_data_get_index (args))
-#define gcry_ac_name_to_id(args ...) _pk_wrap (gcry_ac_name_to_id (args))
-#define gcry_ac_open(args ...) _pk_wrap (gcry_ac_open (args))
-#define gcry_ac_data_new(args ...) _pk_wrap (gcry_ac_data_new (args))
-#define gcry_ac_data_set(args ...) _pk_wrap (gcry_ac_data_set (args))
-#define gcry_ac_key_init(args ...) _pk_wrap (gcry_ac_key_init (args))
-#define gcry_ac_id_to_name(args ...) _pk_wrap (gcry_ac_id_to_name (args))
-#define gcry_sexp_build_array(args ...) _pk_wrap (gcry_sexp_build_array (args))
-#define gcry_sexp_build(args ...) _pk_wrap (gcry_sexp_build (args))
-#define gcry_ac_key_get_nbits(args ...) _pk_wrap (gcry_ac_key_get_nbits (args))
-#define gcry_ac_data_encrypt(args ...) _pk_wrap (gcry_ac_data_encrypt (args))
-#define gcry_ac_data_decrypt(args ...) _pk_wrap (gcry_ac_data_decrypt (args))
-#define gcry_ac_data_sign(args ...) _pk_wrap (gcry_ac_data_sign (args))
-#define gcry_ac_data_verify(args ...) _pk_wrap (gcry_ac_data_verify (args))
-#define gcry_ac_key_test(args ...) _pk_wrap (gcry_ac_key_test (args))
-#define gcry_ac_key_pair_generate_ext(args ...) _pk_wrap (gcry_ac_key_pair_generate_ext (args))
-#define gcry_ac_key_get_nbits(args ...) _pk_wrap (gcry_ac_key_get_nbits (args))
-#define gcry_ac_key_get_grip(args ...) _pk_wrap (gcry_ac_key_get_grip (args))
-#define gcry_ac_list(args ...) _pk_wrap (gcry_ac_list (args))
-
-
-
/* Extract an unsigned number that is expected in the S-Expression
SEXP at position IDX. */
static gcry_err_code_t
sexp_nth_number (gcry_sexp_t sexp, int idx, unsigned long int *number)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
unsigned long int number_new = 0;
const char *data = NULL;
size_t data_length = 0;
data = gcry_sexp_nth_data (sexp, idx, &data_length);
if (! data)
err = GPG_ERR_INV_OBJ;
else
{
char *buf = gcry_malloc (data_length + 1);
if (! buf)
err = GPG_ERR_INTERNAL; /* FIXME! */
else
{
memcpy (buf, data, data_length);
buf[data_length] = 0;
number_new = (unsigned int) strtoul (buf, NULL, 0);
gcry_free (buf);
}
}
if (! err)
*number = number_new;
return err;
}
static gcry_err_code_t
sexp_extract_flags (gcry_sexp_t flags_sexp, unsigned int *flags)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
unsigned int flags_sexp_length = 0;
unsigned int flags_new = 0;
const char *identifier = NULL;
size_t identifier_length = 0;
unsigned int i = 0, j = 0;
flags_sexp_length = gcry_sexp_length (flags_sexp);
for (i = 1; (i < flags_sexp_length) && (! err); i++)
{
identifier = gcry_sexp_nth_data (flags_sexp, i, &identifier_length);
if (identifier)
{
/* Iterate through list of known flags. */
for (j = 0; pk_sexp_flags[j].identifier; j++)
if ((identifier_length == strlen (pk_sexp_flags[j].identifier))
&& (! memcmp (identifier, pk_sexp_flags[j].identifier,
identifier_length)))
{
flags_new |= pk_sexp_flags[j].flag;
break;
}
if (! pk_sexp_flags[j].identifier)
/* Flag not found. */
err = GPG_ERR_INV_FLAG;
}
}
if (! err)
*flags = flags_new;
return err;
}
/* Extract the MPI values from the S-Expression contained in SEXP that
has to be of type TYPE into a newly allocated array that is to be
stored in RETARRAY; the flags contained in the S-Expression are
stored in SEXP_FLAGS; general flags specifying the mode of
operation are stored in FLAGS. A new handle for the according
algorithm is stored in HANDLE, addotinally the algorithm
information block is stored in ALGORITHM_INFO_BLOCK. */
static gcry_err_code_t
sexp_extract_std (gcry_sexp_t sexp, pk_sexp_type_t type, gcry_ac_data_t *data,
unsigned int *sexp_flags, unsigned int *flags,
gcry_ac_handle_t *handle)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_ac_handle_t handle_new = NULL;
gcry_ac_data_t data_new = NULL;
unsigned int sexp_flags_parsed = 0;
unsigned int flags_parsed = 0;
gcry_sexp_t list2 = NULL;
gcry_sexp_t list = NULL;
const char *identifier = NULL;
size_t identifier_length = 0;
gcry_ac_id_t algorithm_id = 0;
unsigned int i = 0;
/* Check that the first element is valid. */
list = gcry_sexp_find_token (sexp, pk_sexp_types[type].identifier, 0);
if (! list)
err = GPG_ERR_INV_OBJ;
if (! err)
{
/* Extract inner list. */
list2 = gcry_sexp_cadr (list);
if (! list2)
err = GPG_ERR_NO_OBJ;
}
if (! err)
{
/* Extract identifier of inner list. */
identifier = gcry_sexp_nth_data (list2, 0, &identifier_length);
if (! identifier)
err = GPG_ERR_INV_OBJ;
}
if (! err)
{
if ((identifier_length == 5) && (! memcmp (identifier, "flags", 5)))
{
/* Seems to be a `modern' S-Expression. */
flags_parsed |= PK_FLAG_MODERN;
err = sexp_extract_flags (list2, &sexp_flags_parsed);
if (! err)
{
/* Fetch the next S-Expression. */
gcry_sexp_release (list2);
list2 = gcry_sexp_nth (list, 2);
if (! list2)
err = GPG_ERR_INV_OBJ;
}
if (! err)
/* Extract identifier. */
identifier = gcry_sexp_nth_data (list2, 0, &identifier_length);
}
}
if (! err)
{
/* Convert identifier into an algorithm ID. */
char *name_terminated;
name_terminated = gcry_xmalloc (identifier_length + 1);
strncpy (name_terminated, identifier, identifier_length);
name_terminated[identifier_length] = 0;
- err = gcry_ac_name_to_id (name_terminated, &algorithm_id);
+ err = _gcry_ac_name_to_id (name_terminated, &algorithm_id);
free (name_terminated);
}
if (! err)
{
if (*handle)
{
/* There's already an according handle, therefore we check
wether the new algorithm ID matches the one of the
already opened handled. */
gcry_ac_id_t id;
_gcry_ac_info_get (*handle, &id, NULL);
if (id != algorithm_id)
err = GPG_ERR_CONFLICT;
}
else
{
/* Create new handle. */
- err = gcry_ac_open (&handle_new, algorithm_id, 0);
+ err = _gcry_ac_open (&handle_new, algorithm_id, 0);
}
}
if (! err)
/* Allocate data set for MPIs. */
- err = gcry_ac_data_new (&data_new);
+ err = _gcry_ac_data_new (&data_new);
if (! err)
{
/* Extract MPI values. */
gcry_sexp_t elem_list = NULL;
gcry_sexp_t data_list = NULL;
unsigned int data_list_n = 0;
- gcry_mpi_t mpi = NULL;
- char name[] = { 0, 0 };
size_t tmp_data_length = 0;
+ gcry_mpi_t mpi = NULL;
+ char *name;
data_list = gcry_sexp_nth (list2, 1);
if (data_list)
{
if (! gcry_sexp_nth_data (data_list, 0, &tmp_data_length))
{
/* Seems that all the data element lists are contained
in another sub list. */
i = 0;
}
else
{
data_list = list2;
i = 1;
}
}
else
err = GPG_ERR_INV_OBJ;
data_list_n = gcry_sexp_length (data_list);
for (; i < data_list_n; i++)
{
mpi = NULL;
elem_list = gcry_sexp_nth (data_list, i);
if (! elem_list)
err = GPG_ERR_INV_OBJ; /* FIXME? */
if (! err)
{
identifier = gcry_sexp_nth_data (elem_list, 0, &identifier_length);
if (identifier_length != 1)
/* FIXME? Should this be an error or should it be
ignored? */
err = GPG_ERR_INV_OBJ;
}
if (! err)
{
mpi = gcry_sexp_nth_mpi (elem_list, 1, GCRYMPI_FMT_USG);
if (! mpi)
err = GPG_ERR_INV_OBJ;
}
if (! err)
{
- name[0] = *identifier;
- err = gcry_ac_data_set (data_new, name, mpi);
+ name = gcry_malloc (identifier_length + 1);
+ if (! name)
+ err = gcry_err_code_from_errno (ENOMEM);
+ else
+ {
+ strncpy (name, identifier, identifier_length);
+ name[identifier_length] = 0;
+
+ err = _gcry_ac_data_set (data_new, GCRY_AC_FLAG_DEALLOC, name, mpi);
+ if (err)
+ gcry_free (name);
+ }
}
- if (mpi)
- gcry_mpi_release (mpi);
if (elem_list)
gcry_sexp_release (elem_list);
}
if (data_list != list2)
gcry_sexp_release (data_list);
}
if (list)
gcry_sexp_release (list);
if (list2)
gcry_sexp_release (list2);
if (! err)
{
/* Copy out. */
if (! *handle)
*handle = handle_new;
*data = data_new;
if (sexp_flags)
*sexp_flags = sexp_flags_parsed;
if (flags)
*flags = flags_parsed;
}
else
{
/* Deallocate resources. */
if (handle_new)
- gcry_ac_close (handle_new);
+ _gcry_ac_close (handle_new);
if (data_new)
- gcry_ac_data_destroy (data_new);
+ _gcry_ac_data_destroy (data_new);
}
return err;
}
static gcry_err_code_t
sexp_extract_key (gcry_sexp_t sexp, pk_key_type_t which, gcry_ac_key_t *key,
gcry_ac_handle_t *handle)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_ac_handle_t handle_new = NULL;
gcry_ac_key_t key_new = NULL;
gcry_ac_key_type_t key_type = 0;
gcry_ac_data_t data = NULL;
if ((which == PK_KEY_TYPE_PUBLIC) || (which == PK_KEY_TYPE_ANY))
{
err = sexp_extract_std (sexp, PK_SEXP_TYPE_KEY_PUBLIC, &data,
NULL, NULL, &handle_new);
if (! err)
key_type = GCRY_AC_KEY_PUBLIC;
}
if ((which == PK_KEY_TYPE_SECRET) || ((which == PK_KEY_TYPE_ANY)
&& (err == GPG_ERR_INV_OBJ)))
{
err = sexp_extract_std (sexp, PK_SEXP_TYPE_KEY_SECRET, &data,
NULL, NULL, &handle_new);
if (! err)
key_type = GCRY_AC_KEY_SECRET;
}
if (! err)
- err = gcry_ac_key_init (&key_new, handle_new, key_type, data);
+ err = _gcry_ac_key_init (&key_new, handle_new, key_type, data);
if (! err)
{
*handle = handle_new;
*key = key_new;
}
else
{
if (handle_new)
- gcry_ac_close (handle_new);
+ _gcry_ac_close (handle_new);
if (key_new)
- gcry_ac_key_destroy (key_new);
+ _gcry_ac_key_destroy (key_new);
else if (data)
- gcry_ac_data_destroy (data);
+ _gcry_ac_data_destroy (data);
}
return err;
}
/* Convert a `data'-S-Expression into an MPI value, suitable for
passing to the low level functions. Two different styles for the
input S-Expression are supported: to use the `old' style, the input
S-Expression must simply consist of a single MPI value;
`modern'-style S-Expression follow a more complex structure:
(data
[(flags <flag identifiers>)]
[(hash <algorithm identifier> <text>)]
[(value <value>)])
For encryption, the `value'-S-Expression must be present. For
non-encryption-data (i.e. for signatures) either the `value'- or
the `hash'-S-Expression must be present (the latter one has higher
priority). */
static gcry_err_code_t
sexp_extract_data (gcry_sexp_t data_sexp, gcry_ac_handle_t handle,
gcry_ac_key_t key, gcry_mpi_t *data,
unsigned int for_encryption, unsigned int *flags)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_sexp_t data_sexp_inner = NULL;
gcry_mpi_t data_new = NULL;
unsigned int flags_parsed = 0;
data_sexp_inner = gcry_sexp_find_token (data_sexp, "data", 0);
if (! data_sexp_inner)
{
/* Assume old style. */
data_new = gcry_sexp_nth_mpi (data_sexp, 0, 0);
if (! data_new)
err = GPG_ERR_INV_OBJ;
}
else
{
/* Assume modern style. */
gcry_sexp_t flags_sexp = NULL;
gcry_sexp_t hash_sexp = NULL;
gcry_sexp_t value_sexp = NULL;
unsigned int i = 0;
unsigned int nbits = 0;
- err = gcry_ac_key_get_nbits (handle, key, &nbits);
+ err = _gcry_ac_key_get_nbits (handle, key, &nbits);
if (! err)
{
flags_sexp = gcry_sexp_find_token (data_sexp_inner, "flags", 0);
if (flags_sexp)
{
err = sexp_extract_flags (flags_sexp, &flags_parsed);
gcry_sexp_release (flags_sexp);
}
}
if (! err)
{
if (! (flags_parsed & (PK_SEXP_FLAG_PKCS1_V1_5 | PK_SEXP_FLAG_RAW)))
/* Default to `raw'. */
flags_parsed |= PK_SEXP_FLAG_RAW;
/* Get `hash'- or `value'-S-Expression. */
hash_sexp = gcry_sexp_find_token (data_sexp_inner, "hash", 0);
if (! hash_sexp)
value_sexp = gcry_sexp_find_token (data_sexp_inner, "value", 0);
if (! ((! hash_sexp) ^ (! value_sexp)))
/* None or both given. */
err = GPG_ERR_INV_OBJ;
else if (1
&& (flags_parsed & PK_SEXP_FLAG_PKCS1_V1_5)
&& (flags_parsed & PK_SEXP_FLAG_RAW)
&& (! for_encryption))
err = GPG_ERR_CONFLICT;
else if ((flags_parsed & PK_SEXP_FLAG_RAW) && value_sexp)
{
/* Raw value, this can be used for both, signing and
encryption. */
data_new = gcry_sexp_nth_mpi (value_sexp, 1, 0);
if (! data_new)
err = GPG_ERR_INV_OBJ;
}
else if (1
&& (flags_parsed & PK_SEXP_FLAG_PKCS1_V1_5)
&& value_sexp
&& for_encryption)
{
/* Create PKCS#1 block type 2 padding. Only used for
encryption. */
unsigned char *frame = NULL;
size_t nframe = (nbits + 7) / 8;
const void *value;
size_t valuelen;
unsigned char *p;
value = gcry_sexp_nth_data (value_sexp, 1, &valuelen);
if (! (value && valuelen))
err = GPG_ERR_INV_OBJ;
else if ((valuelen + 7 > nframe) || (! nframe))
/* Can't encode a VALUELEN value in a NFRAME bytes
frame. The key is too short. */
err = GPG_ERR_TOO_SHORT;
else if (! (frame = gcry_malloc_secure (nframe)))
err = gcry_err_code_from_errno (errno);
else
{
unsigned int n = 0;
frame[n++] = 0;
frame[n++] = 2; /* Block type. */
i = nframe - 3 - valuelen;
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)
/* Okay, no (more) zero bytes. */
break;
k += k/128; /* Better get some more. */
pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
for (j = 0; j < i && k; j++)
{
if (! p[j])
p[j] = pp[--k];
}
gcry_free (pp);
}
memcpy (frame + n, p, i);
n += i;
gcry_free (p);
frame[n++] = 0;
memcpy (frame + n, value, valuelen);
n += valuelen;
assert (n == nframe);
/* FIXME, error checking? */
gcry_mpi_scan (&data_new, GCRYMPI_FMT_USG, frame, n, &nframe);
}
gcry_free (frame);
}
else if (1
&& (flags_parsed & PK_SEXP_FLAG_PKCS1_V1_5)
&& hash_sexp
&& (! for_encryption))
{
/* Create PKCS#1 block type 1 padding. Only used for
signing. */
const char *identifier = NULL;
size_t identifier_length = 0;
if (gcry_sexp_length (hash_sexp) != 3)
err = GPG_ERR_INV_OBJ;
if (! err)
{
identifier = gcry_sexp_nth_data (hash_sexp, 1, &identifier_length);
if (! identifier_length)
err = GPG_ERR_INV_OBJ;
}
if (! err)
{
static struct
{
const char *name;
int algo;
} hashnames[] =
{
{ "sha1", GCRY_MD_SHA1 },
{ "md5", GCRY_MD_MD5 },
{ "rmd160", GCRY_MD_RMD160 },
{ "sha256", GCRY_MD_SHA256 },
{ "sha384", GCRY_MD_SHA384 },
{ "sha512", GCRY_MD_SHA512 },
{ "md2", GCRY_MD_MD2 },
{ "md4", GCRY_MD_MD4 },
{ "tiger", GCRY_MD_TIGER },
{ "haval", GCRY_MD_HAVAL },
{ NULL }
};
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) == identifier_length)
&& (! memcmp (hashnames[i].name, identifier,
identifier_length)))
break;
algo = hashnames[i].algo;
asnlen = DIM (asn);
dlen = gcry_md_get_algo_dlen (algo);
if (! hashnames[i].name)
err = GPG_ERR_DIGEST_ALGO;
else if (! ((value = gcry_sexp_nth_data (hash_sexp, 2,
&valuelen))
&& valuelen))
err = GPG_ERR_INV_OBJ;
else if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn,
&asnlen))
/* We don't have all of the above algorithms. */
err = GPG_ERR_NOT_IMPLEMENTED;
else if (valuelen != dlen)
/* Hash value does not match the length of digest for
the given algorithm. */
err = GPG_ERR_CONFLICT;
else if ((! dlen) || (dlen + asnlen + 4 > nframe))
/* Can't encode an DLEN byte digest MD into a NFRAME
byte frame. */
err = GPG_ERR_TOO_SHORT;
else if (! (frame = gcry_malloc (nframe)))
err = gcry_err_code_from_errno (errno);
else
{
/* Assemble the PKCS#1-V1_5 block type 1. */
unsigned int n = 0;
frame[n++] = 0;
frame[n++] = 1; /* Block type. */
i = nframe - valuelen - asnlen - 3 ;
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;
assert (n == nframe);
/* Convert it into an MPI, FIXME: error checking? */
gcry_mpi_scan (&data_new, GCRYMPI_FMT_USG, frame, n, &nframe);
}
gcry_free (frame);
}
}
else
err = GPG_ERR_CONFLICT;
if (data_sexp_inner)
gcry_sexp_release (data_sexp_inner);
if (hash_sexp)
gcry_sexp_release (hash_sexp);
if (value_sexp)
gcry_sexp_release (value_sexp);
}
}
if (! err)
{
*data = data_new;
if (flags)
*flags = flags_parsed;
}
return err;
}
/* sexp_construct and sexp_extract operate on S-Expressions of the
following form:
(<sexp identifier>
(<algorithm identifier>
[(flags <flag identifiers>)]
(<mpi identifier 0> <mpi value 0>)
...)) */
/* Construct a new S-Expression that is to be stored in SEXP. TYPE
specifies the type of the S-Expression; ARRAY contains MPI values
that are to be inserted into the S-Expression; ALGORITHM_INFO is
used for looking up properties according to TYPE. */
static gcry_err_code_t
sexp_construct_std (gcry_sexp_t *sexp, pk_sexp_type_t type,
gcry_ac_handle_t handle, gcry_ac_data_t data)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
const char *algorithm_name = NULL;
gcry_ac_id_t algorithm_id = 0;
char *format_string = NULL;
unsigned int elements_n = 0;
gcry_sexp_t sexp_new = NULL;
const char *name = NULL;
void **arg_list = NULL;
size_t size = 0;
unsigned int i;
/* Figure out algorithm name. */
_gcry_ac_info_get (handle, &algorithm_id, NULL);
- err = gcry_ac_id_to_name (algorithm_id, &algorithm_name);
+ err = _gcry_ac_id_to_name (algorithm_id, &algorithm_name);
if (! err)
{
/* Calc. */
- elements_n = gcry_ac_data_length (data);
+ elements_n = _gcry_ac_data_length (data);
size = 5 + strlen (pk_sexp_types[type].identifier) + (elements_n * 5);
size += strlen (algorithm_name);
/* Allocate. */
format_string = gcry_malloc (size);
if (! format_string)
err = GPG_ERR_INTERNAL; /* FIXME! */
}
if (! err)
{
/* Construct format string. */
char *p = format_string;
p += sprintf (p, "(%s(%s",
pk_sexp_types[type].identifier, algorithm_name);
for (i = 0; i < elements_n && (! err); i++)
{
- err = gcry_ac_data_get_index (data, i, &name, NULL);
+ err = _gcry_ac_data_get_index (data, 0, i, &name, NULL);
if (! err)
p += sprintf (p, "(%s%%m)", name);
}
p += sprintf (p, "))");
}
if (! err)
/* Construct argument list. */
err = _gcry_ac_arg_list_from_data (data, &arg_list);
if (! err)
/* Construct S-Expression. */
err = gcry_sexp_build_array (&sexp_new, NULL, format_string, arg_list);
/* Deallocate resources. */
if (format_string)
gcry_free (format_string);
if (arg_list)
gcry_free (arg_list);
if (! err)
/* Copy out. */
*sexp = sexp_new;
return err;
}
static gcry_err_code_t
sexp_mpi_arg_list_create (gcry_mpi_t *mpis, void ***arg_list)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
void **arg_list_new = NULL;
unsigned int i = 0;
/* Count. */
for (i = 0; mpis[i]; i++);
/* Allocate. */
arg_list_new = gcry_malloc (sizeof (void *) * i);
if (! arg_list_new)
err = GPG_ERR_INTERNAL; /* FIXME. */
if (! err)
/* Fill. */
for (i = 0; mpis[i]; i++)
arg_list_new[0] = (void *) &mpis[i];
if (! err)
*arg_list = arg_list_new;
else
{
if (arg_list_new)
gcry_free (arg_list_new);
}
return err;
}
static gcry_err_code_t
sexp_construct_factors (gcry_sexp_t *sexp, gcry_mpi_t *factors)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_sexp_t sexp_new = NULL;
unsigned int factors_n = 0;
char *format_string = NULL;
void **arg_list = NULL;
size_t size = 0;
err = sexp_mpi_arg_list_create (factors, &arg_list);
if (! err)
{
/* Calculate length and allocate format string. */
for (factors_n = 0; factors[factors_n]; factors_n++);
size += 30 + factors_n * 2;
format_string = gcry_malloc (size);
if (! format_string)
err = GPG_ERR_INTERNAL; /* FIXME! */
}
if (! err)
{
/* Construct format string. */
unsigned char *p = format_string;
unsigned int i = 0;
p += sprintf (p, "(misc-key-info(pm1-factors");
for (i = 0; i < factors_n; i++)
p += sprintf (p, "%m");
p += sprintf (p, "))");
err = gcry_sexp_build_array (&sexp_new, NULL, format_string, arg_list);
}
if (format_string)
gcry_free (format_string);
if (arg_list)
gcry_free (arg_list);
if (! err)
*sexp = sexp_new;
return err;
}
static gcry_err_code_t
sexp_construct_genkey (gcry_sexp_t *genkey_sexp,
gcry_ac_handle_t handle,
gcry_ac_key_pair_t key_pair, gcry_mpi_t *misc_data)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_sexp_t genkey_sexp_new = NULL;
gcry_sexp_t key_public_sexp = NULL;
gcry_sexp_t key_secret_sexp = NULL;
gcry_sexp_t key_factors_sexp = NULL;
gcry_ac_data_t key_public = NULL;
gcry_ac_data_t key_secret = NULL;
char *format_string = NULL;
size_t size = 0;
- key_public = gcry_ac_key_data_get (gcry_ac_key_pair_extract (key_pair,
+ key_public = _gcry_ac_key_data_get (_gcry_ac_key_pair_extract (key_pair,
GCRY_AC_KEY_PUBLIC));
- key_secret = gcry_ac_key_data_get (gcry_ac_key_pair_extract (key_pair,
+ key_secret = _gcry_ac_key_data_get (_gcry_ac_key_pair_extract (key_pair,
GCRY_AC_KEY_SECRET));
err = sexp_construct_std (&key_public_sexp, PK_SEXP_TYPE_KEY_PUBLIC,
handle, key_public);
if (! err)
err = sexp_construct_std (&key_secret_sexp, PK_SEXP_TYPE_KEY_SECRET,
handle, key_secret);
if (! err)
if (misc_data)
err = sexp_construct_factors (&key_factors_sexp, misc_data);
if (! err)
{
/* Calculate size and allocate format string. */
size += 11;
size += gcry_sexp_sprint (key_public_sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
size += gcry_sexp_sprint (key_secret_sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
if (key_factors_sexp)
size += gcry_sexp_sprint (key_factors_sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
format_string = gcry_malloc (size);
if (! format_string)
err = GPG_ERR_INTERNAL; /* FIXME! */
}
if (! err)
{
char *p = format_string;
p += sprintf (p, "(key-data");
p += gcry_sexp_sprint (key_public_sexp, GCRYSEXP_FMT_ADVANCED, p,
size - (p - format_string)) - 1;
p += gcry_sexp_sprint (key_secret_sexp, GCRYSEXP_FMT_ADVANCED, p,
size - (p - format_string)) - 1;
if (key_factors_sexp)
p += gcry_sexp_sprint (key_factors_sexp, GCRYSEXP_FMT_ADVANCED, p,
size - (p - format_string)) - 1;
p += sprintf (p, ")");
err = gcry_sexp_build (&genkey_sexp_new, NULL, format_string);
}
if (format_string)
gcry_free (format_string);
if (key_public_sexp)
gcry_sexp_release (key_public_sexp);
if (key_secret_sexp)
gcry_sexp_release (key_secret_sexp);
if (key_factors_sexp)
gcry_sexp_release (key_factors_sexp);
if (! err)
*genkey_sexp = genkey_sexp_new;
else
{
if (genkey_sexp_new)
gcry_sexp_release (genkey_sexp_new);
}
return err;
}
/* Map a string to the algorithm ID. */
int
gcry_pk_map_name (const char *string)
{
gcry_ac_id_t algorithm_id = 0;
- gcry_ac_name_to_id (string, &algorithm_id);
+ _gcry_ac_name_to_id (string, &algorithm_id);
return algorithm_id;
}
/* Map an algorithm ID to it's name. */
const char *
gcry_pk_algo_name (int algorithm)
{
const char *algorithm_name = NULL;
- gcry_ac_id_to_name (algorithm, &algorithm_name);
+ _gcry_ac_id_to_name (algorithm, &algorithm_name);
return algorithm_name;
}
/*
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 *data_encrypted_sexp,
gcry_sexp_t data_plain_sexp,
gcry_sexp_t key_public_sexp)
{
gcry_sexp_t data_encrypted_sexp_new = NULL;
gcry_ac_data_t data_encrypted = NULL;
gcry_ac_key_t key_public = NULL;
gcry_mpi_t data_plain = NULL;
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_ac_handle_t handle = NULL;
/* Extract key. */
err = sexp_extract_key (key_public_sexp, PK_KEY_TYPE_PUBLIC,
&key_public, &handle);
if (! err)
/* Extract plain data. */
err = sexp_extract_data (data_plain_sexp, handle, key_public,
&data_plain, 1, NULL);
if (! err)
/* Encrypt. */
- err = gcry_ac_data_encrypt (handle, 0, key_public, data_plain,
+ err = _gcry_ac_data_encrypt (handle, 0, key_public, data_plain,
&data_encrypted);
if (! err)
/* Build the return list. */
err = sexp_construct_std (&data_encrypted_sexp_new, PK_SEXP_TYPE_ENCRYPTION,
handle, data_encrypted);
/* Deallocate resources. */
if (handle)
- gcry_ac_close (handle);
+ _gcry_ac_close (handle);
if (key_public)
- gcry_ac_key_destroy (key_public);
+ _gcry_ac_key_destroy (key_public);
if (data_plain)
gcry_mpi_release (data_plain);
if (data_encrypted)
- gcry_ac_data_destroy (data_encrypted);
+ _gcry_ac_data_destroy (data_encrypted);
if (! err)
*data_encrypted_sexp = data_encrypted_sexp_new;
else
{
if (data_encrypted_sexp_new)
gcry_sexp_release (data_encrypted_sexp_new);
}
return gcry_error (err);
}
/****************
* 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 *data_decrypted_sexp,
gcry_sexp_t data_encrypted_sexp,
gcry_sexp_t key_secret_sexp)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_sexp_t data_decrypted_sexp_new = NULL;
gcry_ac_data_t data_encrypted = NULL;
gcry_mpi_t data_decrypted = NULL;
gcry_ac_key_t key_secret = NULL;
gcry_ac_handle_t handle = NULL;
unsigned int sexp_flags_data = 0;
unsigned int ac_flags = 0;
unsigned int flags = 0;
/* Extract key. */
err = sexp_extract_key (key_secret_sexp, PK_KEY_TYPE_SECRET,
&key_secret, &handle);
if (! err)
{
/* Extract encrypted data. */
err = sexp_extract_std (data_encrypted_sexp, PK_SEXP_TYPE_ENCRYPTION,
&data_encrypted, &sexp_flags_data, &flags,
&handle);
if (! err)
{
/* Convert flags. */
if (sexp_flags_data & PK_SEXP_FLAG_NO_BLINDING)
- ac_flags |= GCRY_AC_FLAG_DATA_NO_BLINDING;
+ ac_flags |= GCRY_AC_FLAG_NO_BLINDING;
}
}
if (! err)
/* Decrypt. */
- err = gcry_ac_data_decrypt (handle, ac_flags, key_secret,
+ err = _gcry_ac_data_decrypt (handle, ac_flags, key_secret,
&data_decrypted, data_encrypted);
if (! err)
{
/* Build the return list. */
if (flags & PK_FLAG_MODERN)
err = gcry_sexp_build (&data_decrypted_sexp_new, NULL,
"(value %m)", data_decrypted);
else
err = gcry_sexp_build (&data_decrypted_sexp_new, NULL,
"%m", data_decrypted);
}
/* Deallocate resources. */
if (handle)
- gcry_ac_close (handle);
+ _gcry_ac_close (handle);
if (key_secret)
- gcry_ac_key_destroy (key_secret);
+ _gcry_ac_key_destroy (key_secret);
if (data_decrypted)
gcry_mpi_release (data_decrypted);
if (data_encrypted)
- gcry_ac_data_destroy (data_encrypted);
+ _gcry_ac_data_destroy (data_encrypted);
if (! err)
*data_decrypted_sexp = data_decrypted_sexp_new;
else
{
if (data_decrypted_sexp_new)
gcry_sexp_release (data_decrypted_sexp_new);
}
return gcry_error (err);
}
/****************
* 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>)
* )) */
gcry_error_t
gcry_pk_sign (gcry_sexp_t *data_signed_sexp,
gcry_sexp_t data_sexp,
gcry_sexp_t key_secret_sexp)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_sexp_t data_signed_sexp_new = NULL;
gcry_ac_data_t data_signed = NULL;
gcry_ac_key_t key_secret = NULL;
gcry_ac_handle_t handle = NULL;
gcry_mpi_t data = NULL;
*data_signed_sexp = NULL;
/* Extract key. */
err = sexp_extract_key (key_secret_sexp, PK_KEY_TYPE_SECRET,
&key_secret, &handle);
if (! err)
/* Extract data. */
err = sexp_extract_data (data_sexp, handle, key_secret,
&data, 0, NULL);
if (! err)
/* Sign data. */
- err = gcry_ac_data_sign (handle, key_secret, data, &data_signed);
+ err = _gcry_ac_data_sign (handle, key_secret, data, &data_signed);
if (! err)
/* Build the return list. */
err = sexp_construct_std (&data_signed_sexp_new, PK_SEXP_TYPE_SIGNATURE,
handle, data_signed);
/* Deallocate resources. */
if (handle)
- gcry_ac_close (handle);
+ _gcry_ac_close (handle);
if (key_secret)
- gcry_ac_key_destroy (key_secret);
+ _gcry_ac_key_destroy (key_secret);
if (data_signed)
- gcry_ac_data_destroy (data_signed);
+ _gcry_ac_data_destroy (data_signed);
if (data)
gcry_mpi_release (data);
if (! err)
*data_signed_sexp = data_signed_sexp_new;
else
{
if (data_signed_sexp_new)
gcry_sexp_release (data_signed_sexp_new);
}
return gcry_error (err);
}
/****************
* 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 data_signed_sexp,
gcry_sexp_t data_sexp,
gcry_sexp_t key_public_sexp)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_ac_data_t data_signed = NULL;
gcry_ac_key_t key_public = NULL;
gcry_ac_handle_t handle = NULL;
gcry_mpi_t data = NULL;
/* Extract key. */
err = sexp_extract_key (key_public_sexp, PK_KEY_TYPE_PUBLIC,
&key_public, &handle);
if (! err)
/* Extract signed data. */
err = sexp_extract_std (data_signed_sexp, PK_SEXP_TYPE_SIGNATURE,
&data_signed, NULL, NULL, &handle);
if (! err)
/* Extract data. */
err = sexp_extract_data (data_sexp, handle, key_public, &data, 0, NULL);
if (! err)
/* Verify signature. */
- err = gcry_ac_data_verify (handle, key_public, data, data_signed);
+ err = _gcry_ac_data_verify (handle, key_public, data, data_signed);
/* Deallocate resources. */
if (handle)
- gcry_ac_close (handle);
+ _gcry_ac_close (handle);
if (key_public)
- gcry_ac_key_destroy (key_public);
+ _gcry_ac_key_destroy (key_public);
if (data)
gcry_mpi_release (data);
if (data_signed)
- gcry_ac_data_destroy (data_signed);
+ _gcry_ac_data_destroy (data_signed);
return gcry_error (err);
}
/* Test a key. */
gcry_error_t
gcry_pk_testkey (gcry_sexp_t key_secret_sexp)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_ac_handle_t handle = NULL;
gcry_ac_key_t key_secret = NULL;
/* Extract key. */
err = sexp_extract_key (key_secret_sexp, PK_KEY_TYPE_SECRET,
&key_secret, &handle);
if (! err)
/* Check. */
- err = gcry_ac_key_test (handle, key_secret);
+ err = _gcry_ac_key_test (handle, key_secret);
/* Deallocate resources. */
if (handle)
- gcry_ac_close (handle);
+ _gcry_ac_close (handle);
if (key_secret)
- gcry_ac_key_destroy (key_secret);
+ _gcry_ac_key_destroy (key_secret);
return gcry_error (err);
}
/****************
* 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 *key_pair_sexp, gcry_sexp_t key_spec)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_ac_handle_t handle = NULL;
gcry_sexp_t key_pair_sexp_new = NULL;
gcry_ac_key_pair_t key_pair = NULL;
gcry_mpi_t *misc_data = NULL;
unsigned long int nbits = 0;
gcry_ac_key_spec_rsa_t spec_rsa = { 65537 };
void *spec = NULL;
gcry_sexp_t list = NULL;
gcry_sexp_t list2 = NULL;
const char *identifier = NULL;
size_t identifier_length = 0;
gcry_ac_id_t algorithm_id = 0;
*key_pair_sexp = NULL;
list = gcry_sexp_find_token (key_spec, "genkey", 0);
if (! list)
/* Does not contain genkey data. */
err = GPG_ERR_INV_OBJ;
if (! err)
{
/* Extract inner list. */
list2 = gcry_sexp_cadr (list);
if (list2)
{
gcry_sexp_release (list);
list = list2;
list2 = NULL;
}
else
/* No cdr for the genkey. */
err = GPG_ERR_NO_OBJ;
}
if (! err)
{
/* Extract algorithm name. */
identifier = gcry_sexp_nth_data (list, 0, &identifier_length);
if (! identifier)
err = GPG_ERR_INV_OBJ;
}
if (! err)
{
/* Convert identifier into an algorithm ID. */
char *name_terminated;
name_terminated = gcry_xmalloc (identifier_length + 1);
strncpy (name_terminated, identifier, identifier_length);
name_terminated[identifier_length] = 0;
- err = gcry_ac_name_to_id (name_terminated, &algorithm_id);
+ err = _gcry_ac_name_to_id (name_terminated, &algorithm_id);
free (name_terminated);
}
if (! err)
- err = gcry_ac_open (&handle, algorithm_id, 0);
+ err = _gcry_ac_open (&handle, algorithm_id, 0);
if (! err)
{
/* RSA special case. */
list2 = gcry_sexp_find_token (list, "rsa-use-e", 0);
if (list2)
{
spec = (void *) &spec_rsa;
err = sexp_nth_number (list2, 1, &spec_rsa.e);
gcry_sexp_release (list2);
list2 = NULL;
}
}
if (! err)
{
/* Extract nbits. */
list2 = gcry_sexp_find_token (list, "nbits", 0);
if (list2)
{
err = sexp_nth_number (list2, 1, &nbits);
gcry_sexp_release (list2);
list2 = NULL;
}
else
err = GPG_ERR_NO_OBJ;
}
if (! err)
/* Generate key pair. */
- err = gcry_ac_key_pair_generate_ext (handle, (unsigned int) nbits, spec,
- &key_pair, &misc_data);
+ err = _gcry_ac_key_pair_generate (handle, (unsigned int) nbits, spec,
+ &key_pair, &misc_data);
if (! err)
/* Construct return list. */
err = sexp_construct_genkey (&key_pair_sexp_new, handle,
key_pair, misc_data);
/* Deallocate resources. */
if (handle)
- gcry_ac_close (handle);
+ _gcry_ac_close (handle);
if (key_pair)
- gcry_ac_key_pair_destroy (key_pair);
+ _gcry_ac_key_pair_destroy (key_pair);
if (misc_data)
gcry_free (misc_data);
if (list2)
gcry_sexp_release (list2);
if (list)
gcry_sexp_release (list);
if (! err)
*key_pair_sexp = key_pair_sexp_new;
return gcry_error (err);
}
/* Get the number of nbits from the public key. */
unsigned int
gcry_pk_get_nbits (gcry_sexp_t key_sexp)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_ac_handle_t handle = NULL;
gcry_ac_key_t key = NULL;
unsigned int nbits = 0;
/* Extract key. */
err = sexp_extract_key (key_sexp, PK_KEY_TYPE_ANY, &key, &handle);
if (! err)
- err = gcry_ac_key_get_nbits (handle, key, &nbits);
+ err = _gcry_ac_key_get_nbits (handle, key, &nbits);
if (handle)
- gcry_ac_close (handle);
+ _gcry_ac_close (handle);
if (key)
- gcry_ac_key_destroy (key);
+ _gcry_ac_key_destroy (key);
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_sexp, unsigned char *key_grip)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_ac_handle_t handle = NULL;
gcry_ac_key_t key = NULL;
err = sexp_extract_key (key_sexp, PK_KEY_TYPE_ANY, &key, &handle);
if (! err)
- err = gcry_ac_key_get_grip (handle, key, key_grip);
+ err = _gcry_ac_key_get_grip (handle, key, key_grip);
if (handle)
- gcry_ac_close (handle);
+ _gcry_ac_close (handle);
if (key)
- gcry_ac_key_destroy (key);
+ _gcry_ac_key_destroy (key);
return err ? NULL : key_grip;
}
gcry_error_t
gcry_pk_ctl (int cmd, void *buffer, size_t buflen)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_ac_handle_t handle = NULL;
switch (cmd)
{
case GCRYCTL_DISABLE_ALGO:
/* This one expects a buffer pointing to an integer with the
algorithm ID. */
if ((! buffer) || (buflen != sizeof (int)))
err = GPG_ERR_CIPHER_ALGO;
else
{
- err = gcry_ac_open (&handle, *((int *) buffer), 0);
+ err = _gcry_ac_open (&handle, *((int *) buffer), 0);
if (! err)
{
_gcry_ac_algorithm_disable (handle);
- gcry_ac_close (handle);
+ _gcry_ac_close (handle);
}
}
default:
err = GPG_ERR_INV_OP;
}
return gcry_error (err);
}
/****************
* Return information about the given algorithm
* WHAT select 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 *number)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_ac_handle_t handle = NULL;
size_t number_new = 0;
- err = gcry_ac_open (&handle, algorithm, 0);
+ err = _gcry_ac_open (&handle, algorithm, 0);
if (! err)
switch (what)
{
case GCRYCTL_TEST_ALGO:
{
int use = number ? *number : 0;
if (buffer)
err = GPG_ERR_INV_ARG;
else
{
unsigned int use_flags;
_gcry_ac_info_get (handle, NULL, &use_flags);
if ((use & use_flags) != use)
err = GPG_ERR_PUBKEY_ALGO;
}
break;
}
case GCRYCTL_GET_ALGO_USAGE:
{
_gcry_ac_info_get (handle, NULL, &number_new);
break;
}
case GCRYCTL_GET_ALGO_NPKEY:
{
_gcry_ac_elements_amount_get (handle,
NULL, &number_new,
NULL, NULL);
break;
}
case GCRYCTL_GET_ALGO_NSKEY:
{
_gcry_ac_elements_amount_get (handle,
&number_new, NULL,
NULL, NULL);
break;
}
case GCRYCTL_GET_ALGO_NSIGN:
{
_gcry_ac_elements_amount_get (handle,
NULL, NULL,
NULL, &number_new);
break;
}
case GCRYCTL_GET_ALGO_NENCR:
{
_gcry_ac_elements_amount_get (handle,
NULL, NULL,
&number_new, NULL);
break;
}
default:
err = GPG_ERR_INV_OP;
}
if (handle)
- gcry_ac_close (handle);
+ _gcry_ac_close (handle);
if (number_new)
*number = number_new;
return gcry_error (err);
}
/* 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;
- err = gcry_ac_list (list, list_length);
+ err = _gcry_ac_list (list, list_length);
return gcry_error (err);
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Jul 8, 12:20 PM (1 d, 14 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
cb/9e/9b55fafac376374efb407adb83fb
Attached To
rC libgcrypt
Event Timeline
Log In to Comment