Page MenuHome GnuPG

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/cipher/dsa.c b/cipher/dsa.c
index 55805e21..7652c19f 100644
--- a/cipher/dsa.c
+++ b/cipher/dsa.c
@@ -1,1129 +1,1163 @@
/* dsa.c - DSA signature algorithm
* Copyright (C) 1998, 2000, 2001, 2002, 2003,
* 2006, 2008 Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
#include "pubkey-internal.h"
typedef struct
{
gcry_mpi_t p; /* prime */
gcry_mpi_t q; /* group order */
gcry_mpi_t g; /* group generator */
gcry_mpi_t y; /* g^x mod p */
} DSA_public_key;
typedef struct
{
gcry_mpi_t p; /* prime */
gcry_mpi_t q; /* group order */
gcry_mpi_t g; /* group generator */
gcry_mpi_t y; /* g^x mod p */
gcry_mpi_t x; /* secret exponent */
} DSA_secret_key;
/* A structure used to hold domain parameters. */
typedef struct
{
gcry_mpi_t p; /* prime */
gcry_mpi_t q; /* group order */
gcry_mpi_t g; /* group generator */
} dsa_domain_t;
/* A sample 1024 bit DSA key used for the selftests. */
static const char sample_secret_key[] =
"(private-key"
" (dsa"
" (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB"
" 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191"
" CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44"
" 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D8777B#)"
" (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)"
" (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503"
" AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E"
" B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984"
" 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15#)"
" (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46"
" A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827"
" 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20"
" 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)"
" (x #11D54E4ADBD3034160F2CED4B7CD292A4EBF3EC0#)))";
/* A sample 1024 bit DSA key used for the selftests (public only). */
static const char sample_public_key[] =
"(public-key"
" (dsa"
" (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB"
" 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191"
" CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44"
" 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D8777B#)"
" (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)"
" (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503"
" AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E"
" B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984"
" 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15#)"
" (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46"
" A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827"
" 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20"
" 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)))";
static int test_keys (DSA_secret_key *sk, unsigned int qbits);
static int check_secret_key (DSA_secret_key *sk);
static gpg_err_code_t generate (DSA_secret_key *sk,
unsigned int nbits,
unsigned int qbits,
int transient_key,
dsa_domain_t *domain,
gcry_mpi_t **ret_factors);
static void sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input,
DSA_secret_key *skey);
static int verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input,
DSA_public_key *pkey);
static void (*progress_cb) (void *,const char *, int, int, int );
static void *progress_cb_data;
void
_gcry_register_pk_dsa_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, "pk_dsa", c, 0, 0);
}
/* Check that a freshly generated key actually works. Returns 0 on success. */
static int
test_keys (DSA_secret_key *sk, unsigned int qbits)
{
int result = -1; /* Default to failure. */
DSA_public_key pk;
gcry_mpi_t data = gcry_mpi_new (qbits);
gcry_mpi_t sig_a = gcry_mpi_new (qbits);
gcry_mpi_t sig_b = gcry_mpi_new (qbits);
/* Put the relevant parameters into a public key structure. */
pk.p = sk->p;
pk.q = sk->q;
pk.g = sk->g;
pk.y = sk->y;
/* Create a random plaintext. */
gcry_mpi_randomize (data, qbits, GCRY_WEAK_RANDOM);
/* Sign DATA using the secret key. */
sign (sig_a, sig_b, data, sk);
/* Verify the signature using the public key. */
if ( !verify (sig_a, sig_b, data, &pk) )
goto leave; /* Signature does not match. */
/* Modify the data and check that the signing fails. */
gcry_mpi_add_ui (data, data, 1);
if ( verify (sig_a, sig_b, data, &pk) )
goto leave; /* Signature matches but should not. */
result = 0; /* The test succeeded. */
leave:
gcry_mpi_release (sig_b);
gcry_mpi_release (sig_a);
gcry_mpi_release (data);
return result;
}
/*
Generate a DSA key pair with a key of size NBITS. If transient_key
is true the key is generated using the standard RNG and not the
very secure one.
Returns: 2 structures filled with all needed values
and an array with the n-1 factors of (p-1)
*/
static gpg_err_code_t
generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
int transient_key, dsa_domain_t *domain, gcry_mpi_t **ret_factors )
{
gcry_mpi_t p; /* the prime */
gcry_mpi_t q; /* the 160 bit prime factor */
gcry_mpi_t g; /* the generator */
gcry_mpi_t y; /* g^x mod p */
gcry_mpi_t x; /* the secret exponent */
gcry_mpi_t h, e; /* helper */
unsigned char *rndbuf;
gcry_random_level_t random_level;
if (qbits)
; /* Caller supplied qbits. Use this value. */
else if ( nbits >= 512 && nbits <= 1024 )
qbits = 160;
else if ( nbits == 2048 )
qbits = 224;
else if ( nbits == 3072 )
qbits = 256;
else if ( nbits == 7680 )
qbits = 384;
else if ( nbits == 15360 )
qbits = 512;
else
return GPG_ERR_INV_VALUE;
if (qbits < 160 || qbits > 512 || (qbits%8) )
return GPG_ERR_INV_VALUE;
if (nbits < 2*qbits || nbits > 15360)
return GPG_ERR_INV_VALUE;
if (fips_mode ())
{
if (nbits < 1024)
return GPG_ERR_INV_VALUE;
if (transient_key)
return GPG_ERR_INV_VALUE;
}
if (domain->p && domain->q && domain->g)
{
/* Domain parameters are given; use them. */
p = mpi_copy (domain->p);
q = mpi_copy (domain->q);
g = mpi_copy (domain->g);
gcry_assert (mpi_get_nbits (p) == nbits);
gcry_assert (mpi_get_nbits (q) == qbits);
h = mpi_alloc (0);
e = NULL;
}
else
{
/* Generate new domain parameters. */
p = _gcry_generate_elg_prime (1, nbits, qbits, NULL, ret_factors);
/* Get q out of factors. */
q = mpi_copy ((*ret_factors)[0]);
gcry_assert (mpi_get_nbits (q) == qbits);
/* Find a generator g (h and e are helpers).
e = (p-1)/q */
e = mpi_alloc (mpi_get_nlimbs (p));
mpi_sub_ui (e, p, 1);
mpi_fdiv_q (e, e, q);
g = mpi_alloc (mpi_get_nlimbs (p));
h = mpi_alloc_set_ui (1); /* (We start with 2.) */
do
{
mpi_add_ui (h, h, 1);
/* g = h^e mod p */
gcry_mpi_powm (g, h, e, p);
}
while (!mpi_cmp_ui (g, 1)); /* Continue until g != 1. */
}
/* Select a random number X with the property:
* 0 < x < q-1
*
* FIXME: Why do we use the requirement x < q-1 ? It should be
* sufficient to test for x < q. FIPS-186-3 check x < q-1 but it
* does not check for 0 < x because it makes sure that Q is unsigned
* and finally adds one to the result so that 0 will never be
* returned. We should replace the code below with _gcry_dsa_gen_k.
*
* This must be a very good random number because this is the secret
* part. The random quality depends on the transient_key flag. */
random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
if (DBG_CIPHER)
log_debug("choosing a random x%s", transient_key? " (transient-key)":"");
gcry_assert( qbits >= 160 );
x = mpi_alloc_secure( mpi_get_nlimbs(q) );
mpi_sub_ui( h, q, 1 ); /* put q-1 into h */
rndbuf = NULL;
do
{
if( DBG_CIPHER )
progress('.');
if( !rndbuf )
rndbuf = gcry_random_bytes_secure ((qbits+7)/8, random_level);
else
{ /* Change only some of the higher bits (= 2 bytes)*/
char *r = gcry_random_bytes_secure (2, random_level);
memcpy(rndbuf, r, 2 );
gcry_free(r);
}
_gcry_mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 );
mpi_clear_highbit( x, qbits+1 );
}
while ( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) );
gcry_free(rndbuf);
mpi_free( e );
mpi_free( h );
/* y = g^x mod p */
y = mpi_alloc( mpi_get_nlimbs(p) );
gcry_mpi_powm( y, g, x, p );
if( DBG_CIPHER )
{
progress('\n');
log_mpidump("dsa p", p );
log_mpidump("dsa q", q );
log_mpidump("dsa g", g );
log_mpidump("dsa y", y );
log_mpidump("dsa x", x );
}
/* Copy the stuff to the key structures. */
sk->p = p;
sk->q = q;
sk->g = g;
sk->y = y;
sk->x = x;
/* Now we can test our keys (this should never fail!). */
if ( test_keys (sk, qbits) )
{
gcry_mpi_release (sk->p); sk->p = NULL;
gcry_mpi_release (sk->q); sk->q = NULL;
gcry_mpi_release (sk->g); sk->g = NULL;
gcry_mpi_release (sk->y); sk->y = NULL;
gcry_mpi_release (sk->x); sk->x = NULL;
fips_signal_error ("self-test after key generation failed");
return GPG_ERR_SELFTEST_FAILED;
}
return 0;
}
/* Generate a DSA key pair with a key of size NBITS using the
algorithm given in FIPS-186-3. If USE_FIPS186_2 is true,
FIPS-186-2 is used and thus the length is restricted to 1024/160.
If DERIVEPARMS is not NULL it may contain a seed value. If domain
parameters are specified in DOMAIN, DERIVEPARMS may not be given
and NBITS and QBITS must match the specified domain parameters. */
static gpg_err_code_t
generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
gcry_sexp_t deriveparms, int use_fips186_2,
dsa_domain_t *domain,
int *r_counter, void **r_seed, size_t *r_seedlen,
gcry_mpi_t *r_h)
{
gpg_err_code_t ec;
struct {
gcry_sexp_t sexp;
const void *seed;
size_t seedlen;
} initial_seed = { NULL, NULL, 0 };
gcry_mpi_t prime_q = NULL;
gcry_mpi_t prime_p = NULL;
gcry_mpi_t value_g = NULL; /* The generator. */
gcry_mpi_t value_y = NULL; /* g^x mod p */
gcry_mpi_t value_x = NULL; /* The secret exponent. */
gcry_mpi_t value_h = NULL; /* Helper. */
gcry_mpi_t value_e = NULL; /* Helper. */
/* Preset return values. */
*r_counter = 0;
*r_seed = NULL;
*r_seedlen = 0;
*r_h = NULL;
/* Derive QBITS from NBITS if requested */
if (!qbits)
{
if (nbits == 1024)
qbits = 160;
else if (nbits == 2048)
qbits = 224;
else if (nbits == 3072)
qbits = 256;
}
/* Check that QBITS and NBITS match the standard. Note that FIPS
186-3 uses N for QBITS and L for NBITS. */
if (nbits == 1024 && qbits == 160)
;
else if (nbits == 2048 && qbits == 224)
;
else if (nbits == 2048 && qbits == 256)
;
else if (nbits == 3072 && qbits == 256)
;
else
return GPG_ERR_INV_VALUE;
if (domain->p && domain->q && domain->g)
{
/* Domain parameters are given; use them. */
prime_p = mpi_copy (domain->p);
prime_q = mpi_copy (domain->q);
value_g = mpi_copy (domain->g);
gcry_assert (mpi_get_nbits (prime_p) == nbits);
gcry_assert (mpi_get_nbits (prime_q) == qbits);
gcry_assert (!deriveparms);
ec = 0;
}
else
{
/* Generate new domain parameters. */
/* Get an initial seed value. */
if (deriveparms)
{
initial_seed.sexp = gcry_sexp_find_token (deriveparms, "seed", 0);
if (initial_seed.sexp)
initial_seed.seed = gcry_sexp_nth_data (initial_seed.sexp, 1,
&initial_seed.seedlen);
}
/* Fixme: Enable 186-3 after it has been approved and after fixing
the generation function. */
/* if (use_fips186_2) */
(void)use_fips186_2;
ec = _gcry_generate_fips186_2_prime (nbits, qbits,
initial_seed.seed,
initial_seed.seedlen,
&prime_q, &prime_p,
r_counter,
r_seed, r_seedlen);
/* else */
/* ec = _gcry_generate_fips186_3_prime (nbits, qbits, NULL, 0, */
/* &prime_q, &prime_p, */
/* r_counter, */
/* r_seed, r_seedlen, NULL); */
gcry_sexp_release (initial_seed.sexp);
if (ec)
goto leave;
/* Find a generator g (h and e are helpers).
e = (p-1)/q */
value_e = mpi_alloc_like (prime_p);
mpi_sub_ui (value_e, prime_p, 1);
mpi_fdiv_q (value_e, value_e, prime_q );
value_g = mpi_alloc_like (prime_p);
value_h = mpi_alloc_set_ui (1);
do
{
mpi_add_ui (value_h, value_h, 1);
/* g = h^e mod p */
mpi_powm (value_g, value_h, value_e, prime_p);
}
while (!mpi_cmp_ui (value_g, 1)); /* Continue until g != 1. */
}
/* Select a random number x with: 0 < x < q */
value_x = gcry_mpi_snew (qbits);
do
{
if( DBG_CIPHER )
progress('.');
gcry_mpi_randomize (value_x, qbits, GCRY_VERY_STRONG_RANDOM);
mpi_clear_highbit (value_x, qbits+1);
}
while (!(mpi_cmp_ui (value_x, 0) > 0 && mpi_cmp (value_x, prime_q) < 0));
/* y = g^x mod p */
value_y = mpi_alloc_like (prime_p);
gcry_mpi_powm (value_y, value_g, value_x, prime_p);
if (DBG_CIPHER)
{
progress('\n');
log_mpidump("dsa p", prime_p );
log_mpidump("dsa q", prime_q );
log_mpidump("dsa g", value_g );
log_mpidump("dsa y", value_y );
log_mpidump("dsa x", value_x );
log_mpidump("dsa h", value_h );
}
/* Copy the stuff to the key structures. */
sk->p = prime_p; prime_p = NULL;
sk->q = prime_q; prime_q = NULL;
sk->g = value_g; value_g = NULL;
sk->y = value_y; value_y = NULL;
sk->x = value_x; value_x = NULL;
*r_h = value_h; value_h = NULL;
leave:
gcry_mpi_release (prime_p);
gcry_mpi_release (prime_q);
gcry_mpi_release (value_g);
gcry_mpi_release (value_y);
gcry_mpi_release (value_x);
gcry_mpi_release (value_h);
gcry_mpi_release (value_e);
/* As a last step test this keys (this should never fail of course). */
if (!ec && test_keys (sk, qbits) )
{
gcry_mpi_release (sk->p); sk->p = NULL;
gcry_mpi_release (sk->q); sk->q = NULL;
gcry_mpi_release (sk->g); sk->g = NULL;
gcry_mpi_release (sk->y); sk->y = NULL;
gcry_mpi_release (sk->x); sk->x = NULL;
fips_signal_error ("self-test after key generation failed");
ec = GPG_ERR_SELFTEST_FAILED;
}
if (ec)
{
*r_counter = 0;
gcry_free (*r_seed); *r_seed = NULL;
*r_seedlen = 0;
gcry_mpi_release (*r_h); *r_h = NULL;
}
return ec;
}
/*
Test whether the secret key is valid.
Returns: if this is a valid key.
*/
static int
check_secret_key( DSA_secret_key *sk )
{
int rc;
gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs(sk->y) );
gcry_mpi_powm( y, sk->g, sk->x, sk->p );
rc = !mpi_cmp( y, sk->y );
mpi_free( y );
return rc;
}
/*
Make a DSA signature from HASH and put it into r and s.
*/
static void
-sign(gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_secret_key *skey )
+sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_secret_key *skey )
{
gcry_mpi_t k;
gcry_mpi_t kinv;
gcry_mpi_t tmp;
/* Select a random k with 0 < k < q */
k = _gcry_dsa_gen_k (skey->q, GCRY_STRONG_RANDOM);
/* r = (a^k mod p) mod q */
gcry_mpi_powm( r, skey->g, k, skey->p );
mpi_fdiv_r( r, r, skey->q );
/* kinv = k^(-1) mod q */
kinv = mpi_alloc( mpi_get_nlimbs(k) );
mpi_invm(kinv, k, skey->q );
/* s = (kinv * ( hash + x * r)) mod q */
tmp = mpi_alloc( mpi_get_nlimbs(skey->p) );
mpi_mul( tmp, skey->x, r );
mpi_add( tmp, tmp, hash );
mpi_mulm( s , kinv, tmp, skey->q );
mpi_free(k);
mpi_free(kinv);
mpi_free(tmp);
}
/*
Returns true if the signature composed from R and S is valid.
*/
static int
verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey )
{
int rc;
gcry_mpi_t w, u1, u2, v;
gcry_mpi_t base[3];
gcry_mpi_t ex[3];
if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) )
return 0; /* assertion 0 < r < q failed */
if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
return 0; /* assertion 0 < s < q failed */
w = mpi_alloc( mpi_get_nlimbs(pkey->q) );
u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
v = mpi_alloc( mpi_get_nlimbs(pkey->p) );
/* w = s^(-1) mod q */
mpi_invm( w, s, pkey->q );
/* u1 = (hash * w) mod q */
mpi_mulm( u1, hash, w, pkey->q );
/* u2 = r * w mod q */
mpi_mulm( u2, r, w, pkey->q );
/* v = g^u1 * y^u2 mod p mod q */
base[0] = pkey->g; ex[0] = u1;
base[1] = pkey->y; ex[1] = u2;
base[2] = NULL; ex[2] = NULL;
mpi_mulpowm( v, base, ex, pkey->p );
mpi_fdiv_r( v, v, pkey->q );
rc = !mpi_cmp( v, r );
mpi_free(w);
mpi_free(u1);
mpi_free(u2);
mpi_free(v);
return rc;
}
/*********************************************
************** interface ******************
*********************************************/
static gcry_err_code_t
dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
const gcry_sexp_t genparms,
gcry_mpi_t *skey, gcry_mpi_t **retfactors,
gcry_sexp_t *r_extrainfo)
{
gpg_err_code_t ec;
DSA_secret_key sk;
gcry_sexp_t l1;
unsigned int qbits = 0;
gcry_sexp_t deriveparms = NULL;
gcry_sexp_t seedinfo = NULL;
int transient_key = 0;
int use_fips186_2 = 0;
int use_fips186 = 0;
dsa_domain_t domain;
(void)algo; /* No need to check it. */
(void)evalue; /* Not required for DSA. */
memset (&domain, 0, sizeof domain);
if (genparms)
{
gcry_sexp_t domainsexp;
/* Parse the optional qbits element. */
l1 = gcry_sexp_find_token (genparms, "qbits", 0);
if (l1)
{
char buf[50];
const char *s;
size_t n;
s = gcry_sexp_nth_data (l1, 1, &n);
if (!s || n >= DIM (buf) - 1 )
{
gcry_sexp_release (l1);
return GPG_ERR_INV_OBJ; /* No value or value too large. */
}
memcpy (buf, s, n);
buf[n] = 0;
qbits = (unsigned int)strtoul (buf, NULL, 0);
gcry_sexp_release (l1);
}
/* Parse the optional transient-key flag. */
l1 = gcry_sexp_find_token (genparms, "transient-key", 0);
if (l1)
{
transient_key = 1;
gcry_sexp_release (l1);
}
/* Get the optional derive parameters. */
deriveparms = gcry_sexp_find_token (genparms, "derive-parms", 0);
/* Parse the optional "use-fips186" flags. */
l1 = gcry_sexp_find_token (genparms, "use-fips186", 0);
if (l1)
{
use_fips186 = 1;
gcry_sexp_release (l1);
}
l1 = gcry_sexp_find_token (genparms, "use-fips186-2", 0);
if (l1)
{
use_fips186_2 = 1;
gcry_sexp_release (l1);
}
/* Check whether domain parameters are given. */
domainsexp = gcry_sexp_find_token (genparms, "domain", 0);
if (domainsexp)
{
/* DERIVEPARMS can't be used together with domain
parameters. NBITS abnd QBITS may not be specified
because there values are derived from the domain
parameters. */
if (deriveparms || qbits || nbits)
{
gcry_sexp_release (domainsexp);
gcry_sexp_release (deriveparms);
return GPG_ERR_INV_VALUE;
}
/* Put all domain parameters into the domain object. */
l1 = gcry_sexp_find_token (domainsexp, "p", 0);
domain.p = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l1);
l1 = gcry_sexp_find_token (domainsexp, "q", 0);
domain.q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l1);
l1 = gcry_sexp_find_token (domainsexp, "g", 0);
domain.g = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l1);
gcry_sexp_release (domainsexp);
/* Check that all domain parameters are available. */
if (!domain.p || !domain.q || !domain.g)
{
gcry_mpi_release (domain.p);
gcry_mpi_release (domain.q);
gcry_mpi_release (domain.g);
gcry_sexp_release (deriveparms);
return GPG_ERR_MISSING_VALUE;
}
/* Get NBITS and QBITS from the domain parameters. */
nbits = mpi_get_nbits (domain.p);
qbits = mpi_get_nbits (domain.q);
}
}
if (deriveparms || use_fips186 || use_fips186_2 || fips_mode ())
{
int counter;
void *seed;
size_t seedlen;
gcry_mpi_t h_value;
ec = generate_fips186 (&sk, nbits, qbits, deriveparms, use_fips186_2,
&domain,
&counter, &seed, &seedlen, &h_value);
gcry_sexp_release (deriveparms);
if (!ec && h_value)
{
/* Format the seed-values unless domain parameters are used
for which a H_VALUE of NULL is an indication. */
ec = gpg_err_code (gcry_sexp_build
(&seedinfo, NULL,
"(seed-values(counter %d)(seed %b)(h %m))",
counter, (int)seedlen, seed, h_value));
if (ec)
{
gcry_mpi_release (sk.p); sk.p = NULL;
gcry_mpi_release (sk.q); sk.q = NULL;
gcry_mpi_release (sk.g); sk.g = NULL;
gcry_mpi_release (sk.y); sk.y = NULL;
gcry_mpi_release (sk.x); sk.x = NULL;
}
gcry_free (seed);
gcry_mpi_release (h_value);
}
}
else
{
ec = generate (&sk, nbits, qbits, transient_key, &domain, retfactors);
}
gcry_mpi_release (domain.p);
gcry_mpi_release (domain.q);
gcry_mpi_release (domain.g);
if (!ec)
{
skey[0] = sk.p;
skey[1] = sk.q;
skey[2] = sk.g;
skey[3] = sk.y;
skey[4] = sk.x;
if (!r_extrainfo)
{
/* Old style interface - return the factors - if any - at
retfactors. */
}
else if (!*retfactors && !seedinfo)
{
/* No factors and no seedinfo, thus there is nothing to return. */
*r_extrainfo = NULL;
}
else
{
/* Put the factors into extrainfo and set retfactors to NULL
to make use of the new interface. Note that the factors
are not confidential thus we can store them in standard
memory. */
int nfactors, i, j;
char *p;
char *format = NULL;
void **arg_list = NULL;
for (nfactors=0; *retfactors && (*retfactors)[nfactors]; nfactors++)
;
/* Allocate space for the format string:
"(misc-key-info%S(pm1-factors%m))"
with one "%m" for each factor and construct it. */
format = gcry_malloc (50 + 2*nfactors);
if (!format)
ec = gpg_err_code_from_syserror ();
else
{
p = stpcpy (format, "(misc-key-info");
if (seedinfo)
p = stpcpy (p, "%S");
if (nfactors)
{
p = stpcpy (p, "(pm1-factors");
for (i=0; i < nfactors; i++)
p = stpcpy (p, "%m");
p = stpcpy (p, ")");
}
p = stpcpy (p, ")");
/* Allocate space for the list of factors plus one for
an S-expression plus an extra NULL entry for safety
and fill it with the factors. */
arg_list = gcry_calloc (nfactors+1+1, sizeof *arg_list);
if (!arg_list)
ec = gpg_err_code_from_syserror ();
else
{
i = 0;
if (seedinfo)
arg_list[i++] = &seedinfo;
for (j=0; j < nfactors; j++)
arg_list[i++] = (*retfactors) + j;
arg_list[i] = NULL;
ec = gpg_err_code (gcry_sexp_build_array
(r_extrainfo, NULL, format, arg_list));
}
}
gcry_free (arg_list);
gcry_free (format);
for (i=0; i < nfactors; i++)
{
gcry_mpi_release ((*retfactors)[i]);
(*retfactors)[i] = NULL;
}
gcry_free (*retfactors);
*retfactors = NULL;
if (ec)
{
for (i=0; i < 5; i++)
{
gcry_mpi_release (skey[i]);
skey[i] = NULL;
}
}
}
}
gcry_sexp_release (seedinfo);
return ec;
}
static gcry_err_code_t
dsa_generate (int algo, unsigned int nbits, unsigned long evalue,
gcry_mpi_t *skey, gcry_mpi_t **retfactors)
{
(void)evalue;
return dsa_generate_ext (algo, nbits, 0, NULL, skey, retfactors, NULL);
}
static gcry_err_code_t
dsa_check_secret_key (int algo, gcry_mpi_t *skey)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
DSA_secret_key sk;
(void)algo;
if ((! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]) || (! skey[4]))
err = GPG_ERR_BAD_MPI;
else
{
sk.p = skey[0];
sk.q = skey[1];
sk.g = skey[2];
sk.y = skey[3];
sk.x = skey[4];
if (! check_secret_key (&sk))
err = GPG_ERR_BAD_SECKEY;
}
return err;
}
static gcry_err_code_t
dsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
int flags, int hashalgo)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
DSA_secret_key sk;
(void)algo;
(void)flags;
(void)hashalgo;
if ((! data)
|| (! skey[0]) || (! skey[1]) || (! skey[2])
|| (! skey[3]) || (! skey[4]))
err = GPG_ERR_BAD_MPI;
else
{
sk.p = skey[0];
sk.q = skey[1];
sk.g = skey[2];
sk.y = skey[3];
sk.x = skey[4];
resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.p));
resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.p));
- sign (resarr[0], resarr[1], data, &sk);
+ if (mpi_is_opaque (data))
+ {
+ const void *abuf;
+ unsigned int abits;
+ gcry_mpi_t a;
+
+ abuf = gcry_mpi_get_opaque (data, &abits);
+ err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, abits/8, NULL);
+ if (!err)
+ {
+ sign (resarr[0], resarr[1], a, &sk);
+ gcry_mpi_release (a);
+ }
+ }
+ else
+ sign (resarr[0], resarr[1], data, &sk);
}
return err;
}
static gcry_err_code_t
dsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
int (*cmp) (void *, gcry_mpi_t), void *opaquev)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
DSA_public_key pk;
(void)algo;
(void)cmp;
(void)opaquev;
if ((! data[0]) || (! data[1]) || (! hash)
|| (! pkey[0]) || (! pkey[1]) || (! pkey[2]) || (! pkey[3]))
err = GPG_ERR_BAD_MPI;
else
{
pk.p = pkey[0];
pk.q = pkey[1];
pk.g = pkey[2];
pk.y = pkey[3];
- if (! verify (data[0], data[1], hash, &pk))
- err = GPG_ERR_BAD_SIGNATURE;
+ if (mpi_is_opaque (hash))
+ {
+ const void *abuf;
+ unsigned int abits;
+ gcry_mpi_t a;
+
+ abuf = gcry_mpi_get_opaque (hash, &abits);
+ err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, abits/8, NULL);
+ if (!err)
+ {
+ if (!verify (data[0], data[1], a, &pk))
+ err = GPG_ERR_BAD_SIGNATURE;
+ gcry_mpi_release (a);
+ }
+ }
+ else
+ {
+ if (!verify (data[0], data[1], hash, &pk))
+ err = GPG_ERR_BAD_SIGNATURE;
+ }
}
return err;
}
static unsigned int
dsa_get_nbits (int algo, gcry_mpi_t *pkey)
{
(void)algo;
return mpi_get_nbits (pkey[0]);
}
/*
Self-test section.
*/
static const char *
selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey)
{
static const char sample_data[] =
"(data (flags raw)"
" (value #a0b1c2d3e4f500102030405060708090a1b2c3d4#))";
static const char sample_data_bad[] =
"(data (flags raw)"
" (value #a0b1c2d3e4f510102030405060708090a1b2c3d4#))";
const char *errtxt = NULL;
gcry_error_t err;
gcry_sexp_t data = NULL;
gcry_sexp_t data_bad = NULL;
gcry_sexp_t sig = NULL;
err = gcry_sexp_sscan (&data, NULL,
sample_data, strlen (sample_data));
if (!err)
err = gcry_sexp_sscan (&data_bad, NULL,
sample_data_bad, strlen (sample_data_bad));
if (err)
{
errtxt = "converting data failed";
goto leave;
}
err = gcry_pk_sign (&sig, data, skey);
if (err)
{
errtxt = "signing failed";
goto leave;
}
err = gcry_pk_verify (sig, data, pkey);
if (err)
{
errtxt = "verify failed";
goto leave;
}
err = gcry_pk_verify (sig, data_bad, pkey);
if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE)
{
errtxt = "bad signature not detected";
goto leave;
}
leave:
gcry_sexp_release (sig);
gcry_sexp_release (data_bad);
gcry_sexp_release (data);
return errtxt;
}
static gpg_err_code_t
selftests_dsa (selftest_report_func_t report)
{
const char *what;
const char *errtxt;
gcry_error_t err;
gcry_sexp_t skey = NULL;
gcry_sexp_t pkey = NULL;
/* Convert the S-expressions into the internal representation. */
what = "convert";
err = gcry_sexp_sscan (&skey, NULL,
sample_secret_key, strlen (sample_secret_key));
if (!err)
err = gcry_sexp_sscan (&pkey, NULL,
sample_public_key, strlen (sample_public_key));
if (err)
{
errtxt = gcry_strerror (err);
goto failed;
}
what = "key consistency";
err = gcry_pk_testkey (skey);
if (err)
{
errtxt = gcry_strerror (err);
goto failed;
}
what = "sign";
errtxt = selftest_sign_1024 (pkey, skey);
if (errtxt)
goto failed;
gcry_sexp_release (pkey);
gcry_sexp_release (skey);
return 0; /* Succeeded. */
failed:
gcry_sexp_release (pkey);
gcry_sexp_release (skey);
if (report)
report ("pubkey", GCRY_PK_DSA, what, errtxt);
return GPG_ERR_SELFTEST_FAILED;
}
/* Run a full self-test for ALGO and return 0 on success. */
static gpg_err_code_t
run_selftests (int algo, int extended, selftest_report_func_t report)
{
gpg_err_code_t ec;
(void)extended;
switch (algo)
{
case GCRY_PK_DSA:
ec = selftests_dsa (report);
break;
default:
ec = GPG_ERR_PUBKEY_ALGO;
break;
}
return ec;
}
static const char *dsa_names[] =
{
"dsa",
"openpgp-dsa",
NULL,
};
gcry_pk_spec_t _gcry_pubkey_spec_dsa =
{
"DSA", dsa_names,
"pqgy", "pqgyx", "", "rs", "pqgy",
GCRY_PK_USAGE_SIGN,
dsa_generate,
dsa_check_secret_key,
NULL,
NULL,
dsa_sign,
dsa_verify,
dsa_get_nbits
};
pk_extra_spec_t _gcry_pubkey_extraspec_dsa =
{
run_selftests,
dsa_generate_ext
};
diff --git a/cipher/ecc.c b/cipher/ecc.c
index e4b1799e..725dfbe6 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -1,2182 +1,2214 @@
/* ecc.c - Elliptic Curve Cryptography
* Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
* Copyright (C) 2013 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* This code is originally based on the Patch 0.1.6 for the gnupg
1.4.x branch as retrieved on 2007-03-21 from
http://www.calcurco.cat/eccGnuPG/src/gnupg-1.4.6-ecc0.2.0beta1.diff.bz2
The original authors are:
Written by
Sergi Blanch i Torne <d4372211 at alumnes.eup.udl.es>,
Ramiro Moreno Chiral <ramiro at eup.udl.es>
Maintainers
Sergi Blanch i Torne
Ramiro Moreno Chiral
Mikael Mylnikov (mmr)
For use in Libgcrypt the code has been heavily modified and cleaned
up. In fact there is not much left of the orginally code except for
some variable names and the text book implementaion of the sign and
verification algorithms. The arithmetic functions have entirely
been rewritten and moved to mpi/ec.c.
ECDH encrypt and decrypt code written by Andrey Jivsov,
*/
/* TODO:
- If we support point compression we need to uncompress before
computing the keygrip
- In mpi/ec.c we use mpi_powm for x^2 mod p: Either implement a
special case in mpi_powm or check whether mpi_mulm is faster.
- Split this up into several files. For example the curve
management and gcry_mpi_ec_new are independent of the actual ECDSA
implementation. This will also help to support optimized versions
of some curves.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
#include "context.h"
#include "ec-context.h"
#include "pubkey-internal.h"
/* Definition of a curve. */
typedef struct
{
gcry_mpi_t p; /* Prime specifying the field GF(p). */
gcry_mpi_t a; /* First coefficient of the Weierstrass equation. */
gcry_mpi_t b; /* Second coefficient of the Weierstrass equation. */
mpi_point_struct G; /* Base point (generator). */
gcry_mpi_t n; /* Order of G. */
const char *name; /* Name of the curve or NULL. */
} elliptic_curve_t;
typedef struct
{
elliptic_curve_t E;
mpi_point_struct Q; /* Q = [d]G */
} ECC_public_key;
typedef struct
{
elliptic_curve_t E;
mpi_point_struct Q;
gcry_mpi_t d;
} ECC_secret_key;
/* This tables defines aliases for curve names. */
static const struct
{
const char *name; /* Our name. */
const char *other; /* Other name. */
} curve_aliases[] =
{
{ "NIST P-192", "1.2.840.10045.3.1.1" }, /* X9.62 OID */
{ "NIST P-192", "prime192v1" }, /* X9.62 name. */
{ "NIST P-192", "secp192r1" }, /* SECP name. */
{ "NIST P-192", "nistp192" }, /* rfc5656. */
{ "NIST P-224", "secp224r1" },
{ "NIST P-224", "1.3.132.0.33" }, /* SECP OID. */
{ "NIST P-224", "nistp224" }, /* rfc5656. */
{ "NIST P-256", "1.2.840.10045.3.1.7" }, /* From NIST SP 800-78-1. */
{ "NIST P-256", "prime256v1" },
{ "NIST P-256", "secp256r1" },
{ "NIST P-256", "nistp256" }, /* rfc5656. */
{ "NIST P-384", "secp384r1" },
{ "NIST P-384", "1.3.132.0.34" },
{ "NIST P-384", "nistp384" }, /* rfc5656. */
{ "NIST P-521", "secp521r1" },
{ "NIST P-521", "1.3.132.0.35" },
{ "NIST P-521", "nistp521" }, /* rfc5656. */
{ "brainpoolP160r1", "1.3.36.3.3.2.8.1.1.1" },
{ "brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3" },
{ "brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5" },
{ "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7" },
{ "brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9" },
{ "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11"},
{ "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13"},
{ NULL, NULL}
};
typedef struct {
const char *desc; /* Description of the curve. */
unsigned int nbits; /* Number of bits. */
unsigned int fips:1; /* True if this is a FIPS140-2 approved curve. */
const char *p; /* Order of the prime field. */
const char *a, *b; /* The coefficients. */
const char *n; /* The order of the base point. */
const char *g_x, *g_y; /* Base point. */
} ecc_domain_parms_t;
/* This static table defines all available curves. */
static const ecc_domain_parms_t domain_parms[] =
{
{
"NIST P-192", 192, 1,
"0xfffffffffffffffffffffffffffffffeffffffffffffffff",
"0xfffffffffffffffffffffffffffffffefffffffffffffffc",
"0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
"0xffffffffffffffffffffffff99def836146bc9b1b4d22831",
"0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
"0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"
},
{
"NIST P-224", 224, 1,
"0xffffffffffffffffffffffffffffffff000000000000000000000001",
"0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
"0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
"0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" ,
"0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
"0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"
},
{
"NIST P-256", 256, 1,
"0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
"0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
"0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
"0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
"0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
"0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
},
{
"NIST P-384", 384, 1,
"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
"ffffffff0000000000000000ffffffff",
"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
"ffffffff0000000000000000fffffffc",
"0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a"
"c656398d8a2ed19d2a85c8edd3ec2aef",
"0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf"
"581a0db248b0a77aecec196accc52973",
"0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38"
"5502f25dbf55296c3a545e3872760ab7",
"0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0"
"0a60b1ce1d7e819d7a431d7c90ea0e5f"
},
{
"NIST P-521", 521, 1,
"0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc",
"0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10"
"9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
"0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
"0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3d"
"baa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
"0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6"
"62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"
},
{ "brainpoolP160r1", 160, 0,
"0xe95e4a5f737059dc60dfc7ad95b3d8139515620f",
"0x340e7be2a280eb74e2be61bada745d97e8f7c300",
"0x1e589a8595423412134faa2dbdec95c8d8675e58",
"0xe95e4a5f737059dc60df5991d45029409e60fc09",
"0xbed5af16ea3f6a4f62938c4631eb5af7bdbcdbc3",
"0x1667cb477a1a8ec338f94741669c976316da6321"
},
{ "brainpoolP192r1", 192, 0,
"0xc302f41d932a36cda7a3463093d18db78fce476de1a86297",
"0x6a91174076b1e0e19c39c031fe8685c1cae040e5c69a28ef",
"0x469a28ef7c28cca3dc721d044f4496bcca7ef4146fbf25c9",
"0xc302f41d932a36cda7a3462f9e9e916b5be8f1029ac4acc1",
"0xc0a0647eaab6a48753b033c56cb0f0900a2f5c4853375fd6",
"0x14b690866abd5bb88b5f4828c1490002e6773fa2fa299b8f"
},
{ "brainpoolP224r1", 224, 0,
"0xd7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff",
"0x68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43",
"0x2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400b",
"0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939f",
"0x0d9029ad2c7e5cf4340823b2a87dc68c9e4ce3174c1e6efdee12c07d",
"0x58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cd"
},
{ "brainpoolP256r1", 256, 0,
"0xa9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377",
"0x7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9",
"0x26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6",
"0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7",
"0x8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262",
"0x547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997"
},
{ "brainpoolP320r1", 320, 0,
"0xd35e472036bc4fb7e13c785ed201e065f98fcfa6f6f40def4f92b9ec7893ec28"
"fcd412b1f1b32e27",
"0x3ee30b568fbab0f883ccebd46d3f3bb8a2a73513f5eb79da66190eb085ffa9f4"
"92f375a97d860eb4",
"0x520883949dfdbc42d3ad198640688a6fe13f41349554b49acc31dccd88453981"
"6f5eb4ac8fb1f1a6",
"0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e9"
"8691555b44c59311",
"0x43bd7e9afb53d8b85289bcc48ee5bfe6f20137d10a087eb6e7871e2a10a599c7"
"10af8d0d39e20611",
"0x14fdd05545ec1cc8ab4093247f77275e0743ffed117182eaa9c77877aaac6ac7"
"d35245d1692e8ee1"
},
{ "brainpoolP384r1", 384, 0,
"0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123"
"acd3a729901d1a71874700133107ec53",
"0x7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f"
"8aa5814a503ad4eb04a8c7dd22ce2826",
"0x04a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d5"
"7cb4390295dbc9943ab78696fa504c11",
"0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7"
"cf3ab6af6b7fc3103b883202e9046565",
"0x1d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8"
"e826e03436d646aaef87b2e247d4af1e",
"0x8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff9912928"
"0e4646217791811142820341263c5315"
},
{ "brainpoolP512r1", 512, 0,
"0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330871"
"7d4d9b009bc66842aecda12ae6a380e62881ff2f2d82c68528aa6056583a48f3",
"0x7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc"
"2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94ca",
"0x3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a7"
"2bf2c7b9e7c1ac4d77fc94cadc083e67984050b75ebae5dd2809bd638016f723",
"0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870"
"553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90069",
"0x81aee4bdd82ed9645a21322e9c4c6a9385ed9f70b5d916c1b43b62eef4d0098e"
"ff3b1f78e2d0d48d50d1687b93b97d5f7c6d5047406a5e688b352209bcb9f822",
"0x7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111"
"b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892"
},
{ NULL, 0, 0, NULL, NULL, NULL, NULL }
};
/* Registered progress function and its callback value. */
static void (*progress_cb) (void *, const char*, int, int, int);
static void *progress_cb_data;
#define point_init(a) _gcry_mpi_point_init ((a))
#define point_free(a) _gcry_mpi_point_free_parts ((a))
/* Local prototypes. */
static void test_keys (ECC_secret_key * sk, unsigned int nbits);
static int check_secret_key (ECC_secret_key * sk);
static gpg_err_code_t sign (gcry_mpi_t input, ECC_secret_key *skey,
gcry_mpi_t r, gcry_mpi_t s);
static gpg_err_code_t verify (gcry_mpi_t input, ECC_public_key *pkey,
gcry_mpi_t r, gcry_mpi_t s);
static gcry_mpi_t gen_y_2 (gcry_mpi_t x, elliptic_curve_t * base);
void
_gcry_register_pk_ecc_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, "pk_ecc", c, 0, 0); */
/* } */
/* Set the value from S into D. */
static void
point_set (mpi_point_t d, mpi_point_t s)
{
mpi_set (d->x, s->x);
mpi_set (d->y, s->y);
mpi_set (d->z, s->z);
}
/*
* Release a curve object.
*/
static void
curve_free (elliptic_curve_t *E)
{
mpi_free (E->p); E->p = NULL;
mpi_free (E->a); E->a = NULL;
mpi_free (E->b); E->b = NULL;
point_free (&E->G);
mpi_free (E->n); E->n = NULL;
}
/*
* Return a copy of a curve object.
*/
static elliptic_curve_t
curve_copy (elliptic_curve_t E)
{
elliptic_curve_t R;
R.p = mpi_copy (E.p);
R.a = mpi_copy (E.a);
R.b = mpi_copy (E.b);
point_init (&R.G);
point_set (&R.G, &E.G);
R.n = mpi_copy (E.n);
return R;
}
/* Helper to scan a hex string. */
static gcry_mpi_t
scanval (const char *string)
{
gpg_error_t err;
gcry_mpi_t val;
err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
if (err)
log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (err));
return val;
}
/****************
* Solve the right side of the equation that defines a curve.
*/
static gcry_mpi_t
gen_y_2 (gcry_mpi_t x, elliptic_curve_t *base)
{
gcry_mpi_t three, x_3, axb, y;
three = mpi_alloc_set_ui (3);
x_3 = mpi_new (0);
axb = mpi_new (0);
y = mpi_new (0);
mpi_powm (x_3, x, three, base->p);
mpi_mulm (axb, base->a, x, base->p);
mpi_addm (axb, axb, base->b, base->p);
mpi_addm (y, x_3, axb, base->p);
mpi_free (x_3);
mpi_free (axb);
mpi_free (three);
return y; /* The quadratic value of the coordinate if it exist. */
}
/* Generate the crypto system setup. This function takes the NAME of
a curve or the desired number of bits and stores at R_CURVE the
parameters of the named curve or those of a suitable curve. If
R_NBITS is not NULL, the chosen number of bits is stored there. */
static gpg_err_code_t
fill_in_curve (unsigned int nbits, const char *name,
elliptic_curve_t *curve, unsigned int *r_nbits)
{
int idx, aliasno;
const char *resname = NULL; /* Set to a found curve name. */
if (name)
{
/* First check our native curves. */
for (idx = 0; domain_parms[idx].desc; idx++)
if (!strcmp (name, domain_parms[idx].desc))
{
resname = domain_parms[idx].desc;
break;
}
/* If not found consult the alias table. */
if (!domain_parms[idx].desc)
{
for (aliasno = 0; curve_aliases[aliasno].name; aliasno++)
if (!strcmp (name, curve_aliases[aliasno].other))
break;
if (curve_aliases[aliasno].name)
{
for (idx = 0; domain_parms[idx].desc; idx++)
if (!strcmp (curve_aliases[aliasno].name,
domain_parms[idx].desc))
{
resname = domain_parms[idx].desc;
break;
}
}
}
}
else
{
for (idx = 0; domain_parms[idx].desc; idx++)
if (nbits == domain_parms[idx].nbits)
break;
}
if (!domain_parms[idx].desc)
return GPG_ERR_INV_VALUE;
/* In fips mode we only support NIST curves. Note that it is
possible to bypass this check by specifying the curve parameters
directly. */
if (fips_mode () && !domain_parms[idx].fips )
return GPG_ERR_NOT_SUPPORTED;
if (r_nbits)
*r_nbits = domain_parms[idx].nbits;
curve->p = scanval (domain_parms[idx].p);
curve->a = scanval (domain_parms[idx].a);
curve->b = scanval (domain_parms[idx].b);
curve->n = scanval (domain_parms[idx].n);
curve->G.x = scanval (domain_parms[idx].g_x);
curve->G.y = scanval (domain_parms[idx].g_y);
curve->G.z = mpi_alloc_set_ui (1);
curve->name = resname;
return 0;
}
/*
* First obtain the setup. Over the finite field randomize an scalar
* secret value, and calculate the public point.
*/
static gpg_err_code_t
generate_key (ECC_secret_key *sk, unsigned int nbits, const char *name,
int transient_key,
gcry_mpi_t g_x, gcry_mpi_t g_y,
gcry_mpi_t q_x, gcry_mpi_t q_y,
const char **r_usedcurve)
{
gpg_err_code_t err;
elliptic_curve_t E;
mpi_point_struct Q;
mpi_ec_t ctx;
gcry_random_level_t random_level;
*r_usedcurve = NULL;
err = fill_in_curve (nbits, name, &E, &nbits);
if (err)
return err;
if (DBG_CIPHER)
{
log_mpidump ("ecgen curve p", E.p);
log_mpidump ("ecgen curve a", E.a);
log_mpidump ("ecgen curve b", E.b);
log_mpidump ("ecgen curve n", E.n);
log_mpidump ("ecgen curve Gx", E.G.x);
log_mpidump ("ecgen curve Gy", E.G.y);
log_mpidump ("ecgen curve Gz", E.G.z);
if (E.name)
log_debug ("ecgen curve used: %s\n", E.name);
}
random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
sk->d = _gcry_dsa_gen_k (E.n, random_level);
/* Compute Q. */
point_init (&Q);
ctx = _gcry_mpi_ec_p_internal_new (E.p, E.a);
_gcry_mpi_ec_mul_point (&Q, sk->d, &E.G, ctx);
/* Copy the stuff to the key structures. */
sk->E.p = mpi_copy (E.p);
sk->E.a = mpi_copy (E.a);
sk->E.b = mpi_copy (E.b);
point_init (&sk->E.G);
point_set (&sk->E.G, &E.G);
sk->E.n = mpi_copy (E.n);
point_init (&sk->Q);
/* We want the Q=(x,y) be a "compliant key" in terms of the
* http://tools.ietf.org/html/draft-jivsov-ecc-compact, which simply
* means that we choose either Q=(x,y) or -Q=(x,p-y) such that we
* end up with the min(y,p-y) as the y coordinate. Such a public
* key allows the most efficient compression: y can simply be
* dropped because we know that it's a minimum of the two
* possibilities without any loss of security. */
{
gcry_mpi_t x, y, p_y;
const unsigned int pbits = mpi_get_nbits (E.p);
x = mpi_new (pbits);
y = mpi_new (pbits);
p_y = mpi_new (pbits);
if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx))
log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q");
mpi_sub (p_y, E.p, y); /* p_y = p - y */
if (mpi_cmp (p_y, y) < 0) /* p - y < p */
{
/* We need to end up with -Q; this assures that new Q's y is
the smallest one */
mpi_sub (sk->d, E.n, sk->d); /* d = order - d */
gcry_mpi_point_snatch_set (&sk->Q, x, p_y, mpi_alloc_set_ui (1));
if (DBG_CIPHER)
log_debug ("ecgen converted Q to a compliant point\n");
}
else /* p - y >= p */
{
/* No change is needed exactly 50% of the time: just copy. */
point_set (&sk->Q, &Q);
if (DBG_CIPHER)
log_debug ("ecgen didn't need to convert Q to a compliant point\n");
mpi_free (p_y);
mpi_free (x);
}
mpi_free (y);
}
/* We also return copies of G and Q in affine coordinates if
requested. */
if (g_x && g_y)
{
if (_gcry_mpi_ec_get_affine (g_x, g_y, &sk->E.G, ctx))
log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "G");
}
if (q_x && q_y)
{
if (_gcry_mpi_ec_get_affine (q_x, q_y, &sk->Q, ctx))
log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q");
}
_gcry_mpi_ec_free (ctx);
point_free (&Q);
*r_usedcurve = E.name;
curve_free (&E);
/* Now we can test our keys (this should never fail!). */
test_keys (sk, nbits - 64);
return 0;
}
/*
* To verify correct skey it use a random information.
* First, encrypt and decrypt this dummy value,
* test if the information is recuperated.
* Second, test with the sign and verify functions.
*/
static void
test_keys (ECC_secret_key *sk, unsigned int nbits)
{
ECC_public_key pk;
gcry_mpi_t test = mpi_new (nbits);
mpi_point_struct R_;
gcry_mpi_t c = mpi_new (nbits);
gcry_mpi_t out = mpi_new (nbits);
gcry_mpi_t r = mpi_new (nbits);
gcry_mpi_t s = mpi_new (nbits);
if (DBG_CIPHER)
log_debug ("Testing key.\n");
point_init (&R_);
pk.E = curve_copy (sk->E);
point_init (&pk.Q);
point_set (&pk.Q, &sk->Q);
gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
if (sign (test, sk, r, s) )
log_fatal ("ECDSA operation: sign failed\n");
if (verify (test, &pk, r, s))
{
log_fatal ("ECDSA operation: sign, verify failed\n");
}
if (DBG_CIPHER)
log_debug ("ECDSA operation: sign, verify ok.\n");
point_free (&pk.Q);
curve_free (&pk.E);
point_free (&R_);
mpi_free (s);
mpi_free (r);
mpi_free (out);
mpi_free (c);
mpi_free (test);
}
/*
* To check the validity of the value, recalculate the correspondence
* between the public value and the secret one.
*/
static int
check_secret_key (ECC_secret_key * sk)
{
int rc = 1;
mpi_point_struct Q;
gcry_mpi_t y_2, y2;
mpi_ec_t ctx = NULL;
point_init (&Q);
/* ?primarity test of 'p' */
/* (...) //!! */
/* G in E(F_p) */
y_2 = gen_y_2 (sk->E.G.x, &sk->E); /* y^2=x^3+a*x+b */
y2 = mpi_alloc (0);
mpi_mulm (y2, sk->E.G.y, sk->E.G.y, sk->E.p); /* y^2=y*y */
if (mpi_cmp (y_2, y2))
{
if (DBG_CIPHER)
log_debug ("Bad check: Point 'G' does not belong to curve 'E'!\n");
goto leave;
}
/* G != PaI */
if (!mpi_cmp_ui (sk->E.G.z, 0))
{
if (DBG_CIPHER)
log_debug ("Bad check: 'G' cannot be Point at Infinity!\n");
goto leave;
}
ctx = _gcry_mpi_ec_p_internal_new (sk->E.p, sk->E.a);
_gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ctx);
if (mpi_cmp_ui (Q.z, 0))
{
if (DBG_CIPHER)
log_debug ("check_secret_key: E is not a curve of order n\n");
goto leave;
}
/* pubkey cannot be PaI */
if (!mpi_cmp_ui (sk->Q.z, 0))
{
if (DBG_CIPHER)
log_debug ("Bad check: Q can not be a Point at Infinity!\n");
goto leave;
}
/* pubkey = [d]G over E */
_gcry_mpi_ec_mul_point (&Q, sk->d, &sk->E.G, ctx);
if ((Q.x == sk->Q.x) && (Q.y == sk->Q.y) && (Q.z == sk->Q.z))
{
if (DBG_CIPHER)
log_debug
("Bad check: There is NO correspondence between 'd' and 'Q'!\n");
goto leave;
}
rc = 0; /* Okay. */
leave:
_gcry_mpi_ec_free (ctx);
mpi_free (y2);
mpi_free (y_2);
point_free (&Q);
return rc;
}
/*
* Return the signature struct (r,s) from the message hash. The caller
* must have allocated R and S.
*/
static gpg_err_code_t
sign (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s)
{
gpg_err_code_t err = 0;
gcry_mpi_t k, dr, sum, k_1, x;
mpi_point_struct I;
mpi_ec_t ctx;
if (DBG_CIPHER)
log_mpidump ("ecdsa sign hash ", input );
k = NULL;
dr = mpi_alloc (0);
sum = mpi_alloc (0);
k_1 = mpi_alloc (0);
x = mpi_alloc (0);
point_init (&I);
mpi_set_ui (s, 0);
mpi_set_ui (r, 0);
ctx = _gcry_mpi_ec_p_internal_new (skey->E.p, skey->E.a);
while (!mpi_cmp_ui (s, 0)) /* s == 0 */
{
while (!mpi_cmp_ui (r, 0)) /* r == 0 */
{
/* Note, that we are guaranteed to enter this loop at least
once because r has been intialized to 0. We can't use a
do_while because we want to keep the value of R even if S
has to be recomputed. */
mpi_free (k);
k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM);
_gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx);
if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx))
{
if (DBG_CIPHER)
log_debug ("ecc sign: Failed to get affine coordinates\n");
err = GPG_ERR_BAD_SIGNATURE;
goto leave;
}
mpi_mod (r, x, skey->E.n); /* r = x mod n */
}
mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */
mpi_addm (sum, input, dr, skey->E.n); /* sum = hash + (d*r) mod n */
mpi_invm (k_1, k, skey->E.n); /* k_1 = k^(-1) mod n */
mpi_mulm (s, k_1, sum, skey->E.n); /* s = k^(-1)*(hash+(d*r)) mod n */
}
if (DBG_CIPHER)
{
log_mpidump ("ecdsa sign result r ", r);
log_mpidump ("ecdsa sign result s ", s);
}
leave:
_gcry_mpi_ec_free (ctx);
point_free (&I);
mpi_free (x);
mpi_free (k_1);
mpi_free (sum);
mpi_free (dr);
mpi_free (k);
return err;
}
/*
* Check if R and S verifies INPUT.
*/
static gpg_err_code_t
verify (gcry_mpi_t input, ECC_public_key *pkey, gcry_mpi_t r, gcry_mpi_t s)
{
gpg_err_code_t err = 0;
gcry_mpi_t h, h1, h2, x, y;
mpi_point_struct Q, Q1, Q2;
mpi_ec_t ctx;
if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) )
return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */
if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) )
return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */
h = mpi_alloc (0);
h1 = mpi_alloc (0);
h2 = mpi_alloc (0);
x = mpi_alloc (0);
y = mpi_alloc (0);
point_init (&Q);
point_init (&Q1);
point_init (&Q2);
ctx = _gcry_mpi_ec_p_internal_new (pkey->E.p, pkey->E.a);
/* h = s^(-1) (mod n) */
mpi_invm (h, s, pkey->E.n);
/* log_mpidump (" h", h); */
/* h1 = hash * s^(-1) (mod n) */
mpi_mulm (h1, input, h, pkey->E.n);
/* log_mpidump (" h1", h1); */
/* Q1 = [ hash * s^(-1) ]G */
_gcry_mpi_ec_mul_point (&Q1, h1, &pkey->E.G, ctx);
/* log_mpidump ("Q1.x", Q1.x); */
/* log_mpidump ("Q1.y", Q1.y); */
/* log_mpidump ("Q1.z", Q1.z); */
/* h2 = r * s^(-1) (mod n) */
mpi_mulm (h2, r, h, pkey->E.n);
/* log_mpidump (" h2", h2); */
/* Q2 = [ r * s^(-1) ]Q */
_gcry_mpi_ec_mul_point (&Q2, h2, &pkey->Q, ctx);
/* log_mpidump ("Q2.x", Q2.x); */
/* log_mpidump ("Q2.y", Q2.y); */
/* log_mpidump ("Q2.z", Q2.z); */
/* Q = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */
_gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx);
/* log_mpidump (" Q.x", Q.x); */
/* log_mpidump (" Q.y", Q.y); */
/* log_mpidump (" Q.z", Q.z); */
if (!mpi_cmp_ui (Q.z, 0))
{
if (DBG_CIPHER)
log_debug ("ecc verify: Rejected\n");
err = GPG_ERR_BAD_SIGNATURE;
goto leave;
}
if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx))
{
if (DBG_CIPHER)
log_debug ("ecc verify: Failed to get affine coordinates\n");
err = GPG_ERR_BAD_SIGNATURE;
goto leave;
}
mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */
if (mpi_cmp (x, r)) /* x != r */
{
if (DBG_CIPHER)
{
log_mpidump (" x", x);
log_mpidump (" y", y);
log_mpidump (" r", r);
log_mpidump (" s", s);
log_debug ("ecc verify: Not verified\n");
}
err = GPG_ERR_BAD_SIGNATURE;
goto leave;
}
if (DBG_CIPHER)
log_debug ("ecc verify: Accepted\n");
leave:
_gcry_mpi_ec_free (ctx);
point_free (&Q2);
point_free (&Q1);
point_free (&Q);
mpi_free (y);
mpi_free (x);
mpi_free (h2);
mpi_free (h1);
mpi_free (h);
return err;
}
/*********************************************
************** interface ******************
*********************************************/
static gcry_mpi_t
ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p)
{
gpg_error_t err;
int pbytes = (mpi_get_nbits (p)+7)/8;
size_t n;
unsigned char *buf, *ptr;
gcry_mpi_t result;
buf = gcry_xmalloc ( 1 + 2*pbytes );
*buf = 04; /* Uncompressed point. */
ptr = buf+1;
err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x);
if (err)
log_fatal ("mpi_print failed: %s\n", gpg_strerror (err));
if (n < pbytes)
{
memmove (ptr+(pbytes-n), ptr, n);
memset (ptr, 0, (pbytes-n));
}
ptr += pbytes;
err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y);
if (err)
log_fatal ("mpi_print failed: %s\n", gpg_strerror (err));
if (n < pbytes)
{
memmove (ptr+(pbytes-n), ptr, n);
memset (ptr, 0, (pbytes-n));
}
err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, buf, 1+2*pbytes, NULL);
if (err)
log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err));
gcry_free (buf);
return result;
}
/* Convert POINT into affine coordinates using the context CTX and
return a newly allocated MPI. If the conversion is not possible
NULL is returned. This function won't print an error message. */
gcry_mpi_t
_gcry_mpi_ec_ec2os (gcry_mpi_point_t point, mpi_ec_t ectx)
{
gcry_mpi_t g_x, g_y, result;
g_x = mpi_new (0);
g_y = mpi_new (0);
if (_gcry_mpi_ec_get_affine (g_x, g_y, point, ectx))
result = NULL;
else
result = ec2os (g_x, g_y, ectx->p);
mpi_free (g_x);
mpi_free (g_y);
return result;
}
/* RESULT must have been initialized and is set on success to the
point given by VALUE. */
static gcry_error_t
os2ec (mpi_point_t result, gcry_mpi_t value)
{
gcry_error_t err;
size_t n;
unsigned char *buf;
gcry_mpi_t x, y;
n = (mpi_get_nbits (value)+7)/8;
buf = gcry_xmalloc (n);
err = gcry_mpi_print (GCRYMPI_FMT_USG, buf, n, &n, value);
if (err)
{
gcry_free (buf);
return err;
}
if (n < 1)
{
gcry_free (buf);
return GPG_ERR_INV_OBJ;
}
if (*buf != 4)
{
gcry_free (buf);
return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression. */
}
if ( ((n-1)%2) )
{
gcry_free (buf);
return GPG_ERR_INV_OBJ;
}
n = (n-1)/2;
err = gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL);
if (err)
{
gcry_free (buf);
return err;
}
err = gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL);
gcry_free (buf);
if (err)
{
mpi_free (x);
return err;
}
mpi_set (result->x, x);
mpi_set (result->y, y);
mpi_set_ui (result->z, 1);
mpi_free (x);
mpi_free (y);
return 0;
}
/* Extended version of ecc_generate. */
static gcry_err_code_t
ecc_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
const gcry_sexp_t genparms,
gcry_mpi_t *skey, gcry_mpi_t **retfactors,
gcry_sexp_t *r_extrainfo)
{
gpg_err_code_t ec;
ECC_secret_key sk;
gcry_mpi_t g_x, g_y, q_x, q_y;
char *curve_name = NULL;
gcry_sexp_t l1;
int transient_key = 0;
const char *usedcurve = NULL;
(void)algo;
(void)evalue;
if (genparms)
{
/* Parse the optional "curve" parameter. */
l1 = gcry_sexp_find_token (genparms, "curve", 0);
if (l1)
{
curve_name = _gcry_sexp_nth_string (l1, 1);
gcry_sexp_release (l1);
if (!curve_name)
return GPG_ERR_INV_OBJ; /* No curve name or value too large. */
}
/* Parse the optional transient-key flag. */
l1 = gcry_sexp_find_token (genparms, "transient-key", 0);
if (l1)
{
transient_key = 1;
gcry_sexp_release (l1);
}
}
/* NBITS is required if no curve name has been given. */
if (!nbits && !curve_name)
return GPG_ERR_NO_OBJ; /* No NBITS parameter. */
g_x = mpi_new (0);
g_y = mpi_new (0);
q_x = mpi_new (0);
q_y = mpi_new (0);
ec = generate_key (&sk, nbits, curve_name, transient_key, g_x, g_y, q_x, q_y,
&usedcurve);
gcry_free (curve_name);
if (ec)
return ec;
if (usedcurve) /* Fixme: No error return checking. */
gcry_sexp_build (r_extrainfo, NULL, "(curve %s)", usedcurve);
skey[0] = sk.E.p;
skey[1] = sk.E.a;
skey[2] = sk.E.b;
skey[3] = ec2os (g_x, g_y, sk.E.p);
skey[4] = sk.E.n;
skey[5] = ec2os (q_x, q_y, sk.E.p);
skey[6] = sk.d;
mpi_free (g_x);
mpi_free (g_y);
mpi_free (q_x);
mpi_free (q_y);
point_free (&sk.E.G);
point_free (&sk.Q);
/* Make an empty list of factors. */
*retfactors = gcry_calloc ( 1, sizeof **retfactors );
if (!*retfactors)
return gpg_err_code_from_syserror (); /* Fixme: relase mem? */
if (DBG_CIPHER)
{
log_mpidump ("ecgen result p", skey[0]);
log_mpidump ("ecgen result a", skey[1]);
log_mpidump ("ecgen result b", skey[2]);
log_mpidump ("ecgen result G", skey[3]);
log_mpidump ("ecgen result n", skey[4]);
log_mpidump ("ecgen result Q", skey[5]);
log_mpidump ("ecgen result d", skey[6]);
}
return 0;
}
static gcry_err_code_t
ecc_generate (int algo, unsigned int nbits, unsigned long evalue,
gcry_mpi_t *skey, gcry_mpi_t **retfactors)
{
(void)evalue;
return ecc_generate_ext (algo, nbits, 0, NULL, skey, retfactors, NULL);
}
/* Return the parameters of the curve NAME in an MPI array. */
static gcry_err_code_t
ecc_get_param (const char *name, gcry_mpi_t *pkey)
{
gpg_err_code_t err;
unsigned int nbits;
elliptic_curve_t E;
mpi_ec_t ctx;
gcry_mpi_t g_x, g_y;
err = fill_in_curve (0, name, &E, &nbits);
if (err)
return err;
g_x = mpi_new (0);
g_y = mpi_new (0);
ctx = _gcry_mpi_ec_p_internal_new (E.p, E.a);
if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx))
log_fatal ("ecc get param: Failed to get affine coordinates\n");
_gcry_mpi_ec_free (ctx);
point_free (&E.G);
pkey[0] = E.p;
pkey[1] = E.a;
pkey[2] = E.b;
pkey[3] = ec2os (g_x, g_y, E.p);
pkey[4] = E.n;
pkey[5] = NULL;
mpi_free (g_x);
mpi_free (g_y);
return 0;
}
/* Return the parameters of the curve NAME as an S-expression. */
static gcry_sexp_t
ecc_get_param_sexp (const char *name)
{
gcry_mpi_t pkey[6];
gcry_sexp_t result;
int i;
if (ecc_get_param (name, pkey))
return NULL;
if (gcry_sexp_build (&result, NULL,
"(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)))",
pkey[0], pkey[1], pkey[2], pkey[3], pkey[4]))
result = NULL;
for (i=0; pkey[i]; i++)
gcry_mpi_release (pkey[i]);
return result;
}
/* Return the name matching the parameters in PKEY. */
static const char *
ecc_get_curve (gcry_mpi_t *pkey, int iterator, unsigned int *r_nbits)
{
gpg_err_code_t err;
elliptic_curve_t E;
int idx;
gcry_mpi_t tmp;
const char *result = NULL;
if (r_nbits)
*r_nbits = 0;
if (!pkey)
{
idx = iterator;
if (idx >= 0 && idx < DIM (domain_parms))
{
result = domain_parms[idx].desc;
if (r_nbits)
*r_nbits = domain_parms[idx].nbits;
}
return result;
}
if (!pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] || !pkey[4])
return NULL;
E.p = pkey[0];
E.a = pkey[1];
E.b = pkey[2];
point_init (&E.G);
err = os2ec (&E.G, pkey[3]);
if (err)
{
point_free (&E.G);
return NULL;
}
E.n = pkey[4];
for (idx = 0; domain_parms[idx].desc; idx++)
{
tmp = scanval (domain_parms[idx].p);
if (!mpi_cmp (tmp, E.p))
{
mpi_free (tmp);
tmp = scanval (domain_parms[idx].a);
if (!mpi_cmp (tmp, E.a))
{
mpi_free (tmp);
tmp = scanval (domain_parms[idx].b);
if (!mpi_cmp (tmp, E.b))
{
mpi_free (tmp);
tmp = scanval (domain_parms[idx].n);
if (!mpi_cmp (tmp, E.n))
{
mpi_free (tmp);
tmp = scanval (domain_parms[idx].g_x);
if (!mpi_cmp (tmp, E.G.x))
{
mpi_free (tmp);
tmp = scanval (domain_parms[idx].g_y);
if (!mpi_cmp (tmp, E.G.y))
{
result = domain_parms[idx].desc;
if (r_nbits)
*r_nbits = domain_parms[idx].nbits;
break;
}
}
}
}
}
}
mpi_free (tmp);
}
point_free (&E.G);
return result;
}
static gcry_err_code_t
ecc_check_secret_key (int algo, gcry_mpi_t *skey)
{
gpg_err_code_t err;
ECC_secret_key sk;
(void)algo;
/* FIXME: This check looks a bit fishy: Now long is the array? */
if (!skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] || !skey[5]
|| !skey[6])
return GPG_ERR_BAD_MPI;
sk.E.p = skey[0];
sk.E.a = skey[1];
sk.E.b = skey[2];
point_init (&sk.E.G);
err = os2ec (&sk.E.G, skey[3]);
if (err)
{
point_free (&sk.E.G);
return err;
}
sk.E.n = skey[4];
point_init (&sk.Q);
err = os2ec (&sk.Q, skey[5]);
if (err)
{
point_free (&sk.E.G);
point_free (&sk.Q);
return err;
}
sk.d = skey[6];
if (check_secret_key (&sk))
{
point_free (&sk.E.G);
point_free (&sk.Q);
return GPG_ERR_BAD_SECKEY;
}
point_free (&sk.E.G);
point_free (&sk.Q);
return 0;
}
static gcry_err_code_t
ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
int flags, int hashalgo)
{
gpg_err_code_t err;
ECC_secret_key sk;
(void)algo;
(void)flags;
(void)hashalgo;
if (!data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4]
|| !skey[6] )
return GPG_ERR_BAD_MPI;
sk.E.p = skey[0];
sk.E.a = skey[1];
sk.E.b = skey[2];
point_init (&sk.E.G);
err = os2ec (&sk.E.G, skey[3]);
if (err)
{
point_free (&sk.E.G);
return err;
}
sk.E.n = skey[4];
/* Note: We don't have any need for Q here. */
sk.d = skey[6];
resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.E.p));
resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.E.p));
- err = sign (data, &sk, resarr[0], resarr[1]);
+
+ if (mpi_is_opaque (data))
+ {
+ const void *abuf;
+ unsigned int abits;
+ gcry_mpi_t a;
+
+ abuf = gcry_mpi_get_opaque (data, &abits);
+ err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, abits/8, NULL);
+ if (!err)
+ {
+ err = sign (a, &sk, resarr[0], resarr[1]);
+ gcry_mpi_release (a);
+ }
+ }
+ else
+ err = sign (data, &sk, resarr[0], resarr[1]);
+
if (err)
{
mpi_free (resarr[0]);
mpi_free (resarr[1]);
resarr[0] = NULL; /* Mark array as released. */
}
point_free (&sk.E.G);
return err;
}
static gcry_err_code_t
ecc_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
int (*cmp)(void *, gcry_mpi_t), void *opaquev)
{
gpg_err_code_t err;
ECC_public_key pk;
(void)algo;
(void)cmp;
(void)opaquev;
if (!data[0] || !data[1] || !hash || !pkey[0] || !pkey[1] || !pkey[2]
|| !pkey[3] || !pkey[4] || !pkey[5] )
return GPG_ERR_BAD_MPI;
pk.E.p = pkey[0];
pk.E.a = pkey[1];
pk.E.b = pkey[2];
point_init (&pk.E.G);
err = os2ec (&pk.E.G, pkey[3]);
if (err)
{
point_free (&pk.E.G);
return err;
}
pk.E.n = pkey[4];
point_init (&pk.Q);
err = os2ec (&pk.Q, pkey[5]);
if (err)
{
point_free (&pk.E.G);
point_free (&pk.Q);
return err;
}
- err = verify (hash, &pk, data[0], data[1]);
+ if (mpi_is_opaque (hash))
+ {
+ const void *abuf;
+ unsigned int abits;
+ gcry_mpi_t a;
+
+ abuf = gcry_mpi_get_opaque (hash, &abits);
+ err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, abits/8, NULL);
+ if (!err)
+ {
+ err = verify (a, &pk, data[0], data[1]);
+ gcry_mpi_release (a);
+ }
+ }
+ else
+ err = verify (hash, &pk, data[0], data[1]);
point_free (&pk.E.G);
point_free (&pk.Q);
return err;
}
/* ecdh raw is classic 2-round DH protocol published in 1976.
*
* Overview of ecc_encrypt_raw and ecc_decrypt_raw.
*
* As with any PK operation, encrypt version uses a public key and
* decrypt -- private.
*
* Symbols used below:
* G - field generator point
* d - private long-term scalar
* dG - public long-term key
* k - ephemeral scalar
* kG - ephemeral public key
* dkG - shared secret
*
* ecc_encrypt_raw description:
* input:
* data[0] : private scalar (k)
* output:
* result[0] : shared point (kdG)
* result[1] : generated ephemeral public key (kG)
*
* ecc_decrypt_raw description:
* input:
* data[0] : a point kG (ephemeral public key)
* output:
* result[0] : shared point (kdG)
*/
static gcry_err_code_t
ecc_encrypt_raw (int algo, gcry_mpi_t *resarr, gcry_mpi_t k,
gcry_mpi_t *pkey, int flags)
{
ECC_public_key pk;
mpi_ec_t ctx;
gcry_mpi_t result[2];
int err;
(void)algo;
(void)flags;
if (!k
|| !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] || !pkey[4] || !pkey[5])
return GPG_ERR_BAD_MPI;
pk.E.p = pkey[0];
pk.E.a = pkey[1];
pk.E.b = pkey[2];
point_init (&pk.E.G);
err = os2ec (&pk.E.G, pkey[3]);
if (err)
{
point_free (&pk.E.G);
return err;
}
pk.E.n = pkey[4];
point_init (&pk.Q);
err = os2ec (&pk.Q, pkey[5]);
if (err)
{
point_free (&pk.E.G);
point_free (&pk.Q);
return err;
}
ctx = _gcry_mpi_ec_p_internal_new (pk.E.p, pk.E.a);
/* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so */
{
mpi_point_struct R; /* Result that we return. */
gcry_mpi_t x, y;
x = mpi_new (0);
y = mpi_new (0);
point_init (&R);
/* R = kQ <=> R = kdG */
_gcry_mpi_ec_mul_point (&R, k, &pk.Q, ctx);
if (_gcry_mpi_ec_get_affine (x, y, &R, ctx))
log_fatal ("ecdh: Failed to get affine coordinates for kdG\n");
result[0] = ec2os (x, y, pk.E.p);
/* R = kG */
_gcry_mpi_ec_mul_point (&R, k, &pk.E.G, ctx);
if (_gcry_mpi_ec_get_affine (x, y, &R, ctx))
log_fatal ("ecdh: Failed to get affine coordinates for kG\n");
result[1] = ec2os (x, y, pk.E.p);
mpi_free (x);
mpi_free (y);
point_free (&R);
}
_gcry_mpi_ec_free (ctx);
point_free (&pk.E.G);
point_free (&pk.Q);
if (!result[0] || !result[1])
{
mpi_free (result[0]);
mpi_free (result[1]);
return GPG_ERR_ENOMEM;
}
/* Success. */
resarr[0] = result[0];
resarr[1] = result[1];
return 0;
}
/* input:
* data[0] : a point kG (ephemeral public key)
* output:
* resaddr[0] : shared point kdG
*
* see ecc_encrypt_raw for details.
*/
static gcry_err_code_t
ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
gcry_mpi_t *skey, int flags)
{
ECC_secret_key sk;
mpi_point_struct R; /* Result that we return. */
mpi_point_struct kG;
mpi_ec_t ctx;
gcry_mpi_t r;
int err;
(void)algo;
(void)flags;
*result = NULL;
if (!data || !data[0]
|| !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4]
|| !skey[5] || !skey[6] )
return GPG_ERR_BAD_MPI;
point_init (&kG);
err = os2ec (&kG, data[0]);
if (err)
{
point_free (&kG);
return err;
}
sk.E.p = skey[0];
sk.E.a = skey[1];
sk.E.b = skey[2];
point_init (&sk.E.G);
err = os2ec (&sk.E.G, skey[3]);
if (err)
{
point_free (&kG);
point_free (&sk.E.G);
return err;
}
sk.E.n = skey[4];
point_init (&sk.Q);
err = os2ec (&sk.Q, skey[5]);
if (err)
{
point_free (&kG);
point_free (&sk.E.G);
point_free (&sk.Q);
return err;
}
sk.d = skey[6];
ctx = _gcry_mpi_ec_p_internal_new (sk.E.p, sk.E.a);
/* R = dkG */
point_init (&R);
_gcry_mpi_ec_mul_point (&R, sk.d, &kG, ctx);
point_free (&kG);
/* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so: */
{
gcry_mpi_t x, y;
x = mpi_new (0);
y = mpi_new (0);
if (_gcry_mpi_ec_get_affine (x, y, &R, ctx))
log_fatal ("ecdh: Failed to get affine coordinates\n");
r = ec2os (x, y, sk.E.p);
mpi_free (x);
mpi_free (y);
}
point_free (&R);
_gcry_mpi_ec_free (ctx);
point_free (&kG);
point_free (&sk.E.G);
point_free (&sk.Q);
if (!r)
return GPG_ERR_ENOMEM;
/* Success. */
*result = r;
return 0;
}
static unsigned int
ecc_get_nbits (int algo, gcry_mpi_t *pkey)
{
(void)algo;
return mpi_get_nbits (pkey[0]);
}
/* See rsa.c for a description of this function. */
static gpg_err_code_t
compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
{
#define N_COMPONENTS 6
static const char names[N_COMPONENTS+1] = "pabgnq";
gpg_err_code_t ec = 0;
gcry_sexp_t l1;
gcry_mpi_t values[N_COMPONENTS];
int idx;
/* Clear the values for easier error cleanup. */
for (idx=0; idx < N_COMPONENTS; idx++)
values[idx] = NULL;
/* Fill values with all provided parameters. */
for (idx=0; idx < N_COMPONENTS; idx++)
{
l1 = gcry_sexp_find_token (keyparam, names+idx, 1);
if (l1)
{
values[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l1);
if (!values[idx])
{
ec = GPG_ERR_INV_OBJ;
goto leave;
}
}
}
/* Check whether a curve parameter is available and use that to fill
in missing values. */
l1 = gcry_sexp_find_token (keyparam, "curve", 5);
if (l1)
{
char *curve;
gcry_mpi_t tmpvalues[N_COMPONENTS];
for (idx = 0; idx < N_COMPONENTS; idx++)
tmpvalues[idx] = NULL;
curve = _gcry_sexp_nth_string (l1, 1);
gcry_sexp_release (l1);
if (!curve)
{
ec = GPG_ERR_INV_OBJ; /* Name missing or out of core. */
goto leave;
}
ec = ecc_get_param (curve, tmpvalues);
gcry_free (curve);
if (ec)
goto leave;
for (idx = 0; idx < N_COMPONENTS; idx++)
{
if (!values[idx])
values[idx] = tmpvalues[idx];
else
mpi_free (tmpvalues[idx]);
}
}
/* Check that all parameters are known and normalize all MPIs (that
should not be required but we use an internal function later and
thus we better make 100% sure that they are normalized). */
for (idx = 0; idx < N_COMPONENTS; idx++)
if (!values[idx])
{
ec = GPG_ERR_NO_OBJ;
goto leave;
}
else
_gcry_mpi_normalize (values[idx]);
/* Hash them all. */
for (idx = 0; idx < N_COMPONENTS; idx++)
{
char buf[30];
unsigned char *rawmpi;
unsigned int rawmpilen;
rawmpi = _gcry_mpi_get_buffer (values[idx], &rawmpilen, NULL);
if (!rawmpi)
{
ec = gpg_err_code_from_syserror ();
goto leave;
}
snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], rawmpilen);
gcry_md_write (md, buf, strlen (buf));
gcry_md_write (md, rawmpi, rawmpilen);
gcry_md_write (md, ")", 1);
gcry_free (rawmpi);
}
leave:
for (idx = 0; idx < N_COMPONENTS; idx++)
_gcry_mpi_release (values[idx]);
return ec;
#undef N_COMPONENTS
}
/*
Low-level API helper functions.
*/
/* Helper to extract an MPI from key parameters. */
static gpg_err_code_t
mpi_from_keyparam (gcry_mpi_t *r_a, gcry_sexp_t keyparam, const char *name)
{
gcry_err_code_t ec = 0;
gcry_sexp_t l1;
l1 = gcry_sexp_find_token (keyparam, name, 0);
if (l1)
{
*r_a = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l1);
if (!*r_a)
ec = GPG_ERR_INV_OBJ;
}
return ec;
}
/* Helper to extract a point from key parameters. If no parameter
with NAME is found, the functions tries to find a non-encoded point
by appending ".x", ".y" and ".z" to NAME. ".z" is in this case
optional and defaults to 1. */
static gpg_err_code_t
point_from_keyparam (gcry_mpi_point_t *r_a,
gcry_sexp_t keyparam, const char *name)
{
gcry_err_code_t ec;
gcry_mpi_t a = NULL;
gcry_mpi_point_t point;
ec = mpi_from_keyparam (&a, keyparam, name);
if (ec)
return ec;
if (a)
{
point = gcry_mpi_point_new (0);
ec = os2ec (point, a);
mpi_free (a);
if (ec)
{
gcry_mpi_point_release (point);
return ec;
}
}
else
{
char *tmpname;
gcry_mpi_t x = NULL;
gcry_mpi_t y = NULL;
gcry_mpi_t z = NULL;
tmpname = gcry_malloc (strlen (name) + 2 + 1);
if (!tmpname)
return gpg_err_code_from_syserror ();
strcpy (stpcpy (tmpname, name), ".x");
ec = mpi_from_keyparam (&x, keyparam, tmpname);
if (ec)
{
gcry_free (tmpname);
return ec;
}
strcpy (stpcpy (tmpname, name), ".y");
ec = mpi_from_keyparam (&y, keyparam, tmpname);
if (ec)
{
mpi_free (x);
gcry_free (tmpname);
return ec;
}
strcpy (stpcpy (tmpname, name), ".z");
ec = mpi_from_keyparam (&z, keyparam, tmpname);
if (ec)
{
mpi_free (y);
mpi_free (x);
gcry_free (tmpname);
return ec;
}
if (!z)
z = mpi_set_ui (NULL, 1);
if (x && y)
point = gcry_mpi_point_snatch_set (NULL, x, y, z);
else
{
mpi_free (x);
mpi_free (y);
mpi_free (z);
point = NULL;
}
gcry_free (tmpname);
}
if (point)
*r_a = point;
return 0;
}
/* This function creates a new context for elliptic curve operations.
Either KEYPARAM or CURVENAME must be given. If both are given and
KEYPARAM has no curve parameter CURVENAME is used to add missing
parameters. On success 0 is returned and the new context stored at
R_CTX. On error NULL is stored at R_CTX and an error code is
returned. The context needs to be released using
gcry_ctx_release. */
gpg_err_code_t
_gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
gcry_sexp_t keyparam, const char *curvename)
{
gpg_err_code_t errc;
gcry_ctx_t ctx = NULL;
gcry_mpi_t p = NULL;
gcry_mpi_t a = NULL;
gcry_mpi_t b = NULL;
gcry_mpi_point_t G = NULL;
gcry_mpi_t n = NULL;
gcry_mpi_point_t Q = NULL;
gcry_mpi_t d = NULL;
gcry_sexp_t l1;
*r_ctx = NULL;
if (keyparam)
{
errc = mpi_from_keyparam (&p, keyparam, "p");
if (errc)
goto leave;
errc = mpi_from_keyparam (&a, keyparam, "a");
if (errc)
goto leave;
errc = mpi_from_keyparam (&b, keyparam, "b");
if (errc)
goto leave;
errc = point_from_keyparam (&G, keyparam, "g");
if (errc)
goto leave;
errc = mpi_from_keyparam (&n, keyparam, "n");
if (errc)
goto leave;
errc = point_from_keyparam (&Q, keyparam, "q");
if (errc)
goto leave;
errc = mpi_from_keyparam (&d, keyparam, "d");
if (errc)
goto leave;
}
/* Check whether a curve parameter is available and use that to fill
in missing values. If no curve parameter is available try an
optional provided curvename. If only the curvename has been
given use that one. */
if (keyparam)
l1 = gcry_sexp_find_token (keyparam, "curve", 5);
else
l1 = NULL;
if (l1 || curvename)
{
char *name;
elliptic_curve_t *E;
if (l1)
{
name = _gcry_sexp_nth_string (l1, 1);
gcry_sexp_release (l1);
if (!name)
{
errc = GPG_ERR_INV_OBJ; /* Name missing or out of core. */
goto leave;
}
}
else
name = NULL;
E = gcry_calloc (1, sizeof *E);
if (!E)
{
errc = gpg_err_code_from_syserror ();
gcry_free (name);
goto leave;
}
errc = fill_in_curve (0, name? name : curvename, E, NULL);
gcry_free (name);
if (errc)
{
gcry_free (E);
goto leave;
}
if (!p)
{
p = E->p;
E->p = NULL;
}
if (!a)
{
a = E->a;
E->a = NULL;
}
if (!b)
{
b = E->b;
E->b = NULL;
}
if (!G)
{
G = gcry_mpi_point_snatch_set (NULL, E->G.x, E->G.y, E->G.z);
E->G.x = NULL;
E->G.y = NULL;
E->G.z = NULL;
}
if (!n)
{
n = E->n;
E->n = NULL;
}
curve_free (E);
gcry_free (E);
}
errc = _gcry_mpi_ec_p_new (&ctx, p, a);
if (!errc)
{
mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
if (b)
{
ec->b = b;
b = NULL;
}
if (G)
{
ec->G = G;
G = NULL;
}
if (n)
{
ec->n = n;
n = NULL;
}
if (Q)
{
ec->Q = Q;
Q = NULL;
}
if (d)
{
ec->d = d;
d = NULL;
}
*r_ctx = ctx;
}
leave:
mpi_free (p);
mpi_free (a);
mpi_free (b);
gcry_mpi_point_release (G);
mpi_free (n);
gcry_mpi_point_release (Q);
mpi_free (d);
return errc;
}
/* This is the wroker function for gcry_pubkey_get_sexp for ECC
algorithms. Note that the caller has already stored NULL at
R_SEXP. */
gpg_err_code_t
_gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec)
{
gpg_err_code_t rc;
gcry_mpi_t mpi_G = NULL;
gcry_mpi_t mpi_Q = NULL;
if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n)
return GPG_ERR_BAD_CRYPT_CTX;
if (mode == GCRY_PK_GET_SECKEY && !ec->d)
return GPG_ERR_NO_SECKEY;
/* Compute the public point if it is missing. */
if (!ec->Q && ec->d)
{
ec->Q = gcry_mpi_point_new (0);
_gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec);
}
/* Encode G and Q. */
mpi_G = _gcry_mpi_ec_ec2os (ec->G, ec);
if (!mpi_G)
{
rc = GPG_ERR_BROKEN_PUBKEY;
goto leave;
}
if (!ec->Q)
{
rc = GPG_ERR_BAD_CRYPT_CTX;
goto leave;
}
mpi_Q = _gcry_mpi_ec_ec2os (ec->Q, ec);
if (!mpi_Q)
{
rc = GPG_ERR_BROKEN_PUBKEY;
goto leave;
}
/* Fixme: We should return a curve name instead of the parameters if
if know that they match a curve. */
if (ec->d && (!mode || mode == GCRY_PK_GET_SECKEY))
{
/* Let's return a private key. */
rc = gpg_err_code
(gcry_sexp_build
(r_sexp, NULL,
"(private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)(d%m)))",
ec->p, ec->a, ec->b, mpi_G, ec->n, mpi_Q, ec->d));
}
else if (ec->Q)
{
/* Let's return a public key. */
rc = gpg_err_code
(gcry_sexp_build
(r_sexp, NULL,
"(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))",
ec->p, ec->a, ec->b, mpi_G, ec->n, mpi_Q));
}
else
rc = GPG_ERR_BAD_CRYPT_CTX;
leave:
mpi_free (mpi_Q);
mpi_free (mpi_G);
return rc;
}
/*
Self-test section.
*/
static gpg_err_code_t
selftests_ecdsa (selftest_report_func_t report)
{
const char *what;
const char *errtxt;
what = "low-level";
errtxt = NULL; /*selftest ();*/
if (errtxt)
goto failed;
/* FIXME: need more tests. */
return 0; /* Succeeded. */
failed:
if (report)
report ("pubkey", GCRY_PK_ECDSA, what, errtxt);
return GPG_ERR_SELFTEST_FAILED;
}
/* Run a full self-test for ALGO and return 0 on success. */
static gpg_err_code_t
run_selftests (int algo, int extended, selftest_report_func_t report)
{
gpg_err_code_t ec;
(void)extended;
switch (algo)
{
case GCRY_PK_ECDSA:
ec = selftests_ecdsa (report);
break;
default:
ec = GPG_ERR_PUBKEY_ALGO;
break;
}
return ec;
}
static const char *ecdsa_names[] =
{
"ecdsa",
"ecc",
NULL,
};
static const char *ecdh_names[] =
{
"ecdh",
"ecc",
NULL,
};
gcry_pk_spec_t _gcry_pubkey_spec_ecdsa =
{
"ECDSA", ecdsa_names,
"pabgnq", "pabgnqd", "", "rs", "pabgnq",
GCRY_PK_USAGE_SIGN,
ecc_generate,
ecc_check_secret_key,
NULL,
NULL,
ecc_sign,
ecc_verify,
ecc_get_nbits
};
gcry_pk_spec_t _gcry_pubkey_spec_ecdh =
{
"ECDH", ecdh_names,
"pabgnq", "pabgnqd", "se", "", "pabgnq",
GCRY_PK_USAGE_ENCR,
ecc_generate,
ecc_check_secret_key,
ecc_encrypt_raw,
ecc_decrypt_raw,
NULL,
NULL,
ecc_get_nbits
};
pk_extra_spec_t _gcry_pubkey_extraspec_ecdsa =
{
run_selftests,
ecc_generate_ext,
compute_keygrip,
ecc_get_param,
ecc_get_curve,
ecc_get_param_sexp
};
diff --git a/cipher/elgamal.c b/cipher/elgamal.c
index 128dd997..b40d1324 100644
--- a/cipher/elgamal.c
+++ b/cipher/elgamal.c
@@ -1,848 +1,854 @@
/* Elgamal.c - Elgamal Public Key encryption
* Copyright (C) 1998, 2000, 2001, 2002, 2003,
* 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* For a description of the algorithm, see:
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
* ISBN 0-471-11709-9. Pages 476 ff.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
typedef struct
{
gcry_mpi_t p; /* prime */
gcry_mpi_t g; /* group generator */
gcry_mpi_t y; /* g^x mod p */
} ELG_public_key;
typedef struct
{
gcry_mpi_t p; /* prime */
gcry_mpi_t g; /* group generator */
gcry_mpi_t y; /* g^x mod p */
gcry_mpi_t x; /* secret exponent */
} ELG_secret_key;
static int test_keys (ELG_secret_key *sk, unsigned int nbits, int nodie);
static gcry_mpi_t gen_k (gcry_mpi_t p, int small_k);
static void generate (ELG_secret_key *sk, unsigned nbits, gcry_mpi_t **factors);
static int check_secret_key (ELG_secret_key *sk);
static void do_encrypt (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input,
ELG_public_key *pkey);
static void decrypt (gcry_mpi_t output, gcry_mpi_t a, gcry_mpi_t b,
ELG_secret_key *skey);
static void sign (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input,
ELG_secret_key *skey);
static int verify (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input,
ELG_public_key *pkey);
static void (*progress_cb) (void *, const char *, int, int, int);
static void *progress_cb_data;
void
_gcry_register_pk_elg_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, "pk_elg", c, 0, 0);
}
/****************
* Michael Wiener's table on subgroup sizes to match field sizes.
* (floating around somewhere, probably based on the paper from
* Eurocrypt 96, page 332)
*/
static unsigned int
wiener_map( unsigned int n )
{
static struct { unsigned int p_n, q_n; } t[] =
{ /* p q attack cost */
{ 512, 119 }, /* 9 x 10^17 */
{ 768, 145 }, /* 6 x 10^21 */
{ 1024, 165 }, /* 7 x 10^24 */
{ 1280, 183 }, /* 3 x 10^27 */
{ 1536, 198 }, /* 7 x 10^29 */
{ 1792, 212 }, /* 9 x 10^31 */
{ 2048, 225 }, /* 8 x 10^33 */
{ 2304, 237 }, /* 5 x 10^35 */
{ 2560, 249 }, /* 3 x 10^37 */
{ 2816, 259 }, /* 1 x 10^39 */
{ 3072, 269 }, /* 3 x 10^40 */
{ 3328, 279 }, /* 8 x 10^41 */
{ 3584, 288 }, /* 2 x 10^43 */
{ 3840, 296 }, /* 4 x 10^44 */
{ 4096, 305 }, /* 7 x 10^45 */
{ 4352, 313 }, /* 1 x 10^47 */
{ 4608, 320 }, /* 2 x 10^48 */
{ 4864, 328 }, /* 2 x 10^49 */
{ 5120, 335 }, /* 3 x 10^50 */
{ 0, 0 }
};
int i;
for(i=0; t[i].p_n; i++ )
{
if( n <= t[i].p_n )
return t[i].q_n;
}
/* Not in table - use an arbitrary high number. */
return n / 8 + 200;
}
static int
test_keys ( ELG_secret_key *sk, unsigned int nbits, int nodie )
{
ELG_public_key pk;
gcry_mpi_t test = gcry_mpi_new ( 0 );
gcry_mpi_t out1_a = gcry_mpi_new ( nbits );
gcry_mpi_t out1_b = gcry_mpi_new ( nbits );
gcry_mpi_t out2 = gcry_mpi_new ( nbits );
int failed = 0;
pk.p = sk->p;
pk.g = sk->g;
pk.y = sk->y;
gcry_mpi_randomize ( test, nbits, GCRY_WEAK_RANDOM );
do_encrypt ( out1_a, out1_b, test, &pk );
decrypt ( out2, out1_a, out1_b, sk );
if ( mpi_cmp( test, out2 ) )
failed |= 1;
sign ( out1_a, out1_b, test, sk );
if ( !verify( out1_a, out1_b, test, &pk ) )
failed |= 2;
gcry_mpi_release ( test );
gcry_mpi_release ( out1_a );
gcry_mpi_release ( out1_b );
gcry_mpi_release ( out2 );
if (failed && !nodie)
log_fatal ("Elgamal test key for %s %s failed\n",
(failed & 1)? "encrypt+decrypt":"",
(failed & 2)? "sign+verify":"");
if (failed && DBG_CIPHER)
log_debug ("Elgamal test key for %s %s failed\n",
(failed & 1)? "encrypt+decrypt":"",
(failed & 2)? "sign+verify":"");
return failed;
}
/****************
* Generate a random secret exponent k from prime p, so that k is
* relatively prime to p-1. With SMALL_K set, k will be selected for
* better encryption performance - this must never be used signing!
*/
static gcry_mpi_t
gen_k( gcry_mpi_t p, int small_k )
{
gcry_mpi_t k = mpi_alloc_secure( 0 );
gcry_mpi_t temp = mpi_alloc( mpi_get_nlimbs(p) );
gcry_mpi_t p_1 = mpi_copy(p);
unsigned int orig_nbits = mpi_get_nbits(p);
unsigned int nbits, nbytes;
char *rndbuf = NULL;
if (small_k)
{
/* Using a k much lesser than p is sufficient for encryption and
* it greatly improves the encryption performance. We use
* Wiener's table and add a large safety margin. */
nbits = wiener_map( orig_nbits ) * 3 / 2;
if( nbits >= orig_nbits )
BUG();
}
else
nbits = orig_nbits;
nbytes = (nbits+7)/8;
if( DBG_CIPHER )
log_debug("choosing a random k ");
mpi_sub_ui( p_1, p, 1);
for(;;)
{
if( !rndbuf || nbits < 32 )
{
gcry_free(rndbuf);
rndbuf = gcry_random_bytes_secure( nbytes, GCRY_STRONG_RANDOM );
}
else
{
/* Change only some of the higher bits. We could improve
this by directly requesting more memory at the first call
to get_random_bytes() and use this the here maybe it is
easier to do this directly in random.c Anyway, it is
highly inlikely that we will ever reach this code. */
char *pp = gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM );
memcpy( rndbuf, pp, 4 );
gcry_free(pp);
}
_gcry_mpi_set_buffer( k, rndbuf, nbytes, 0 );
for(;;)
{
if( !(mpi_cmp( k, p_1 ) < 0) ) /* check: k < (p-1) */
{
if( DBG_CIPHER )
progress('+');
break; /* no */
}
if( !(mpi_cmp_ui( k, 0 ) > 0) ) /* check: k > 0 */
{
if( DBG_CIPHER )
progress('-');
break; /* no */
}
if (gcry_mpi_gcd( temp, k, p_1 ))
goto found; /* okay, k is relative prime to (p-1) */
mpi_add_ui( k, k, 1 );
if( DBG_CIPHER )
progress('.');
}
}
found:
gcry_free(rndbuf);
if( DBG_CIPHER )
progress('\n');
mpi_free(p_1);
mpi_free(temp);
return k;
}
/****************
* Generate a key pair with a key of size NBITS
* Returns: 2 structures filled with all needed values
* and an array with n-1 factors of (p-1)
*/
static void
generate ( ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t **ret_factors )
{
gcry_mpi_t p; /* the prime */
gcry_mpi_t p_min1;
gcry_mpi_t g;
gcry_mpi_t x; /* the secret exponent */
gcry_mpi_t y;
unsigned int qbits;
unsigned int xbits;
byte *rndbuf;
p_min1 = gcry_mpi_new ( nbits );
qbits = wiener_map( nbits );
if( qbits & 1 ) /* better have a even one */
qbits++;
g = mpi_alloc(1);
p = _gcry_generate_elg_prime( 0, nbits, qbits, g, ret_factors );
mpi_sub_ui(p_min1, p, 1);
/* Select a random number which has these properties:
* 0 < x < p-1
* This must be a very good random number because this is the
* secret part. The prime is public and may be shared anyway,
* so a random generator level of 1 is used for the prime.
*
* I don't see a reason to have a x of about the same size
* as the p. It should be sufficient to have one about the size
* of q or the later used k plus a large safety margin. Decryption
* will be much faster with such an x.
*/
xbits = qbits * 3 / 2;
if( xbits >= nbits )
BUG();
x = gcry_mpi_snew ( xbits );
if( DBG_CIPHER )
log_debug("choosing a random x of size %u", xbits );
rndbuf = NULL;
do
{
if( DBG_CIPHER )
progress('.');
if( rndbuf )
{ /* Change only some of the higher bits */
if( xbits < 16 ) /* should never happen ... */
{
gcry_free(rndbuf);
rndbuf = gcry_random_bytes_secure( (xbits+7)/8,
GCRY_VERY_STRONG_RANDOM );
}
else
{
char *r = gcry_random_bytes_secure( 2,
GCRY_VERY_STRONG_RANDOM );
memcpy(rndbuf, r, 2 );
gcry_free(r);
}
}
else
{
rndbuf = gcry_random_bytes_secure( (xbits+7)/8,
GCRY_VERY_STRONG_RANDOM );
}
_gcry_mpi_set_buffer( x, rndbuf, (xbits+7)/8, 0 );
mpi_clear_highbit( x, xbits+1 );
}
while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) );
gcry_free(rndbuf);
y = gcry_mpi_new (nbits);
gcry_mpi_powm( y, g, x, p );
if( DBG_CIPHER )
{
progress('\n');
log_mpidump("elg p= ", p );
log_mpidump("elg g= ", g );
log_mpidump("elg y= ", y );
log_mpidump("elg x= ", x );
}
/* Copy the stuff to the key structures */
sk->p = p;
sk->g = g;
sk->y = y;
sk->x = x;
gcry_mpi_release ( p_min1 );
/* Now we can test our keys (this should never fail!) */
test_keys ( sk, nbits - 64, 0 );
}
/* Generate a key pair with a key of size NBITS not using a random
value for the secret key but the one given as X. This is useful to
implement a passphrase based decryption for a public key based
encryption. It has appliactions in backup systems.
Returns: A structure filled with all needed values and an array
with n-1 factors of (p-1). */
static gcry_err_code_t
generate_using_x (ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t x,
gcry_mpi_t **ret_factors )
{
gcry_mpi_t p; /* The prime. */
gcry_mpi_t p_min1; /* The prime minus 1. */
gcry_mpi_t g; /* The generator. */
gcry_mpi_t y; /* g^x mod p. */
unsigned int qbits;
unsigned int xbits;
sk->p = NULL;
sk->g = NULL;
sk->y = NULL;
sk->x = NULL;
/* Do a quick check to see whether X is suitable. */
xbits = mpi_get_nbits (x);
if ( xbits < 64 || xbits >= nbits )
return GPG_ERR_INV_VALUE;
p_min1 = gcry_mpi_new ( nbits );
qbits = wiener_map ( nbits );
if ( (qbits & 1) ) /* Better have an even one. */
qbits++;
g = mpi_alloc (1);
p = _gcry_generate_elg_prime ( 0, nbits, qbits, g, ret_factors );
mpi_sub_ui (p_min1, p, 1);
if (DBG_CIPHER)
log_debug ("using a supplied x of size %u", xbits );
if ( !(mpi_cmp_ui ( x, 0 ) > 0 && mpi_cmp ( x, p_min1 ) <0 ) )
{
gcry_mpi_release ( p_min1 );
gcry_mpi_release ( p );
gcry_mpi_release ( g );
return GPG_ERR_INV_VALUE;
}
y = gcry_mpi_new (nbits);
gcry_mpi_powm ( y, g, x, p );
if ( DBG_CIPHER )
{
progress ('\n');
log_mpidump ("elg p= ", p );
log_mpidump ("elg g= ", g );
log_mpidump ("elg y= ", y );
log_mpidump ("elg x= ", x );
}
/* Copy the stuff to the key structures */
sk->p = p;
sk->g = g;
sk->y = y;
sk->x = gcry_mpi_copy (x);
gcry_mpi_release ( p_min1 );
/* Now we can test our keys. */
if ( test_keys ( sk, nbits - 64, 1 ) )
{
gcry_mpi_release ( sk->p ); sk->p = NULL;
gcry_mpi_release ( sk->g ); sk->g = NULL;
gcry_mpi_release ( sk->y ); sk->y = NULL;
gcry_mpi_release ( sk->x ); sk->x = NULL;
return GPG_ERR_BAD_SECKEY;
}
return 0;
}
/****************
* Test whether the secret key is valid.
* Returns: if this is a valid key.
*/
static int
check_secret_key( ELG_secret_key *sk )
{
int rc;
gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs(sk->y) );
gcry_mpi_powm( y, sk->g, sk->x, sk->p );
rc = !mpi_cmp( y, sk->y );
mpi_free( y );
return rc;
}
static void
do_encrypt(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey )
{
gcry_mpi_t k;
/* Note: maybe we should change the interface, so that it
* is possible to check that input is < p and return an
* error code.
*/
k = gen_k( pkey->p, 1 );
gcry_mpi_powm( a, pkey->g, k, pkey->p );
/* b = (y^k * input) mod p
* = ((y^k mod p) * (input mod p)) mod p
* and because input is < p
* = ((y^k mod p) * input) mod p
*/
gcry_mpi_powm( b, pkey->y, k, pkey->p );
gcry_mpi_mulm( b, b, input, pkey->p );
#if 0
if( DBG_CIPHER )
{
log_mpidump("elg encrypted y= ", pkey->y);
log_mpidump("elg encrypted p= ", pkey->p);
log_mpidump("elg encrypted k= ", k);
log_mpidump("elg encrypted M= ", input);
log_mpidump("elg encrypted a= ", a);
log_mpidump("elg encrypted b= ", b);
}
#endif
mpi_free(k);
}
static void
decrypt(gcry_mpi_t output, gcry_mpi_t a, gcry_mpi_t b, ELG_secret_key *skey )
{
gcry_mpi_t t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) );
/* output = b/(a^x) mod p */
gcry_mpi_powm( t1, a, skey->x, skey->p );
mpi_invm( t1, t1, skey->p );
mpi_mulm( output, b, t1, skey->p );
#if 0
if( DBG_CIPHER )
{
log_mpidump("elg decrypted x= ", skey->x);
log_mpidump("elg decrypted p= ", skey->p);
log_mpidump("elg decrypted a= ", a);
log_mpidump("elg decrypted b= ", b);
log_mpidump("elg decrypted M= ", output);
}
#endif
mpi_free(t1);
}
/****************
* Make an Elgamal signature out of INPUT
*/
static void
sign(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_secret_key *skey )
{
gcry_mpi_t k;
gcry_mpi_t t = mpi_alloc( mpi_get_nlimbs(a) );
gcry_mpi_t inv = mpi_alloc( mpi_get_nlimbs(a) );
gcry_mpi_t p_1 = mpi_copy(skey->p);
/*
* b = (t * inv) mod (p-1)
* b = (t * inv(k,(p-1),(p-1)) mod (p-1)
* b = (((M-x*a) mod (p-1)) * inv(k,(p-1),(p-1))) mod (p-1)
*
*/
mpi_sub_ui(p_1, p_1, 1);
k = gen_k( skey->p, 0 /* no small K ! */ );
gcry_mpi_powm( a, skey->g, k, skey->p );
mpi_mul(t, skey->x, a );
mpi_subm(t, input, t, p_1 );
mpi_invm(inv, k, p_1 );
mpi_mulm(b, t, inv, p_1 );
#if 0
if( DBG_CIPHER )
{
log_mpidump("elg sign p= ", skey->p);
log_mpidump("elg sign g= ", skey->g);
log_mpidump("elg sign y= ", skey->y);
log_mpidump("elg sign x= ", skey->x);
log_mpidump("elg sign k= ", k);
log_mpidump("elg sign M= ", input);
log_mpidump("elg sign a= ", a);
log_mpidump("elg sign b= ", b);
}
#endif
mpi_free(k);
mpi_free(t);
mpi_free(inv);
mpi_free(p_1);
}
/****************
* Returns true if the signature composed of A and B is valid.
*/
static int
verify(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey )
{
int rc;
gcry_mpi_t t1;
gcry_mpi_t t2;
gcry_mpi_t base[4];
gcry_mpi_t ex[4];
if( !(mpi_cmp_ui( a, 0 ) > 0 && mpi_cmp( a, pkey->p ) < 0) )
return 0; /* assertion 0 < a < p failed */
t1 = mpi_alloc( mpi_get_nlimbs(a) );
t2 = mpi_alloc( mpi_get_nlimbs(a) );
#if 0
/* t1 = (y^a mod p) * (a^b mod p) mod p */
gcry_mpi_powm( t1, pkey->y, a, pkey->p );
gcry_mpi_powm( t2, a, b, pkey->p );
mpi_mulm( t1, t1, t2, pkey->p );
/* t2 = g ^ input mod p */
gcry_mpi_powm( t2, pkey->g, input, pkey->p );
rc = !mpi_cmp( t1, t2 );
#elif 0
/* t1 = (y^a mod p) * (a^b mod p) mod p */
base[0] = pkey->y; ex[0] = a;
base[1] = a; ex[1] = b;
base[2] = NULL; ex[2] = NULL;
mpi_mulpowm( t1, base, ex, pkey->p );
/* t2 = g ^ input mod p */
gcry_mpi_powm( t2, pkey->g, input, pkey->p );
rc = !mpi_cmp( t1, t2 );
#else
/* t1 = g ^ - input * y ^ a * a ^ b mod p */
mpi_invm(t2, pkey->g, pkey->p );
base[0] = t2 ; ex[0] = input;
base[1] = pkey->y; ex[1] = a;
base[2] = a; ex[2] = b;
base[3] = NULL; ex[3] = NULL;
mpi_mulpowm( t1, base, ex, pkey->p );
rc = !mpi_cmp_ui( t1, 1 );
#endif
mpi_free(t1);
mpi_free(t2);
return rc;
}
/*********************************************
************** interface ******************
*********************************************/
static gpg_err_code_t
elg_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
const gcry_sexp_t genparms,
gcry_mpi_t *skey, gcry_mpi_t **retfactors,
gcry_sexp_t *r_extrainfo)
{
gpg_err_code_t ec;
ELG_secret_key sk;
gcry_mpi_t xvalue = NULL;
gcry_sexp_t l1;
(void)algo;
(void)evalue;
(void)r_extrainfo;
if (genparms)
{
/* Parse the optional xvalue element. */
l1 = gcry_sexp_find_token (genparms, "xvalue", 0);
if (l1)
{
xvalue = gcry_sexp_nth_mpi (l1, 1, 0);
gcry_sexp_release (l1);
if (!xvalue)
return GPG_ERR_BAD_MPI;
}
}
if (xvalue)
ec = generate_using_x (&sk, nbits, xvalue, retfactors);
else
{
generate (&sk, nbits, retfactors);
ec = 0;
}
skey[0] = sk.p;
skey[1] = sk.g;
skey[2] = sk.y;
skey[3] = sk.x;
return ec;
}
static gcry_err_code_t
elg_generate (int algo, unsigned int nbits, unsigned long evalue,
gcry_mpi_t *skey, gcry_mpi_t **retfactors)
{
ELG_secret_key sk;
(void)algo;
(void)evalue;
generate (&sk, nbits, retfactors);
skey[0] = sk.p;
skey[1] = sk.g;
skey[2] = sk.y;
skey[3] = sk.x;
return GPG_ERR_NO_ERROR;
}
static gcry_err_code_t
elg_check_secret_key (int algo, gcry_mpi_t *skey)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
ELG_secret_key sk;
(void)algo;
if ((! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]))
err = GPG_ERR_BAD_MPI;
else
{
sk.p = skey[0];
sk.g = skey[1];
sk.y = skey[2];
sk.x = skey[3];
if (! check_secret_key (&sk))
err = GPG_ERR_BAD_SECKEY;
}
return err;
}
static gcry_err_code_t
elg_encrypt (int algo, gcry_mpi_t *resarr,
gcry_mpi_t data, gcry_mpi_t *pkey, int flags)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
ELG_public_key pk;
(void)algo;
(void)flags;
if ((! data) || (! pkey[0]) || (! pkey[1]) || (! pkey[2]))
err = GPG_ERR_BAD_MPI;
else
{
pk.p = pkey[0];
pk.g = pkey[1];
pk.y = pkey[2];
resarr[0] = mpi_alloc (mpi_get_nlimbs (pk.p));
resarr[1] = mpi_alloc (mpi_get_nlimbs (pk.p));
do_encrypt (resarr[0], resarr[1], data, &pk);
}
return err;
}
static gcry_err_code_t
elg_decrypt (int algo, gcry_mpi_t *result,
gcry_mpi_t *data, gcry_mpi_t *skey, int flags)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
ELG_secret_key sk;
(void)algo;
(void)flags;
if ((! data[0]) || (! data[1])
|| (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]))
err = GPG_ERR_BAD_MPI;
else
{
sk.p = skey[0];
sk.g = skey[1];
sk.y = skey[2];
sk.x = skey[3];
*result = mpi_alloc_secure (mpi_get_nlimbs (sk.p));
decrypt (*result, data[0], data[1], &sk);
}
return err;
}
static gcry_err_code_t
elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
int flags, int hashalgo)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
ELG_secret_key sk;
(void)algo;
(void)flags;
(void)hashalgo;
+ if (mpi_is_opaque (data))
+ return GPG_ERR_INV_DATA;
+
if ((! data)
|| (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]))
err = GPG_ERR_BAD_MPI;
else
{
sk.p = skey[0];
sk.g = skey[1];
sk.y = skey[2];
sk.x = skey[3];
resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.p));
resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.p));
sign (resarr[0], resarr[1], data, &sk);
}
return err;
}
static gcry_err_code_t
elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
int (*cmp) (void *, gcry_mpi_t), void *opaquev)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
ELG_public_key pk;
(void)algo;
(void)cmp;
(void)opaquev;
+ if (mpi_is_opaque (hash))
+ return GPG_ERR_INV_DATA;
+
if ((! data[0]) || (! data[1]) || (! hash)
|| (! pkey[0]) || (! pkey[1]) || (! pkey[2]))
err = GPG_ERR_BAD_MPI;
else
{
pk.p = pkey[0];
pk.g = pkey[1];
pk.y = pkey[2];
if (! verify (data[0], data[1], hash, &pk))
err = GPG_ERR_BAD_SIGNATURE;
}
return err;
}
static unsigned int
elg_get_nbits (int algo, gcry_mpi_t *pkey)
{
(void)algo;
return mpi_get_nbits (pkey[0]);
}
static const char *elg_names[] =
{
"elg",
"openpgp-elg",
"openpgp-elg-sig",
NULL,
};
gcry_pk_spec_t _gcry_pubkey_spec_elg =
{
"ELG", elg_names,
"pgy", "pgyx", "ab", "rs", "pgy",
GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR,
elg_generate,
elg_check_secret_key,
elg_encrypt,
elg_decrypt,
elg_sign,
elg_verify,
elg_get_nbits
};
pk_extra_spec_t _gcry_pubkey_extraspec_elg =
{
NULL,
elg_generate_ext,
NULL
};
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 23a43589..606cedf8 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -1,4187 +1,4234 @@
/* pubkey.c - pubkey dispatcher
* Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005,
* 2007, 2008, 2011 Free Software Foundation, Inc.
* Copyright (C) 2013 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
#include "ath.h"
#include "context.h"
#include "pubkey-internal.h"
static gcry_err_code_t pubkey_decrypt (int algo, gcry_mpi_t *result,
gcry_mpi_t *data, gcry_mpi_t *skey,
int flags);
static gcry_err_code_t pubkey_sign (int algo, gcry_mpi_t *resarr,
- gcry_mpi_t hash, gcry_mpi_t *skey);
+ gcry_mpi_t hash, gcry_mpi_t *skey,
+ struct pk_encoding_ctx *ctx);
static gcry_err_code_t pubkey_verify (int algo, gcry_mpi_t hash,
gcry_mpi_t *data, gcry_mpi_t *pkey,
int (*cmp) (void *, gcry_mpi_t),
void *opaque);
/* A dummy extraspec so that we do not need to tests the extraspec
field from the module specification against NULL and instead
directly test the respective fields of extraspecs. */
static pk_extra_spec_t dummy_extra_spec;
/* This is the list of the default public-key ciphers included in
libgcrypt. FIPS_ALLOWED indicated whether the algorithm is used in
FIPS mode. */
static struct pubkey_table_entry
{
gcry_pk_spec_t *pubkey;
pk_extra_spec_t *extraspec;
unsigned int algorithm;
int fips_allowed;
} pubkey_table[] =
{
#if USE_RSA
{ &_gcry_pubkey_spec_rsa,
&_gcry_pubkey_extraspec_rsa, GCRY_PK_RSA, 1},
#endif
#if USE_ELGAMAL
{ &_gcry_pubkey_spec_elg,
&_gcry_pubkey_extraspec_elg, GCRY_PK_ELG },
{ &_gcry_pubkey_spec_elg,
&_gcry_pubkey_extraspec_elg, GCRY_PK_ELG_E },
#endif
#if USE_DSA
{ &_gcry_pubkey_spec_dsa,
&_gcry_pubkey_extraspec_dsa, GCRY_PK_DSA, 1 },
#endif
#if USE_ECC
{ &_gcry_pubkey_spec_ecdsa,
&_gcry_pubkey_extraspec_ecdsa, GCRY_PK_ECDSA, 0 },
{ &_gcry_pubkey_spec_ecdh,
&_gcry_pubkey_extraspec_ecdsa, GCRY_PK_ECDH, 0 },
#endif
{ NULL, 0 },
};
/* List of registered ciphers. */
static gcry_module_t pubkeys_registered;
/* This is the lock protecting PUBKEYS_REGISTERED. */
static ath_mutex_t pubkeys_registered_lock;
/* Flag to check whether the default pubkeys have already been
registered. */
static int default_pubkeys_registered;
/* Convenient macro for registering the default digests. */
#define REGISTER_DEFAULT_PUBKEYS \
do \
{ \
ath_mutex_lock (&pubkeys_registered_lock); \
if (! default_pubkeys_registered) \
{ \
pk_register_default (); \
default_pubkeys_registered = 1; \
} \
ath_mutex_unlock (&pubkeys_registered_lock); \
} \
while (0)
/* These dummy functions are used in case a cipher implementation
refuses to provide it's own functions. */
static gcry_err_code_t
dummy_generate (int algorithm, unsigned int nbits, unsigned long dummy,
gcry_mpi_t *skey, gcry_mpi_t **retfactors)
{
(void)algorithm;
(void)nbits;
(void)dummy;
(void)skey;
(void)retfactors;
fips_signal_error ("using dummy public key function");
return GPG_ERR_NOT_IMPLEMENTED;
}
static gcry_err_code_t
dummy_check_secret_key (int algorithm, gcry_mpi_t *skey)
{
(void)algorithm;
(void)skey;
fips_signal_error ("using dummy public key function");
return GPG_ERR_NOT_IMPLEMENTED;
}
static gcry_err_code_t
dummy_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
gcry_mpi_t *pkey, int flags)
{
(void)algorithm;
(void)resarr;
(void)data;
(void)pkey;
(void)flags;
fips_signal_error ("using dummy public key function");
return GPG_ERR_NOT_IMPLEMENTED;
}
static gcry_err_code_t
dummy_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data,
gcry_mpi_t *skey, int flags)
{
(void)algorithm;
(void)result;
(void)data;
(void)skey;
(void)flags;
fips_signal_error ("using dummy public key function");
return GPG_ERR_NOT_IMPLEMENTED;
}
static gcry_err_code_t
dummy_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
gcry_mpi_t *skey,
int flags, int hashalgo)
{
(void)algorithm;
(void)resarr;
(void)data;
(void)skey;
(void)flags;
(void)hashalgo;
fips_signal_error ("using dummy public key function");
return GPG_ERR_NOT_IMPLEMENTED;
}
static gcry_err_code_t
dummy_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data,
gcry_mpi_t *pkey,
int (*cmp) (void *, gcry_mpi_t), void *opaquev)
{
(void)algorithm;
(void)hash;
(void)data;
(void)pkey;
(void)cmp;
(void)opaquev;
fips_signal_error ("using dummy public key function");
return GPG_ERR_NOT_IMPLEMENTED;
}
static unsigned
dummy_get_nbits (int algorithm, gcry_mpi_t *pkey)
{
(void)algorithm;
(void)pkey;
fips_signal_error ("using dummy public key function");
return 0;
}
/* Internal function. Register all the pubkeys included in
PUBKEY_TABLE. Returns zero on success or an error code. */
static void
pk_register_default (void)
{
gcry_err_code_t err = 0;
int i;
for (i = 0; (! err) && pubkey_table[i].pubkey; i++)
{
#define pubkey_use_dummy(func) \
if (! pubkey_table[i].pubkey->func) \
pubkey_table[i].pubkey->func = dummy_##func;
pubkey_use_dummy (generate);
pubkey_use_dummy (check_secret_key);
pubkey_use_dummy (encrypt);
pubkey_use_dummy (decrypt);
pubkey_use_dummy (sign);
pubkey_use_dummy (verify);
pubkey_use_dummy (get_nbits);
#undef pubkey_use_dummy
err = _gcry_module_add (&pubkeys_registered,
pubkey_table[i].algorithm,
(void *) pubkey_table[i].pubkey,
(void *) pubkey_table[i].extraspec,
NULL);
}
if (err)
BUG ();
}
/* Internal callback function. Used via _gcry_module_lookup. */
static int
gcry_pk_lookup_func_name (void *spec, void *data)
{
gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) spec;
char *name = (char *) data;
const char **aliases = pubkey->aliases;
int ret = stricmp (name, pubkey->name);
while (ret && *aliases)
ret = stricmp (name, *aliases++);
return ! ret;
}
/* Internal function. Lookup a pubkey entry by it's name. */
static gcry_module_t
gcry_pk_lookup_name (const char *name)
{
gcry_module_t pubkey;
pubkey = _gcry_module_lookup (pubkeys_registered, (void *) name,
gcry_pk_lookup_func_name);
return pubkey;
}
/* Register a new pubkey module whose specification can be found in
PUBKEY. On success, a new algorithm ID is stored in ALGORITHM_ID
and a pointer representhing this module is stored in MODULE. */
gcry_error_t
_gcry_pk_register (gcry_pk_spec_t *pubkey,
pk_extra_spec_t *extraspec,
unsigned int *algorithm_id,
gcry_module_t *module)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_module_t mod;
/* We do not support module loading in fips mode. */
if (fips_mode ())
return gpg_error (GPG_ERR_NOT_SUPPORTED);
ath_mutex_lock (&pubkeys_registered_lock);
err = _gcry_module_add (&pubkeys_registered, 0,
(void *) pubkey,
(void *)(extraspec? extraspec : &dummy_extra_spec),
&mod);
ath_mutex_unlock (&pubkeys_registered_lock);
if (! err)
{
*module = mod;
*algorithm_id = mod->mod_id;
}
return err;
}
/* Unregister the pubkey identified by ID, which must have been
registered with gcry_pk_register. */
void
_gcry_pk_unregister (gcry_module_t module)
{
ath_mutex_lock (&pubkeys_registered_lock);
_gcry_module_release (module);
ath_mutex_unlock (&pubkeys_registered_lock);
}
static void
release_mpi_array (gcry_mpi_t *array)
{
for (; *array; array++)
{
mpi_free(*array);
*array = NULL;
}
}
/****************
* Map a string to the pubkey algo
*/
int
gcry_pk_map_name (const char *string)
{
gcry_module_t pubkey;
int algorithm = 0;
if (!string)
return 0;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
pubkey = gcry_pk_lookup_name (string);
if (pubkey)
{
algorithm = pubkey->mod_id;
_gcry_module_release (pubkey);
}
ath_mutex_unlock (&pubkeys_registered_lock);
return algorithm;
}
/* Map the public key algorithm whose ID is contained in ALGORITHM to
a string representation of the algorithm name. For unknown
algorithm IDs this functions returns "?". */
const char *
gcry_pk_algo_name (int algorithm)
{
gcry_module_t pubkey;
const char *name;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (pubkey)
{
name = ((gcry_pk_spec_t *) pubkey->spec)->name;
_gcry_module_release (pubkey);
}
else
name = "?";
ath_mutex_unlock (&pubkeys_registered_lock);
return name;
}
/* A special version of gcry_pk_algo name to return the first aliased
name of the algorithm. This is required to adhere to the spki
specs where the algorithm names are lowercase. */
const char *
_gcry_pk_aliased_algo_name (int algorithm)
{
const char *name = NULL;
gcry_module_t module;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (module)
{
gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) module->spec;
name = pubkey->aliases? *pubkey->aliases : NULL;
if (!name || !*name)
name = pubkey->name;
_gcry_module_release (module);
}
ath_mutex_unlock (&pubkeys_registered_lock);
return name;
}
static void
disable_pubkey_algo (int algorithm)
{
gcry_module_t pubkey;
ath_mutex_lock (&pubkeys_registered_lock);
pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (pubkey)
{
if (! (pubkey-> flags & FLAG_MODULE_DISABLED))
pubkey->flags |= FLAG_MODULE_DISABLED;
_gcry_module_release (pubkey);
}
ath_mutex_unlock (&pubkeys_registered_lock);
}
/****************
* A USE of 0 means: don't care.
*/
static gcry_err_code_t
check_pubkey_algo (int algorithm, unsigned use)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_pk_spec_t *pubkey;
gcry_module_t module;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (module)
{
pubkey = (gcry_pk_spec_t *) module->spec;
if (((use & GCRY_PK_USAGE_SIGN)
&& (! (pubkey->use & GCRY_PK_USAGE_SIGN)))
|| ((use & GCRY_PK_USAGE_ENCR)
&& (! (pubkey->use & GCRY_PK_USAGE_ENCR))))
err = GPG_ERR_WRONG_PUBKEY_ALGO;
else if (module->flags & FLAG_MODULE_DISABLED)
err = GPG_ERR_PUBKEY_ALGO;
_gcry_module_release (module);
}
else
err = GPG_ERR_PUBKEY_ALGO;
ath_mutex_unlock (&pubkeys_registered_lock);
return err;
}
/****************
* Return the number of public key material numbers
*/
static int
pubkey_get_npkey (int algorithm)
{
gcry_module_t pubkey;
int npkey = 0;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (pubkey)
{
npkey = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_pkey);
_gcry_module_release (pubkey);
}
ath_mutex_unlock (&pubkeys_registered_lock);
return npkey;
}
/****************
* Return the number of secret key material numbers
*/
static int
pubkey_get_nskey (int algorithm)
{
gcry_module_t pubkey;
int nskey = 0;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (pubkey)
{
nskey = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_skey);
_gcry_module_release (pubkey);
}
ath_mutex_unlock (&pubkeys_registered_lock);
return nskey;
}
/****************
* Return the number of signature material numbers
*/
static int
pubkey_get_nsig (int algorithm)
{
gcry_module_t pubkey;
int nsig = 0;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (pubkey)
{
nsig = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_sig);
_gcry_module_release (pubkey);
}
ath_mutex_unlock (&pubkeys_registered_lock);
return nsig;
}
/****************
* Return the number of encryption material numbers
*/
static int
pubkey_get_nenc (int algorithm)
{
gcry_module_t pubkey;
int nenc = 0;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (pubkey)
{
nenc = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_enc);
_gcry_module_release (pubkey);
}
ath_mutex_unlock (&pubkeys_registered_lock);
return nenc;
}
/* Generate a new public key with algorithm ALGORITHM of size NBITS
and return it at SKEY. USE_E depends on the ALGORITHM. GENPARMS
is passed to the algorithm module if it features an extended
generation function. RETFACTOR is used by some algorithms to
return certain additional information which are in general not
required.
The function returns the error code number or 0 on success. */
static gcry_err_code_t
pubkey_generate (int algorithm,
unsigned int nbits,
unsigned long use_e,
gcry_sexp_t genparms,
gcry_mpi_t *skey, gcry_mpi_t **retfactors,
gcry_sexp_t *r_extrainfo)
{
gcry_err_code_t ec = GPG_ERR_PUBKEY_ALGO;
gcry_module_t pubkey;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (pubkey)
{
pk_extra_spec_t *extraspec = pubkey->extraspec;
if (extraspec && extraspec->ext_generate)
{
/* Use the extended generate function. */
ec = extraspec->ext_generate
(algorithm, nbits, use_e, genparms, skey, retfactors, r_extrainfo);
}
else
{
/* Use the standard generate function. */
ec = ((gcry_pk_spec_t *) pubkey->spec)->generate
(algorithm, nbits, use_e, skey, retfactors);
}
_gcry_module_release (pubkey);
}
ath_mutex_unlock (&pubkeys_registered_lock);
return ec;
}
static gcry_err_code_t
pubkey_check_secret_key (int algorithm, gcry_mpi_t *skey)
{
gcry_err_code_t err = GPG_ERR_PUBKEY_ALGO;
gcry_module_t pubkey;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (pubkey)
{
err = ((gcry_pk_spec_t *) pubkey->spec)->check_secret_key
(algorithm, skey);
_gcry_module_release (pubkey);
}
ath_mutex_unlock (&pubkeys_registered_lock);
return err;
}
/****************
* This is the interface to the public key encryption. Encrypt DATA
* with PKEY and put it into RESARR which should be an array of MPIs
* of size PUBKEY_MAX_NENC (or less if the algorithm allows this -
* check with pubkey_get_nenc() )
*/
static gcry_err_code_t
pubkey_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
gcry_mpi_t *pkey, int flags)
{
gcry_pk_spec_t *pubkey;
gcry_module_t module;
gcry_err_code_t rc;
int i;
/* Note: In fips mode DBG_CIPHER will enver evaluate to true but as
an extra failsafe protection we explicitly test for fips mode
here. */
if (DBG_CIPHER && !fips_mode ())
{
log_debug ("pubkey_encrypt: algo=%d\n", algorithm);
for(i = 0; i < pubkey_get_npkey (algorithm); i++)
log_mpidump (" pkey:", pkey[i]);
log_mpidump (" data:", data);
}
ath_mutex_lock (&pubkeys_registered_lock);
module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (module)
{
pubkey = (gcry_pk_spec_t *) module->spec;
rc = pubkey->encrypt (algorithm, resarr, data, pkey, flags);
_gcry_module_release (module);
goto ready;
}
rc = GPG_ERR_PUBKEY_ALGO;
ready:
ath_mutex_unlock (&pubkeys_registered_lock);
if (!rc && DBG_CIPHER && !fips_mode ())
{
for(i = 0; i < pubkey_get_nenc (algorithm); i++)
log_mpidump(" encr:", resarr[i] );
}
return rc;
}
/****************
* This is the interface to the public key decryption.
* ALGO gives the algorithm to use and this implicitly determines
* the size of the arrays.
* result is a pointer to a mpi variable which will receive a
* newly allocated mpi or NULL in case of an error.
*/
static gcry_err_code_t
pubkey_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data,
gcry_mpi_t *skey, int flags)
{
gcry_pk_spec_t *pubkey;
gcry_module_t module;
gcry_err_code_t rc;
int i;
*result = NULL; /* so the caller can always do a mpi_free */
if (DBG_CIPHER && !fips_mode ())
{
log_debug ("pubkey_decrypt: algo=%d\n", algorithm);
for(i = 0; i < pubkey_get_nskey (algorithm); i++)
log_mpidump (" skey:", skey[i]);
for(i = 0; i < pubkey_get_nenc (algorithm); i++)
log_mpidump (" data:", data[i]);
}
ath_mutex_lock (&pubkeys_registered_lock);
module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (module)
{
pubkey = (gcry_pk_spec_t *) module->spec;
rc = pubkey->decrypt (algorithm, result, data, skey, flags);
_gcry_module_release (module);
goto ready;
}
rc = GPG_ERR_PUBKEY_ALGO;
ready:
ath_mutex_unlock (&pubkeys_registered_lock);
if (!rc && DBG_CIPHER && !fips_mode ())
log_mpidump (" plain:", *result);
return rc;
}
/****************
* This is the interface to the public key signing.
* Sign data with skey and put the result into resarr which
* should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the
* algorithm allows this - check with pubkey_get_nsig() )
*/
static gcry_err_code_t
pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
- gcry_mpi_t *skey)
+ gcry_mpi_t *skey, struct pk_encoding_ctx *ctx)
{
gcry_pk_spec_t *pubkey;
gcry_module_t module;
gcry_err_code_t rc;
int i;
if (DBG_CIPHER && !fips_mode ())
{
log_debug ("pubkey_sign: algo=%d\n", algorithm);
for(i = 0; i < pubkey_get_nskey (algorithm); i++)
log_mpidump (" skey:", skey[i]);
log_mpidump(" data:", data );
}
ath_mutex_lock (&pubkeys_registered_lock);
module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (module)
{
pubkey = (gcry_pk_spec_t *) module->spec;
- rc = pubkey->sign (algorithm, resarr, data, skey, 0, 0);
+ rc = pubkey->sign (algorithm, resarr, data, skey,
+ ctx->flags, ctx->hash_algo);
_gcry_module_release (module);
goto ready;
}
rc = GPG_ERR_PUBKEY_ALGO;
ready:
ath_mutex_unlock (&pubkeys_registered_lock);
if (!rc && DBG_CIPHER && !fips_mode ())
for (i = 0; i < pubkey_get_nsig (algorithm); i++)
log_mpidump (" sig:", resarr[i]);
return rc;
}
/****************
* Verify a public key signature.
* Return 0 if the signature is good
*/
static gcry_err_code_t
pubkey_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data,
gcry_mpi_t *pkey,
int (*cmp)(void *, gcry_mpi_t), void *opaquev)
{
gcry_pk_spec_t *pubkey;
gcry_module_t module;
gcry_err_code_t rc;
int i;
if (DBG_CIPHER && !fips_mode ())
{
log_debug ("pubkey_verify: algo=%d\n", algorithm);
for (i = 0; i < pubkey_get_npkey (algorithm); i++)
log_mpidump (" pkey", pkey[i]);
for (i = 0; i < pubkey_get_nsig (algorithm); i++)
log_mpidump (" sig", data[i]);
log_mpidump (" hash", hash);
}
ath_mutex_lock (&pubkeys_registered_lock);
module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (module)
{
pubkey = (gcry_pk_spec_t *) module->spec;
rc = pubkey->verify (algorithm, hash, data, pkey, cmp, opaquev);
_gcry_module_release (module);
goto ready;
}
rc = GPG_ERR_PUBKEY_ALGO;
ready:
ath_mutex_unlock (&pubkeys_registered_lock);
return rc;
}
/* Turn VALUE into an octet string and store it in an allocated buffer
at R_FRAME or - if R_RAME is NULL - copy it into the caller
provided buffer SPACE; either SPACE or R_FRAME may be used. If
SPACE if not NULL, the caller must provide a buffer of at least
NBYTES. If the resulting octet string is shorter than NBYTES pad
it to the left with zeroes. If VALUE does not fit into NBYTES
return an error code. */
static gpg_err_code_t
octet_string_from_mpi (unsigned char **r_frame, void *space,
gcry_mpi_t value, size_t nbytes)
{
gpg_err_code_t rc;
size_t nframe, noff, n;
unsigned char *frame;
if (!r_frame == !space)
return GPG_ERR_INV_ARG; /* Only one may be used. */
if (r_frame)
*r_frame = NULL;
rc = gcry_err_code (gcry_mpi_print (GCRYMPI_FMT_USG,
NULL, 0, &nframe, value));
if (rc)
return rc;
if (nframe > nbytes)
return GPG_ERR_TOO_LARGE; /* Value too long to fit into NBYTES. */
noff = (nframe < nbytes)? nbytes - nframe : 0;
n = nframe + noff;
if (space)
frame = space;
else
{
frame = mpi_is_secure (value)? gcry_malloc_secure (n) : gcry_malloc (n);
if (!frame)
{
rc = gpg_err_code_from_syserror ();
return rc;
}
}
if (noff)
memset (frame, 0, noff);
nframe += noff;
rc = gcry_err_code (gcry_mpi_print (GCRYMPI_FMT_USG,
frame+noff, nframe-noff, NULL, value));
if (rc)
{
gcry_free (frame);
return rc;
}
if (r_frame)
*r_frame = frame;
return 0;
}
/* Encode {VALUE,VALUELEN} for an NBITS keys using the pkcs#1 block
type 2 padding. On sucess the result is stored as a new MPI at
R_RESULT. On error the value at R_RESULT is undefined.
If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
the seed instead of using a random string for it. This feature is
only useful for regression tests. Note that this value may not
contain zero bytes.
We encode the value in this way:
0 2 RND(n bytes) 0 VALUE
0 is a marker we unfortunately can't encode because we return an
MPI which strips all leading zeroes.
2 is the block type.
RND are non-zero random bytes.
(Note that OpenPGP includes the cipher algorithm and a checksum in
VALUE; the caller needs to prepare the value accordingly.)
*/
static gcry_err_code_t
pkcs1_encode_for_encryption (gcry_mpi_t *r_result, unsigned int nbits,
const unsigned char *value, size_t valuelen,
const unsigned char *random_override,
size_t random_override_len)
{
gcry_err_code_t rc = 0;
gcry_error_t err;
unsigned char *frame = NULL;
size_t nframe = (nbits+7) / 8;
int i;
size_t n;
unsigned char *p;
if (valuelen + 7 > nframe || !nframe)
{
/* Can't encode a VALUELEN value in a NFRAME bytes frame. */
return GPG_ERR_TOO_SHORT; /* The key is too short. */
}
if ( !(frame = gcry_malloc_secure (nframe)))
return gpg_err_code_from_syserror ();
n = 0;
frame[n++] = 0;
frame[n++] = 2; /* block type */
i = nframe - 3 - valuelen;
gcry_assert (i > 0);
if (random_override)
{
int j;
if (random_override_len != i)
{
gcry_free (frame);
return GPG_ERR_INV_ARG;
}
/* Check that random does not include a zero byte. */
for (j=0; j < random_override_len; j++)
if (!random_override[j])
{
gcry_free (frame);
return GPG_ERR_INV_ARG;
}
memcpy (frame + n, random_override, random_override_len);
n += random_override_len;
}
else
{
p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
/* Replace zero bytes by new values. */
for (;;)
{
int j, k;
unsigned char *pp;
/* Count the zero bytes. */
for (j=k=0; j < i; j++)
{
if (!p[j])
k++;
}
if (!k)
break; /* Okay: no (more) zero bytes. */
k += k/128 + 3; /* Better get some more. */
pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
for (j=0; j < i && k; )
{
if (!p[j])
p[j] = pp[--k];
if (p[j])
j++;
}
gcry_free (pp);
}
memcpy (frame+n, p, i);
n += i;
gcry_free (p);
}
frame[n++] = 0;
memcpy (frame+n, value, valuelen);
n += valuelen;
gcry_assert (n == nframe);
err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, n, &nframe);
if (err)
rc = gcry_err_code (err);
else if (DBG_CIPHER)
log_mpidump ("PKCS#1 block type 2 encoded data", *r_result);
gcry_free (frame);
return rc;
}
/* Decode a plaintext in VALUE assuming pkcs#1 block type 2 padding.
NBITS is the size of the secret key. On success the result is
stored as a newly allocated buffer at R_RESULT and its valid length at
R_RESULTLEN. On error NULL is stored at R_RESULT. */
static gcry_err_code_t
pkcs1_decode_for_encryption (unsigned char **r_result, size_t *r_resultlen,
unsigned int nbits, gcry_mpi_t value)
{
gcry_error_t err;
unsigned char *frame = NULL;
size_t nframe = (nbits+7) / 8;
size_t n;
*r_result = NULL;
if ( !(frame = gcry_malloc_secure (nframe)))
return gpg_err_code_from_syserror ();
err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &n, value);
if (err)
{
gcry_free (frame);
return gcry_err_code (err);
}
nframe = n; /* Set NFRAME to the actual length. */
/* FRAME = 0x00 || 0x02 || PS || 0x00 || M
pkcs#1 requires that the first byte is zero. Our MPIs usually
strip leading zero bytes; thus we are not able to detect them.
However due to the way gcry_mpi_print is implemented we may see
leading zero bytes nevertheless. We handle this by making the
first zero byte optional. */
if (nframe < 4)
{
gcry_free (frame);
return GPG_ERR_ENCODING_PROBLEM; /* Too short. */
}
n = 0;
if (!frame[0])
n++;
if (frame[n++] != 0x02)
{
gcry_free (frame);
return GPG_ERR_ENCODING_PROBLEM; /* Wrong block type. */
}
/* Skip the non-zero random bytes and the terminating zero byte. */
for (; n < nframe && frame[n] != 0x00; n++)
;
if (n+1 >= nframe)
{
gcry_free (frame);
return GPG_ERR_ENCODING_PROBLEM; /* No zero byte. */
}
n++; /* Skip the zero byte. */
/* To avoid an extra allocation we reuse the frame buffer. The only
caller of this function will anyway free the result soon. */
memmove (frame, frame + n, nframe - n);
*r_result = frame;
*r_resultlen = nframe - n;
if (DBG_CIPHER)
log_printhex ("value extracted from PKCS#1 block type 2 encoded data:",
*r_result, *r_resultlen);
return 0;
}
/* Encode {VALUE,VALUELEN} for an NBITS keys and hash algorith ALGO
using the pkcs#1 block type 1 padding. On success the result is
stored as a new MPI at R_RESULT. On error the value at R_RESULT is
undefined.
We encode the value in this way:
0 1 PAD(n bytes) 0 ASN(asnlen bytes) VALUE(valuelen bytes)
0 is a marker we unfortunately can't encode because we return an
MPI which strips all leading zeroes.
1 is the block type.
PAD consists of 0xff bytes.
0 marks the end of the padding.
ASN is the DER encoding of the hash algorithm; along with the VALUE
it yields a valid DER encoding.
(Note that PGP prior to version 2.3 encoded the message digest as:
0 1 MD(16 bytes) 0 PAD(n bytes) 1
The MD is always 16 bytes here because it's always MD5. GnuPG
does not not support pre-v2.3 signatures, but I'm including this
comment so the information is easily found if needed.)
*/
static gcry_err_code_t
pkcs1_encode_for_signature (gcry_mpi_t *r_result, unsigned int nbits,
const unsigned char *value, size_t valuelen,
int algo)
{
gcry_err_code_t rc = 0;
gcry_error_t err;
byte asn[100];
byte *frame = NULL;
size_t nframe = (nbits+7) / 8;
int i;
size_t n;
size_t asnlen, dlen;
asnlen = DIM(asn);
dlen = gcry_md_get_algo_dlen (algo);
if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
{
/* We don't have yet all of the above algorithms. */
return GPG_ERR_NOT_IMPLEMENTED;
}
if ( valuelen != dlen )
{
/* Hash value does not match the length of digest for
the given algorithm. */
return GPG_ERR_CONFLICT;
}
if ( !dlen || dlen + asnlen + 4 > nframe)
{
/* Can't encode an DLEN byte digest MD into an NFRAME byte
frame. */
return GPG_ERR_TOO_SHORT;
}
if ( !(frame = gcry_malloc (nframe)) )
return gpg_err_code_from_syserror ();
/* Assemble the pkcs#1 block type 1. */
n = 0;
frame[n++] = 0;
frame[n++] = 1; /* block type */
i = nframe - valuelen - asnlen - 3 ;
gcry_assert (i > 1);
memset (frame+n, 0xff, i );
n += i;
frame[n++] = 0;
memcpy (frame+n, asn, asnlen);
n += asnlen;
memcpy (frame+n, value, valuelen );
n += valuelen;
gcry_assert (n == nframe);
/* Convert it into an MPI. */
err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, n, &nframe);
if (err)
rc = gcry_err_code (err);
else if (DBG_CIPHER)
log_mpidump ("PKCS#1 block type 1 encoded data", *r_result);
gcry_free (frame);
return rc;
}
/* Mask generation function for OAEP. See RFC-3447 B.2.1. */
static gcry_err_code_t
mgf1 (unsigned char *output, size_t outlen, unsigned char *seed, size_t seedlen,
int algo)
{
size_t dlen, nbytes, n;
int idx;
gcry_md_hd_t hd;
gcry_error_t err;
err = gcry_md_open (&hd, algo, 0);
if (err)
return gpg_err_code (err);
dlen = gcry_md_get_algo_dlen (algo);
/* We skip step 1 which would be assert(OUTLEN <= 2^32). The loop
in step 3 is merged with step 4 by concatenating no more octets
than what would fit into OUTPUT. The ceiling for the counter IDX
is implemented indirectly. */
nbytes = 0; /* Step 2. */
idx = 0;
while ( nbytes < outlen )
{
unsigned char c[4], *digest;
if (idx)
gcry_md_reset (hd);
c[0] = (idx >> 24) & 0xFF;
c[1] = (idx >> 16) & 0xFF;
c[2] = (idx >> 8) & 0xFF;
c[3] = idx & 0xFF;
idx++;
gcry_md_write (hd, seed, seedlen);
gcry_md_write (hd, c, 4);
digest = gcry_md_read (hd, 0);
n = (outlen - nbytes < dlen)? (outlen - nbytes) : dlen;
memcpy (output+nbytes, digest, n);
nbytes += n;
}
gcry_md_close (hd);
return GPG_ERR_NO_ERROR;
}
/* RFC-3447 (pkcs#1 v2.1) OAEP encoding. NBITS is the length of the
key measured in bits. ALGO is the hash function; it must be a
valid and usable algorithm. {VALUE,VALUELEN} is the message to
encrypt. {LABEL,LABELLEN} is the optional label to be associated
with the message, if LABEL is NULL the default is to use the empty
string as label. On success the encoded ciphertext is returned at
R_RESULT.
If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
the seed instead of using a random string for it. This feature is
only useful for regression tests.
Here is figure 1 from the RFC depicting the process:
+----------+---------+-------+
DB = | lHash | PS | M |
+----------+---------+-------+
|
+----------+ V
| seed |--> MGF ---> xor
+----------+ |
| |
+--+ V |
|00| xor <----- MGF <-----|
+--+ | |
| | |
V V V
+--+----------+----------------------------+
EM = |00|maskedSeed| maskedDB |
+--+----------+----------------------------+
*/
static gcry_err_code_t
oaep_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
const unsigned char *value, size_t valuelen,
const unsigned char *label, size_t labellen,
const void *random_override, size_t random_override_len)
{
gcry_err_code_t rc = 0;
gcry_error_t err;
unsigned char *frame = NULL;
size_t nframe = (nbits+7) / 8;
unsigned char *p;
size_t hlen;
size_t n;
*r_result = NULL;
/* Set defaults for LABEL. */
if (!label || !labellen)
{
label = (const unsigned char*)"";
labellen = 0;
}
hlen = gcry_md_get_algo_dlen (algo);
/* We skip step 1a which would be to check that LABELLEN is not
greater than 2^61-1. See rfc-3447 7.1.1. */
/* Step 1b. Note that the obsolete rfc-2437 uses the check:
valuelen > nframe - 2 * hlen - 1 . */
if (valuelen > nframe - 2 * hlen - 2 || !nframe)
{
/* Can't encode a VALUELEN value in a NFRAME bytes frame. */
return GPG_ERR_TOO_SHORT; /* The key is too short. */
}
/* Allocate the frame. */
frame = gcry_calloc_secure (1, nframe);
if (!frame)
return gpg_err_code_from_syserror ();
/* Step 2a: Compute the hash of the label. We store it in the frame
where later the maskedDB will commence. */
gcry_md_hash_buffer (algo, frame + 1 + hlen, label, labellen);
/* Step 2b: Set octet string to zero. */
/* This has already been done while allocating FRAME. */
/* Step 2c: Create DB by concatenating lHash, PS, 0x01 and M. */
n = nframe - valuelen - 1;
frame[n] = 0x01;
memcpy (frame + n + 1, value, valuelen);
/* Step 3d: Generate seed. We store it where the maskedSeed will go
later. */
if (random_override)
{
if (random_override_len != hlen)
{
gcry_free (frame);
return GPG_ERR_INV_ARG;
}
memcpy (frame + 1, random_override, hlen);
}
else
gcry_randomize (frame + 1, hlen, GCRY_STRONG_RANDOM);
/* Step 2e and 2f: Create maskedDB. */
{
unsigned char *dmask;
dmask = gcry_malloc_secure (nframe - hlen - 1);
if (!dmask)
{
rc = gpg_err_code_from_syserror ();
gcry_free (frame);
return rc;
}
rc = mgf1 (dmask, nframe - hlen - 1, frame+1, hlen, algo);
if (rc)
{
gcry_free (dmask);
gcry_free (frame);
return rc;
}
for (n = 1 + hlen, p = dmask; n < nframe; n++)
frame[n] ^= *p++;
gcry_free (dmask);
}
/* Step 2g and 2h: Create maskedSeed. */
{
unsigned char *smask;
smask = gcry_malloc_secure (hlen);
if (!smask)
{
rc = gpg_err_code_from_syserror ();
gcry_free (frame);
return rc;
}
rc = mgf1 (smask, hlen, frame + 1 + hlen, nframe - hlen - 1, algo);
if (rc)
{
gcry_free (smask);
gcry_free (frame);
return rc;
}
for (n = 1, p = smask; n < 1 + hlen; n++)
frame[n] ^= *p++;
gcry_free (smask);
}
/* Step 2i: Concatenate 0x00, maskedSeed and maskedDB. */
/* This has already been done by using in-place operations. */
/* Convert the stuff into an MPI as expected by the caller. */
err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, nframe, NULL);
if (err)
rc = gcry_err_code (err);
else if (DBG_CIPHER)
log_mpidump ("OAEP encoded data", *r_result);
gcry_free (frame);
return rc;
}
/* RFC-3447 (pkcs#1 v2.1) OAEP decoding. NBITS is the length of the
key measured in bits. ALGO is the hash function; it must be a
valid and usable algorithm. VALUE is the raw decrypted message
{LABEL,LABELLEN} is the optional label to be associated with the
message, if LABEL is NULL the default is to use the empty string as
label. On success the plaintext is returned as a newly allocated
buffer at R_RESULT; its valid length is stored at R_RESULTLEN. On
error NULL is stored at R_RESULT. */
static gcry_err_code_t
oaep_decode (unsigned char **r_result, size_t *r_resultlen,
unsigned int nbits, int algo,
gcry_mpi_t value, const unsigned char *label, size_t labellen)
{
gcry_err_code_t rc;
unsigned char *frame = NULL; /* Encoded messages (EM). */
unsigned char *masked_seed; /* Points into FRAME. */
unsigned char *masked_db; /* Points into FRAME. */
unsigned char *seed = NULL; /* Allocated space for the seed and DB. */
unsigned char *db; /* Points into SEED. */
unsigned char *lhash = NULL; /* Hash of the label. */
size_t nframe; /* Length of the ciphertext (EM). */
size_t hlen; /* Length of the hash digest. */
size_t db_len; /* Length of DB and masked_db. */
size_t nkey = (nbits+7)/8; /* Length of the key in bytes. */
int failed = 0; /* Error indicator. */
size_t n;
*r_result = NULL;
/* This code is implemented as described by rfc-3447 7.1.2. */
/* Set defaults for LABEL. */
if (!label || !labellen)
{
label = (const unsigned char*)"";
labellen = 0;
}
/* Get the length of the digest. */
hlen = gcry_md_get_algo_dlen (algo);
/* Hash the label right away. */
lhash = gcry_malloc (hlen);
if (!lhash)
return gpg_err_code_from_syserror ();
gcry_md_hash_buffer (algo, lhash, label, labellen);
/* Turn the MPI into an octet string. If the octet string is
shorter than the key we pad it to the left with zeroes. This may
happen due to the leading zero in OAEP frames and due to the
following random octets (seed^mask) which may have leading zero
bytes. This all is needed to cope with our leading zeroes
suppressing MPI implementation. The code implictly implements
Step 1b (bail out if NFRAME != N). */
rc = octet_string_from_mpi (&frame, NULL, value, nkey);
if (rc)
{
gcry_free (lhash);
return GPG_ERR_ENCODING_PROBLEM;
}
nframe = nkey;
/* Step 1c: Check that the key is long enough. */
if ( nframe < 2 * hlen + 2 )
{
gcry_free (frame);
gcry_free (lhash);
return GPG_ERR_ENCODING_PROBLEM;
}
/* Step 2 has already been done by the caller and the
gcry_mpi_aprint above. */
/* Allocate space for SEED and DB. */
seed = gcry_malloc_secure (nframe - 1);
if (!seed)
{
rc = gpg_err_code_from_syserror ();
gcry_free (frame);
gcry_free (lhash);
return rc;
}
db = seed + hlen;
/* To avoid choosen ciphertext attacks from now on we make sure to
run all code even in the error case; this avoids possible timing
attacks as described by Manger. */
/* Step 3a: Hash the label. */
/* This has already been done. */
/* Step 3b: Separate the encoded message. */
masked_seed = frame + 1;
masked_db = frame + 1 + hlen;
db_len = nframe - 1 - hlen;
/* Step 3c and 3d: seed = maskedSeed ^ mgf(maskedDB, hlen). */
if (mgf1 (seed, hlen, masked_db, db_len, algo))
failed = 1;
for (n = 0; n < hlen; n++)
seed[n] ^= masked_seed[n];
/* Step 3e and 3f: db = maskedDB ^ mgf(seed, db_len). */
if (mgf1 (db, db_len, seed, hlen, algo))
failed = 1;
for (n = 0; n < db_len; n++)
db[n] ^= masked_db[n];
/* Step 3g: Check lhash, an possible empty padding string terminated
by 0x01 and the first byte of EM being 0. */
if (memcmp (lhash, db, hlen))
failed = 1;
for (n = hlen; n < db_len; n++)
if (db[n] == 0x01)
break;
if (n == db_len)
failed = 1;
if (frame[0])
failed = 1;
gcry_free (lhash);
gcry_free (frame);
if (failed)
{
gcry_free (seed);
return GPG_ERR_ENCODING_PROBLEM;
}
/* Step 4: Output M. */
/* To avoid an extra allocation we reuse the seed buffer. The only
caller of this function will anyway free the result soon. */
n++;
memmove (seed, db + n, db_len - n);
*r_result = seed;
*r_resultlen = db_len - n;
seed = NULL;
if (DBG_CIPHER)
log_printhex ("value extracted from OAEP encoded data:",
*r_result, *r_resultlen);
return 0;
}
/* RFC-3447 (pkcs#1 v2.1) PSS encoding. Encode {VALUE,VALUELEN} for
an NBITS key. Note that VALUE is already the mHash from the
picture below. ALGO is a valid hash algorithm and SALTLEN is the
length of salt to be used. On success the result is stored as a
new MPI at R_RESULT. On error the value at R_RESULT is undefined.
If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
the salt instead of using a random string for the salt. This
feature is only useful for regression tests.
Here is figure 2 from the RFC (errata 595 applied) depicting the
process:
+-----------+
| M |
+-----------+
|
V
Hash
|
V
+--------+----------+----------+
M' = |Padding1| mHash | salt |
+--------+----------+----------+
|
+--------+----------+ V
DB = |Padding2| salt | Hash
+--------+----------+ |
| |
V | +----+
xor <--- MGF <---| |0xbc|
| | +----+
| | |
V V V
+-------------------+----------+----+
EM = | maskedDB | H |0xbc|
+-------------------+----------+----+
*/
static gcry_err_code_t
pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
const unsigned char *value, size_t valuelen, int saltlen,
const void *random_override, size_t random_override_len)
{
gcry_err_code_t rc = 0;
gcry_error_t err;
size_t hlen; /* Length of the hash digest. */
unsigned char *em = NULL; /* Encoded message. */
size_t emlen = (nbits+7)/8; /* Length in bytes of EM. */
unsigned char *h; /* Points into EM. */
unsigned char *buf = NULL; /* Help buffer. */
size_t buflen; /* Length of BUF. */
unsigned char *mhash; /* Points into BUF. */
unsigned char *salt; /* Points into BUF. */
unsigned char *dbmask; /* Points into BUF. */
unsigned char *p;
size_t n;
/* This code is implemented as described by rfc-3447 9.1.1. */
/* Get the length of the digest. */
hlen = gcry_md_get_algo_dlen (algo);
gcry_assert (hlen); /* We expect a valid ALGO here. */
/* Allocate a help buffer and setup some pointers. */
buflen = 8 + hlen + saltlen + (emlen - hlen - 1);
buf = gcry_malloc (buflen);
if (!buf)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
mhash = buf + 8;
salt = mhash + hlen;
dbmask= salt + saltlen;
/* Step 2: That would be: mHash = Hash(M) but our input is already
mHash thus we do only a consistency check and copy to MHASH. */
if (valuelen != hlen)
{
rc = GPG_ERR_INV_LENGTH;
goto leave;
}
memcpy (mhash, value, hlen);
/* Step 3: Check length constraints. */
if (emlen < hlen + saltlen + 2)
{
rc = GPG_ERR_TOO_SHORT;
goto leave;
}
/* Allocate space for EM. */
em = gcry_malloc (emlen);
if (!em)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
h = em + emlen - 1 - hlen;
/* Step 4: Create a salt. */
if (saltlen)
{
if (random_override)
{
if (random_override_len != saltlen)
{
rc = GPG_ERR_INV_ARG;
goto leave;
}
memcpy (salt, random_override, saltlen);
}
else
gcry_randomize (salt, saltlen, GCRY_STRONG_RANDOM);
}
/* Step 5 and 6: M' = Hash(Padding1 || mHash || salt). */
memset (buf, 0, 8); /* Padding. */
gcry_md_hash_buffer (algo, h, buf, 8 + hlen + saltlen);
/* Step 7 and 8: DB = PS || 0x01 || salt. */
/* Note that we use EM to store DB and later Xor in-place. */
p = em + emlen - 1 - hlen - saltlen - 1;
memset (em, 0, p - em);
*p++ = 0x01;
memcpy (p, salt, saltlen);
/* Step 9: dbmask = MGF(H, emlen - hlen - 1). */
mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo);
/* Step 10: maskedDB = DB ^ dbMask */
for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++)
em[n] ^= *p;
/* Step 11: Set the leftmost bits to zero. */
em[0] &= 0xFF >> (8 * emlen - nbits);
/* Step 12: EM = maskedDB || H || 0xbc. */
em[emlen-1] = 0xbc;
/* Convert EM into an MPI. */
err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, em, emlen, NULL);
if (err)
rc = gcry_err_code (err);
else if (DBG_CIPHER)
log_mpidump ("PSS encoded data", *r_result);
leave:
if (em)
{
wipememory (em, emlen);
gcry_free (em);
}
if (buf)
{
wipememory (buf, buflen);
gcry_free (buf);
}
return rc;
}
/* Verify a signature assuming PSS padding. VALUE is the hash of the
message (mHash) encoded as an MPI; its length must match the digest
length of ALGO. ENCODED is the output of the RSA public key
function (EM). NBITS is the size of the public key. ALGO is the
hash algorithm and SALTLEN is the length of the used salt. The
function returns 0 on success or on error code. */
static gcry_err_code_t
pss_verify (gcry_mpi_t value, gcry_mpi_t encoded, unsigned int nbits, int algo,
size_t saltlen)
{
gcry_err_code_t rc = 0;
size_t hlen; /* Length of the hash digest. */
unsigned char *em = NULL; /* Encoded message. */
size_t emlen = (nbits+7)/8; /* Length in bytes of EM. */
unsigned char *salt; /* Points into EM. */
unsigned char *h; /* Points into EM. */
unsigned char *buf = NULL; /* Help buffer. */
size_t buflen; /* Length of BUF. */
unsigned char *dbmask; /* Points into BUF. */
unsigned char *mhash; /* Points into BUF. */
unsigned char *p;
size_t n;
/* This code is implemented as described by rfc-3447 9.1.2. */
/* Get the length of the digest. */
hlen = gcry_md_get_algo_dlen (algo);
gcry_assert (hlen); /* We expect a valid ALGO here. */
/* Allocate a help buffer and setup some pointers.
This buffer is used for two purposes:
+------------------------------+-------+
1. | dbmask | mHash |
+------------------------------+-------+
emlen - hlen - 1 hlen
+----------+-------+---------+-+-------+
2. | padding1 | mHash | salt | | mHash |
+----------+-------+---------+-+-------+
8 hlen saltlen hlen
*/
buflen = 8 + hlen + saltlen;
if (buflen < emlen - hlen - 1)
buflen = emlen - hlen - 1;
buflen += hlen;
buf = gcry_malloc (buflen);
if (!buf)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
dbmask = buf;
mhash = buf + buflen - hlen;
/* Step 2: That would be: mHash = Hash(M) but our input is already
mHash thus we only need to convert VALUE into MHASH. */
rc = octet_string_from_mpi (NULL, mhash, value, hlen);
if (rc)
goto leave;
/* Convert the signature into an octet string. */
rc = octet_string_from_mpi (&em, NULL, encoded, emlen);
if (rc)
goto leave;
/* Step 3: Check length of EM. Because we internally use MPI
functions we can't do this properly; EMLEN is always the length
of the key because octet_string_from_mpi needs to left pad the
result with zero to cope with the fact that our MPIs suppress all
leading zeroes. Thus what we test here are merely the digest and
salt lengths to the key. */
if (emlen < hlen + saltlen + 2)
{
rc = GPG_ERR_TOO_SHORT; /* For the hash and saltlen. */
goto leave;
}
/* Step 4: Check last octet. */
if (em[emlen - 1] != 0xbc)
{
rc = GPG_ERR_BAD_SIGNATURE;
goto leave;
}
/* Step 5: Split EM. */
h = em + emlen - 1 - hlen;
/* Step 6: Check the leftmost bits. */
if ((em[0] & ~(0xFF >> (8 * emlen - nbits))))
{
rc = GPG_ERR_BAD_SIGNATURE;
goto leave;
}
/* Step 7: dbmask = MGF(H, emlen - hlen - 1). */
mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo);
/* Step 8: maskedDB = DB ^ dbMask. */
for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++)
em[n] ^= *p;
/* Step 9: Set leftmost bits in DB to zero. */
em[0] &= 0xFF >> (8 * emlen - nbits);
/* Step 10: Check the padding of DB. */
for (n = 0; n < emlen - hlen - saltlen - 2 && !em[n]; n++)
;
if (n != emlen - hlen - saltlen - 2 || em[n++] != 1)
{
rc = GPG_ERR_BAD_SIGNATURE;
goto leave;
}
/* Step 11: Extract salt from DB. */
salt = em + n;
/* Step 12: M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */
memset (buf, 0, 8);
memcpy (buf+8, mhash, hlen);
memcpy (buf+8+hlen, salt, saltlen);
/* Step 13: H' = Hash(M'). */
gcry_md_hash_buffer (algo, buf, buf, 8 + hlen + saltlen);
/* Step 14: Check H == H'. */
rc = memcmp (h, buf, hlen) ? GPG_ERR_BAD_SIGNATURE : GPG_ERR_NO_ERROR;
leave:
if (em)
{
wipememory (em, emlen);
gcry_free (em);
}
if (buf)
{
wipememory (buf, buflen);
gcry_free (buf);
}
return rc;
}
/* Callback for the pubkey algorithm code to verify PSS signatures.
OPAQUE is the data provided by the actual caller. The meaning of
TMP depends on the actual algorithm (but there is only RSA); now
for RSA it is the output of running the public key function on the
input. */
static int
pss_verify_cmp (void *opaque, gcry_mpi_t tmp)
{
struct pk_encoding_ctx *ctx = opaque;
gcry_mpi_t hash = ctx->verify_arg;
return pss_verify (hash, tmp, ctx->nbits - 1, ctx->hash_algo, ctx->saltlen);
}
/* Internal function. */
static gcry_err_code_t
sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names,
gcry_mpi_t *elements, const char *algo_name)
{
gcry_err_code_t err = 0;
int i, idx;
const char *name;
gcry_sexp_t list;
for (name = element_names, idx = 0; *name && !err; name++, idx++)
{
list = gcry_sexp_find_token (key_sexp, name, 1);
if (!list)
elements[idx] = NULL;
else
{
elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (list);
if (!elements[idx])
err = GPG_ERR_INV_OBJ;
}
}
if (!err)
{
/* Check that all elements are available. */
for (name = element_names, idx = 0; *name; name++, idx++)
if (!elements[idx])
break;
if (*name)
{
err = GPG_ERR_NO_OBJ;
/* Some are missing. Before bailing out we test for
optional parameters. */
if (algo_name && !strcmp (algo_name, "RSA")
&& !strcmp (element_names, "nedpqu") )
{
/* This is RSA. Test whether we got N, E and D and that
the optional P, Q and U are all missing. */
if (elements[0] && elements[1] && elements[2]
&& !elements[3] && !elements[4] && !elements[5])
err = 0;
}
}
}
if (err)
{
for (i = 0; i < idx; i++)
if (elements[i])
gcry_free (elements[i]);
}
return err;
}
/* Internal function used for ecc. Note, that this function makes use
of its intimate knowledge about the ECC parameters from ecc.c. */
static gcry_err_code_t
sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names,
gcry_mpi_t *elements, pk_extra_spec_t *extraspec,
int want_private)
{
gcry_err_code_t err = 0;
int idx;
const char *name;
gcry_sexp_t list;
/* Clear the array for easier error cleanup. */
for (name = element_names, idx = 0; *name; name++, idx++)
elements[idx] = NULL;
gcry_assert (idx >= 5); /* We know that ECC has at least 5 elements
(params only) or 6 (full public key). */
if (idx == 5)
elements[5] = NULL; /* Extra clear for the params only case. */
/* Init the array with the available curve parameters. */
for (name = element_names, idx = 0; *name && !err; name++, idx++)
{
list = gcry_sexp_find_token (key_sexp, name, 1);
if (!list)
elements[idx] = NULL;
else
{
elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (list);
if (!elements[idx])
{
err = GPG_ERR_INV_OBJ;
goto leave;
}
}
}
/* Check whether a curve parameter has been given and then fill any
missing elements. */
list = gcry_sexp_find_token (key_sexp, "curve", 5);
if (list)
{
if (extraspec->get_param)
{
char *curve;
gcry_mpi_t params[6];
for (idx = 0; idx < DIM(params); idx++)
params[idx] = NULL;
curve = _gcry_sexp_nth_string (list, 1);
gcry_sexp_release (list);
if (!curve)
{
/* No curve name given (or out of core). */
err = GPG_ERR_INV_OBJ;
goto leave;
}
err = extraspec->get_param (curve, params);
gcry_free (curve);
if (err)
goto leave;
for (idx = 0; idx < DIM(params); idx++)
{
if (!elements[idx])
elements[idx] = params[idx];
else
mpi_free (params[idx]);
}
}
else
{
gcry_sexp_release (list);
err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */
goto leave;
}
}
/* Check that all parameters are known. */
for (name = element_names, idx = 0; *name; name++, idx++)
if (!elements[idx])
{
if (want_private && *name == 'q')
; /* Q is optional. */
else
{
err = GPG_ERR_NO_OBJ;
goto leave;
}
}
leave:
if (err)
{
for (name = element_names, idx = 0; *name; name++, idx++)
if (elements[idx])
gcry_free (elements[idx]);
}
return err;
}
/****************
* Convert a S-Exp with either a private or a public key to our
* internal format. Currently we do only support the following
* algorithms:
* dsa
* rsa
* openpgp-dsa
* openpgp-rsa
* openpgp-elg
* openpgp-elg-sig
* ecdsa
* ecdh
* Provide a SE with the first element be either "private-key" or
* or "public-key". It is followed by a list with its first element
* be one of the above algorithm identifiers and the remaning
* elements are pairs with parameter-id and value.
* NOTE: we look through the list to find a list beginning with
* "private-key" or "public-key" - the first one found is used.
*
* If OVERRIDE_ELEMS is not NULL those elems override the parameter
* specification taken from the module. This ise used by
* gcry_pk_get_curve.
*
* Returns: A pointer to an allocated array of MPIs if the return value is
* zero; the caller has to release this array.
*
* Example of a DSA public key:
* (private-key
* (dsa
* (p <mpi>)
* (g <mpi>)
* (y <mpi>)
* (x <mpi>)
* )
* )
* The <mpi> are expected to be in GCRYMPI_FMT_USG
*/
static gcry_err_code_t
sexp_to_key (gcry_sexp_t sexp, int want_private, int use,
const char *override_elems,
gcry_mpi_t **retarray, gcry_module_t *retalgo, int *r_is_ecc)
{
gcry_err_code_t err = 0;
gcry_sexp_t list, l2;
char *name;
const char *elems;
gcry_mpi_t *array;
gcry_module_t module;
gcry_pk_spec_t *pubkey;
pk_extra_spec_t *extraspec;
int is_ecc;
/* Check that the first element is valid. */
list = gcry_sexp_find_token (sexp,
want_private? "private-key":"public-key", 0);
if (!list)
return GPG_ERR_INV_OBJ; /* Does not contain a key object. */
l2 = gcry_sexp_cadr( list );
gcry_sexp_release ( list );
list = l2;
name = _gcry_sexp_nth_string (list, 0);
if (!name)
{
gcry_sexp_release ( list );
return GPG_ERR_INV_OBJ; /* Invalid structure of object. */
}
/* Fixme: We should make sure that an ECC key is always named "ecc"
and not "ecdsa". "ecdsa" should be used for the signature
itself. We need a function to test whether an algorithm given
with a key is compatible with an application of the key (signing,
encryption). For RSA this is easy, but ECC is the first
algorithm which has many flavours.
We use an ugly hack here to decide whether to use ecdsa or ecdh.
*/
if (!strcmp (name, "ecc"))
is_ecc = 2;
else if (!strcmp (name, "ecdsa") || !strcmp (name, "ecdh"))
is_ecc = 1;
else
is_ecc = 0;
ath_mutex_lock (&pubkeys_registered_lock);
if (is_ecc == 2 && (use & GCRY_PK_USAGE_SIGN))
module = gcry_pk_lookup_name ("ecdsa");
else if (is_ecc == 2 && (use & GCRY_PK_USAGE_ENCR))
module = gcry_pk_lookup_name ("ecdh");
else
module = gcry_pk_lookup_name (name);
ath_mutex_unlock (&pubkeys_registered_lock);
gcry_free (name);
if (!module)
{
gcry_sexp_release (list);
return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
}
else
{
pubkey = (gcry_pk_spec_t *) module->spec;
extraspec = module->extraspec;
}
if (override_elems)
elems = override_elems;
else if (want_private)
elems = pubkey->elements_skey;
else
elems = pubkey->elements_pkey;
array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
if (!array)
err = gpg_err_code_from_syserror ();
if (!err)
{
if (is_ecc)
err = sexp_elements_extract_ecc (list, elems, array, extraspec,
want_private);
else
err = sexp_elements_extract (list, elems, array, pubkey->name);
}
gcry_sexp_release (list);
if (err)
{
gcry_free (array);
ath_mutex_lock (&pubkeys_registered_lock);
_gcry_module_release (module);
ath_mutex_unlock (&pubkeys_registered_lock);
}
else
{
*retarray = array;
*retalgo = module;
if (r_is_ecc)
*r_is_ecc = is_ecc;
}
return err;
}
static gcry_err_code_t
sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray,
gcry_module_t *retalgo)
{
gcry_err_code_t err = 0;
gcry_sexp_t list, l2;
char *name;
const char *elems;
gcry_mpi_t *array;
gcry_module_t module;
gcry_pk_spec_t *pubkey;
/* Check that the first element is valid. */
list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
if (!list)
return GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */
l2 = gcry_sexp_nth (list, 1);
if (!l2)
{
gcry_sexp_release (list);
return GPG_ERR_NO_OBJ; /* No cadr for the sig object. */
}
name = _gcry_sexp_nth_string (l2, 0);
if (!name)
{
gcry_sexp_release (list);
gcry_sexp_release (l2);
return GPG_ERR_INV_OBJ; /* Invalid structure of object. */
}
else if (!strcmp (name, "flags"))
{
/* Skip flags, since they are not used but here just for the
sake of consistent S-expressions. */
gcry_free (name);
gcry_sexp_release (l2);
l2 = gcry_sexp_nth (list, 2);
if (!l2)
{
gcry_sexp_release (list);
return GPG_ERR_INV_OBJ;
}
name = _gcry_sexp_nth_string (l2, 0);
}
ath_mutex_lock (&pubkeys_registered_lock);
module = gcry_pk_lookup_name (name);
ath_mutex_unlock (&pubkeys_registered_lock);
gcry_free (name);
name = NULL;
if (!module)
{
gcry_sexp_release (l2);
gcry_sexp_release (list);
return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
}
else
pubkey = (gcry_pk_spec_t *) module->spec;
elems = pubkey->elements_sig;
array = gcry_calloc (strlen (elems) + 1 , sizeof *array );
if (!array)
err = gpg_err_code_from_syserror ();
if (!err)
err = sexp_elements_extract (list, elems, array, NULL);
gcry_sexp_release (l2);
gcry_sexp_release (list);
if (err)
{
ath_mutex_lock (&pubkeys_registered_lock);
_gcry_module_release (module);
ath_mutex_unlock (&pubkeys_registered_lock);
gcry_free (array);
}
else
{
*retarray = array;
*retalgo = module;
}
return err;
}
static inline int
get_hash_algo (const char *s, size_t n)
{
static const struct { const char *name; int algo; } hashnames[] = {
{ "sha1", GCRY_MD_SHA1 },
{ "md5", GCRY_MD_MD5 },
{ "sha256", GCRY_MD_SHA256 },
{ "ripemd160", GCRY_MD_RMD160 },
{ "rmd160", GCRY_MD_RMD160 },
{ "sha384", GCRY_MD_SHA384 },
{ "sha512", GCRY_MD_SHA512 },
{ "sha224", GCRY_MD_SHA224 },
{ "md2", GCRY_MD_MD2 },
{ "md4", GCRY_MD_MD4 },
{ "tiger", GCRY_MD_TIGER },
{ "haval", GCRY_MD_HAVAL },
{ NULL, 0 }
};
int algo;
int i;
for (i=0; hashnames[i].name; i++)
{
if ( strlen (hashnames[i].name) == n
&& !memcmp (hashnames[i].name, s, n))
break;
}
if (hashnames[i].name)
algo = hashnames[i].algo;
else
{
/* In case of not listed or dynamically allocated hash
algorithm we fall back to this somewhat slower
method. Further, it also allows to use OIDs as
algorithm names. */
char *tmpname;
tmpname = gcry_malloc (n+1);
if (!tmpname)
algo = 0; /* Out of core - silently give up. */
else
{
memcpy (tmpname, s, n);
tmpname[n] = 0;
algo = gcry_md_map_name (tmpname);
gcry_free (tmpname);
}
}
return algo;
}
/****************
* Take sexp and return an array of MPI as used for our internal decrypt
* function.
* s_data = (enc-val
* [(flags [raw, pkcs1, oaep, no-blinding])]
* [(hash-algo <algo>)]
* [(label <label>)]
* (<algo>
* (<param_name1> <mpi>)
* ...
* (<param_namen> <mpi>)
* ))
* HASH-ALGO and LABEL are specific to OAEP.
* RET_MODERN is set to true when at least an empty flags list has been found.
* CTX is used to return encoding information; it may be NULL in which
* case raw encoding is used.
*/
static gcry_err_code_t
sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
int *ret_modern, int *flags, struct pk_encoding_ctx *ctx)
{
gcry_err_code_t err = 0;
gcry_sexp_t list = NULL, l2 = NULL;
gcry_pk_spec_t *pubkey = NULL;
gcry_module_t module = NULL;
char *name = NULL;
size_t n;
int parsed_flags = 0;
const char *elems;
gcry_mpi_t *array = NULL;
*ret_modern = 0;
/* Check that the first element is valid. */
list = gcry_sexp_find_token (sexp, "enc-val" , 0);
if (!list)
{
err = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */
goto leave;
}
l2 = gcry_sexp_nth (list, 1);
if (!l2)
{
err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */
goto leave;
}
/* Extract identifier of sublist. */
name = _gcry_sexp_nth_string (l2, 0);
if (!name)
{
err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
goto leave;
}
if (!strcmp (name, "flags"))
{
/* There is a flags element - process it. */
const char *s;
int i;
*ret_modern = 1;
for (i = gcry_sexp_length (l2) - 1; i > 0; i--)
{
s = gcry_sexp_nth_data (l2, i, &n);
if (! s)
; /* Not a data element - ignore. */
else if (n == 3 && !memcmp (s, "raw", 3)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
ctx->encoding = PUBKEY_ENC_RAW;
else if (n == 5 && !memcmp (s, "pkcs1", 5)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
ctx->encoding = PUBKEY_ENC_PKCS1;
else if (n == 4 && !memcmp (s, "oaep", 4)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
ctx->encoding = PUBKEY_ENC_OAEP;
else if (n == 3 && !memcmp (s, "pss", 3)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
{
err = GPG_ERR_CONFLICT;
goto leave;
}
else if (n == 11 && ! memcmp (s, "no-blinding", 11))
parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
else
{
err = GPG_ERR_INV_FLAG;
goto leave;
}
}
gcry_sexp_release (l2);
/* Get the OAEP parameters HASH-ALGO and LABEL, if any. */
if (ctx->encoding == PUBKEY_ENC_OAEP)
{
/* Get HASH-ALGO. */
l2 = gcry_sexp_find_token (list, "hash-algo", 0);
if (l2)
{
s = gcry_sexp_nth_data (l2, 1, &n);
if (!s)
err = GPG_ERR_NO_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
err = GPG_ERR_DIGEST_ALGO;
}
gcry_sexp_release (l2);
if (err)
goto leave;
}
/* Get LABEL. */
l2 = gcry_sexp_find_token (list, "label", 0);
if (l2)
{
s = gcry_sexp_nth_data (l2, 1, &n);
if (!s)
err = GPG_ERR_NO_OBJ;
else if (n > 0)
{
ctx->label = gcry_malloc (n);
if (!ctx->label)
err = gpg_err_code_from_syserror ();
else
{
memcpy (ctx->label, s, n);
ctx->labellen = n;
}
}
gcry_sexp_release (l2);
if (err)
goto leave;
}
}
/* Get the next which has the actual data - skip HASH-ALGO and LABEL. */
for (i = 2; (l2 = gcry_sexp_nth (list, i)) != NULL; i++)
{
s = gcry_sexp_nth_data (l2, 0, &n);
if (!(n == 9 && !memcmp (s, "hash-algo", 9))
&& !(n == 5 && !memcmp (s, "label", 5))
&& !(n == 15 && !memcmp (s, "random-override", 15)))
break;
gcry_sexp_release (l2);
}
if (!l2)
{
err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */
goto leave;
}
/* Extract sublist identifier. */
gcry_free (name);
name = _gcry_sexp_nth_string (l2, 0);
if (!name)
{
err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
goto leave;
}
gcry_sexp_release (list);
list = l2;
l2 = NULL;
}
ath_mutex_lock (&pubkeys_registered_lock);
module = gcry_pk_lookup_name (name);
ath_mutex_unlock (&pubkeys_registered_lock);
if (!module)
{
err = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
goto leave;
}
pubkey = (gcry_pk_spec_t *) module->spec;
elems = pubkey->elements_enc;
array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
if (!array)
{
err = gpg_err_code_from_syserror ();
goto leave;
}
err = sexp_elements_extract (list, elems, array, NULL);
leave:
gcry_sexp_release (list);
gcry_sexp_release (l2);
gcry_free (name);
if (err)
{
ath_mutex_lock (&pubkeys_registered_lock);
_gcry_module_release (module);
ath_mutex_unlock (&pubkeys_registered_lock);
gcry_free (array);
gcry_free (ctx->label);
ctx->label = NULL;
}
else
{
*retarray = array;
*retalgo = module;
*flags = parsed_flags;
}
return err;
}
/* Take the hash value and convert into an MPI, suitable for
passing to the low level functions. We currently support the
old style way of passing just a MPI and the modern interface which
allows to pass flags so that we can choose between raw and pkcs1
padding - may be more padding options later.
(<mpi>)
or
(data
- [(flags [raw, pkcs1, oaep, pss, no-blinding])]
+ [(flags [raw, direct, pkcs1, oaep, pss, no-blinding, rfc6979])]
[(hash <algo> <value>)]
[(value <text>)]
[(hash-algo <algo>)]
[(label <label>)]
[(salt-length <length>)]
[(random-override <data>)]
)
Either the VALUE or the HASH element must be present for use
with signatures. VALUE is used for encryption.
HASH-ALGO and LABEL are specific to OAEP.
SALT-LENGTH is for PSS.
RANDOM-OVERRIDE is used to replace random nonces for regression
testing. */
static gcry_err_code_t
sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
struct pk_encoding_ctx *ctx)
{
gcry_err_code_t rc = 0;
gcry_sexp_t ldata, lhash, lvalue;
int i;
size_t n;
const char *s;
- int unknown_flag=0;
+ int unknown_flag = 0;
int parsed_flags = 0;
+ int explicit_raw = 0;
*ret_mpi = NULL;
ldata = gcry_sexp_find_token (input, "data", 0);
if (!ldata)
{ /* assume old style */
*ret_mpi = gcry_sexp_nth_mpi (input, 0, 0);
return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ;
}
/* see whether there is a flags object */
{
gcry_sexp_t lflags = gcry_sexp_find_token (ldata, "flags", 0);
if (lflags)
{ /* parse the flags list. */
for (i=gcry_sexp_length (lflags)-1; i > 0; i--)
{
s = gcry_sexp_nth_data (lflags, i, &n);
if (!s)
; /* not a data element*/
+ else if (n == 7 && ! memcmp (s, "rfc6979", 7))
+ parsed_flags |= PUBKEY_FLAG_RFC6979;
else if ( n == 3 && !memcmp (s, "raw", 3)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
- ctx->encoding = PUBKEY_ENC_RAW;
+ {
+ ctx->encoding = PUBKEY_ENC_RAW;
+ explicit_raw = 1;
+ }
else if ( n == 5 && !memcmp (s, "pkcs1", 5)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
ctx->encoding = PUBKEY_ENC_PKCS1;
else if ( n == 4 && !memcmp (s, "oaep", 4)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
ctx->encoding = PUBKEY_ENC_OAEP;
else if ( n == 3 && !memcmp (s, "pss", 3)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
ctx->encoding = PUBKEY_ENC_PSS;
else if (n == 11 && ! memcmp (s, "no-blinding", 11))
parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
else
unknown_flag = 1;
}
gcry_sexp_release (lflags);
}
}
if (ctx->encoding == PUBKEY_ENC_UNKNOWN)
ctx->encoding = PUBKEY_ENC_RAW; /* default to raw */
/* Get HASH or MPI */
lhash = gcry_sexp_find_token (ldata, "hash", 0);
lvalue = lhash? NULL : gcry_sexp_find_token (ldata, "value", 0);
if (!(!lhash ^ !lvalue))
rc = GPG_ERR_INV_OBJ; /* none or both given */
else if (unknown_flag)
rc = GPG_ERR_INV_FLAG;
+ else if (ctx->encoding == PUBKEY_ENC_RAW && lhash
+ && (explicit_raw || (parsed_flags & PUBKEY_FLAG_RFC6979)))
+ {
+ /* Raw encoding along with a hash element. This is commonly
+ used for DSA. For better backward error compatibility we
+ allow this only if either the rfc6979 flag has been given or
+ the raw flags was explicitly given. */
+ if (gcry_sexp_length (lhash) != 3)
+ rc = GPG_ERR_INV_OBJ;
+ else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
+ rc = GPG_ERR_INV_OBJ;
+ else
+ {
+ void *value;
+ size_t valuelen;
+
+ ctx->hash_algo = get_hash_algo (s, n);
+ if (!ctx->hash_algo)
+ rc = GPG_ERR_DIGEST_ALGO;
+ else if (!(value=gcry_sexp_nth_buffer (lhash, 2, &valuelen)))
+ rc = GPG_ERR_INV_OBJ;
+ else if ((valuelen * 8) < valuelen)
+ {
+ gcry_free (value);
+ rc = GPG_ERR_TOO_LARGE;
+ }
+ else
+ *ret_mpi = gcry_mpi_set_opaque (NULL, value, valuelen*8);
+ }
+ }
else if (ctx->encoding == PUBKEY_ENC_RAW && lvalue)
{
+ /* RFC6969 may only be used with the a hash value and not the
+ MPI based value. */
+ if (parsed_flags & PUBKEY_FLAG_RFC6979)
+ {
+ rc = GPG_ERR_CONFLICT;
+ goto leave;
+ }
+
+ /* Get the value */
*ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, GCRYMPI_FMT_USG);
if (!*ret_mpi)
rc = GPG_ERR_INV_OBJ;
}
else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lvalue
&& ctx->op == PUBKEY_OP_ENCRYPT)
{
const void * value;
size_t valuelen;
gcry_sexp_t list;
void *random_override = NULL;
size_t random_override_len = 0;
if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
rc = GPG_ERR_INV_OBJ;
else
{
/* Get optional RANDOM-OVERRIDE. */
list = gcry_sexp_find_token (ldata, "random-override", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
random_override = gcry_malloc (n);
if (!random_override)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (random_override, s, n);
random_override_len = n;
}
}
gcry_sexp_release (list);
if (rc)
goto leave;
}
rc = pkcs1_encode_for_encryption (ret_mpi, ctx->nbits,
value, valuelen,
random_override,
random_override_len);
gcry_free (random_override);
}
}
else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lhash
&& (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
{
if (gcry_sexp_length (lhash) != 3)
rc = GPG_ERR_INV_OBJ;
else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
rc = GPG_ERR_INV_OBJ;
else
{
const void * value;
size_t valuelen;
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
|| !valuelen )
rc = GPG_ERR_INV_OBJ;
else
rc = pkcs1_encode_for_signature (ret_mpi, ctx->nbits,
value, valuelen,
ctx->hash_algo);
}
}
else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue
&& ctx->op == PUBKEY_OP_ENCRYPT)
{
const void * value;
size_t valuelen;
if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
rc = GPG_ERR_INV_OBJ;
else
{
gcry_sexp_t list;
void *random_override = NULL;
size_t random_override_len = 0;
/* Get HASH-ALGO. */
list = gcry_sexp_find_token (ldata, "hash-algo", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
}
gcry_sexp_release (list);
if (rc)
goto leave;
}
/* Get LABEL. */
list = gcry_sexp_find_token (ldata, "label", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
ctx->label = gcry_malloc (n);
if (!ctx->label)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (ctx->label, s, n);
ctx->labellen = n;
}
}
gcry_sexp_release (list);
if (rc)
goto leave;
}
/* Get optional RANDOM-OVERRIDE. */
list = gcry_sexp_find_token (ldata, "random-override", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
random_override = gcry_malloc (n);
if (!random_override)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (random_override, s, n);
random_override_len = n;
}
}
gcry_sexp_release (list);
if (rc)
goto leave;
}
rc = oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo,
value, valuelen,
ctx->label, ctx->labellen,
random_override, random_override_len);
gcry_free (random_override);
}
}
else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
&& ctx->op == PUBKEY_OP_SIGN)
{
if (gcry_sexp_length (lhash) != 3)
rc = GPG_ERR_INV_OBJ;
else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
rc = GPG_ERR_INV_OBJ;
else
{
const void * value;
size_t valuelen;
void *random_override = NULL;
size_t random_override_len = 0;
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
|| !valuelen )
rc = GPG_ERR_INV_OBJ;
else
{
gcry_sexp_t list;
/* Get SALT-LENGTH. */
list = gcry_sexp_find_token (ldata, "salt-length", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
{
rc = GPG_ERR_NO_OBJ;
goto leave;
}
ctx->saltlen = (unsigned int)strtoul (s, NULL, 10);
gcry_sexp_release (list);
}
/* Get optional RANDOM-OVERRIDE. */
list = gcry_sexp_find_token (ldata, "random-override", 0);
if (list)
{
s = gcry_sexp_nth_data (list, 1, &n);
if (!s)
rc = GPG_ERR_NO_OBJ;
else if (n > 0)
{
random_override = gcry_malloc (n);
if (!random_override)
rc = gpg_err_code_from_syserror ();
else
{
memcpy (random_override, s, n);
random_override_len = n;
}
}
gcry_sexp_release (list);
if (rc)
goto leave;
}
/* Encode the data. (NBITS-1 is due to 8.1.1, step 1.) */
rc = pss_encode (ret_mpi, ctx->nbits - 1, ctx->hash_algo,
value, valuelen, ctx->saltlen,
random_override, random_override_len);
gcry_free (random_override);
}
}
}
else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
&& ctx->op == PUBKEY_OP_VERIFY)
{
if (gcry_sexp_length (lhash) != 3)
rc = GPG_ERR_INV_OBJ;
else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
rc = GPG_ERR_INV_OBJ;
else
{
ctx->hash_algo = get_hash_algo (s, n);
if (!ctx->hash_algo)
rc = GPG_ERR_DIGEST_ALGO;
else
{
*ret_mpi = gcry_sexp_nth_mpi (lhash, 2, GCRYMPI_FMT_USG);
if (!*ret_mpi)
rc = GPG_ERR_INV_OBJ;
ctx->verify_cmp = pss_verify_cmp;
ctx->verify_arg = *ret_mpi;
}
}
}
else
rc = GPG_ERR_CONFLICT;
leave:
gcry_sexp_release (ldata);
gcry_sexp_release (lhash);
gcry_sexp_release (lvalue);
if (!rc)
ctx->flags = parsed_flags;
else
{
gcry_free (ctx->label);
ctx->label = NULL;
}
return rc;
}
static void
init_encoding_ctx (struct pk_encoding_ctx *ctx, enum pk_operation op,
unsigned int nbits)
{
ctx->op = op;
ctx->nbits = nbits;
ctx->encoding = PUBKEY_ENC_UNKNOWN;
ctx->flags = 0;
ctx->hash_algo = GCRY_MD_SHA1;
ctx->label = NULL;
ctx->labellen = 0;
ctx->saltlen = 20;
ctx->verify_cmp = NULL;
ctx->verify_arg = NULL;
}
/*
Do a PK encrypt operation
Caller has to provide a public key as the SEXP pkey and data as a
SEXP with just one MPI in it. Alternatively S_DATA might be a
complex S-Expression, similar to the one used for signature
verification. This provides a flag which allows to handle PKCS#1
block type 2 padding. The function returns a sexp which may be
passed to to pk_decrypt.
Returns: 0 or an errorcode.
s_data = See comment for sexp_data_to_mpi
s_pkey = <key-as-defined-in-sexp_to_key>
r_ciph = (enc-val
(<algo>
(<param_name1> <mpi>)
...
(<param_namen> <mpi>)
))
*/
gcry_error_t
gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
{
gcry_mpi_t *pkey = NULL, data = NULL, *ciph = NULL;
const char *algo_name, *algo_elems;
struct pk_encoding_ctx ctx;
gcry_err_code_t rc;
gcry_pk_spec_t *pubkey = NULL;
gcry_module_t module = NULL;
*r_ciph = NULL;
REGISTER_DEFAULT_PUBKEYS;
/* Get the key. */
rc = sexp_to_key (s_pkey, 0, GCRY_PK_USAGE_ENCR, NULL, &pkey, &module, NULL);
if (rc)
goto leave;
gcry_assert (module);
pubkey = (gcry_pk_spec_t *) module->spec;
/* If aliases for the algorithm name exists, take the first one
instead of the regular name to adhere to SPKI conventions. We
assume that the first alias name is the lowercase version of the
regular one. This change is required for compatibility with
1.1.12 generated S-expressions. */
algo_name = pubkey->aliases? *pubkey->aliases : NULL;
if (!algo_name || !*algo_name)
algo_name = pubkey->name;
algo_elems = pubkey->elements_enc;
/* Get the stuff we want to encrypt. */
init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, gcry_pk_get_nbits (s_pkey));
rc = sexp_data_to_mpi (s_data, &data, &ctx);
if (rc)
goto leave;
/* Now we can encrypt DATA to CIPH. */
ciph = gcry_calloc (strlen (algo_elems) + 1, sizeof (*ciph));
if (!ciph)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
rc = pubkey_encrypt (module->mod_id, ciph, data, pkey, ctx.flags);
mpi_free (data);
data = NULL;
if (rc)
goto leave;
/* We did it. Now build the return list */
if (ctx.encoding == PUBKEY_ENC_OAEP
|| ctx.encoding == PUBKEY_ENC_PKCS1)
{
/* We need to make sure to return the correct length to avoid
problems with missing leading zeroes. We know that this
encoding does only make sense with RSA thus we don't need to
build the S-expression on the fly. */
unsigned char *em;
size_t emlen = (ctx.nbits+7)/8;
rc = octet_string_from_mpi (&em, NULL, ciph[0], emlen);
if (rc)
goto leave;
rc = gcry_err_code (gcry_sexp_build (r_ciph, NULL,
"(enc-val(%s(a%b)))",
algo_name, (int)emlen, em));
gcry_free (em);
if (rc)
goto leave;
}
else
{
char *string, *p;
int i;
size_t nelem = strlen (algo_elems);
size_t needed = 19 + strlen (algo_name) + (nelem * 5);
void **arg_list;
/* Build the string. */
string = p = gcry_malloc (needed);
if (!string)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
p = stpcpy ( p, "(enc-val(" );
p = stpcpy ( p, algo_name );
for (i=0; algo_elems[i]; i++ )
{
*p++ = '(';
*p++ = algo_elems[i];
p = stpcpy ( p, "%m)" );
}
strcpy ( p, "))" );
/* And now the ugly part: We don't have a function to pass an
* array to a format string, so we have to do it this way :-(. */
/* FIXME: There is now such a format specifier, so we can
change the code to be more clear. */
arg_list = malloc (nelem * sizeof *arg_list);
if (!arg_list)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
for (i = 0; i < nelem; i++)
arg_list[i] = ciph + i;
rc = gcry_sexp_build_array (r_ciph, NULL, string, arg_list);
free (arg_list);
if (rc)
BUG ();
gcry_free (string);
}
leave:
if (pkey)
{
release_mpi_array (pkey);
gcry_free (pkey);
}
if (ciph)
{
release_mpi_array (ciph);
gcry_free (ciph);
}
if (module)
{
ath_mutex_lock (&pubkeys_registered_lock);
_gcry_module_release (module);
ath_mutex_unlock (&pubkeys_registered_lock);
}
gcry_free (ctx.label);
return gcry_error (rc);
}
/*
Do a PK decrypt operation
Caller has to provide a secret key as the SEXP skey and data in a
format as created by gcry_pk_encrypt. For historic reasons the
function returns simply an MPI as an S-expression part; this is
deprecated and the new method should be used which returns a real
S-expressionl this is selected by adding at least an empty flags
list to S_DATA.
Returns: 0 or an errorcode.
s_data = (enc-val
[(flags [raw, pkcs1, oaep])]
(<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). In raw mode (or no flags given) the returned value
is to be interpreted as a signed MPI, thus it may have an extra
leading zero octet even if not included in the original data.
With pkcs1 or oaep decoding enabled the returned value is a
verbatim octet string.
*/
gcry_error_t
gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
{
gcry_mpi_t *skey = NULL, *data = NULL, plain = NULL;
unsigned char *unpad = NULL;
size_t unpadlen = 0;
int modern, flags;
struct pk_encoding_ctx ctx;
gcry_err_code_t rc;
gcry_module_t module_enc = NULL, module_key = NULL;
*r_plain = NULL;
ctx.label = NULL;
REGISTER_DEFAULT_PUBKEYS;
rc = sexp_to_key (s_skey, 1, GCRY_PK_USAGE_ENCR, NULL,
&skey, &module_key, NULL);
if (rc)
goto leave;
init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, gcry_pk_get_nbits (s_skey));
rc = sexp_to_enc (s_data, &data, &module_enc, &modern, &flags, &ctx);
if (rc)
goto leave;
if (module_key->mod_id != module_enc->mod_id)
{
rc = GPG_ERR_CONFLICT; /* Key algo does not match data algo. */
goto leave;
}
rc = pubkey_decrypt (module_key->mod_id, &plain, data, skey, flags);
if (rc)
goto leave;
/* Do un-padding if necessary. */
switch (ctx.encoding)
{
case PUBKEY_ENC_PKCS1:
rc = pkcs1_decode_for_encryption (&unpad, &unpadlen,
gcry_pk_get_nbits (s_skey), plain);
mpi_free (plain);
plain = NULL;
if (!rc)
rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)",
(int)unpadlen, unpad));
break;
case PUBKEY_ENC_OAEP:
rc = oaep_decode (&unpad, &unpadlen,
gcry_pk_get_nbits (s_skey), ctx.hash_algo,
plain, ctx.label, ctx.labellen);
mpi_free (plain);
plain = NULL;
if (!rc)
rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)",
(int)unpadlen, unpad));
break;
default:
/* Raw format. For backward compatibility we need to assume a
signed mpi by using the sexp format string "%m". */
rc = gcry_err_code (gcry_sexp_build
(r_plain, NULL, modern? "(value %m)" : "%m", plain));
break;
}
leave:
gcry_free (unpad);
if (skey)
{
release_mpi_array (skey);
gcry_free (skey);
}
mpi_free (plain);
if (data)
{
release_mpi_array (data);
gcry_free (data);
}
if (module_key || module_enc)
{
ath_mutex_lock (&pubkeys_registered_lock);
if (module_key)
_gcry_module_release (module_key);
if (module_enc)
_gcry_module_release (module_enc);
ath_mutex_unlock (&pubkeys_registered_lock);
}
gcry_free (ctx.label);
return gcry_error (rc);
}
/*
Create a signature.
Caller has to provide a secret key as the SEXP skey and data
expressed as a SEXP list hash with only one element which should
instantly be available as a MPI. Alternatively the structure given
below may be used for S_HASH, it provides the abiliy to pass flags
to the operation; the flags defined by now are "pkcs1" which does
PKCS#1 block type 1 style padding and "pss" for PSS encoding.
Returns: 0 or an errorcode.
In case of 0 the function returns a new SEXP with the
signature value; the structure of this signature depends on the
other arguments but is always suitable to be passed to
gcry_pk_verify
s_hash = See comment for sexp_data_to_mpi
s_skey = <key-as-defined-in-sexp_to_key>
r_sig = (sig-val
(<algo>
(<param_name1> <mpi>)
...
(<param_namen> <mpi>))
[(hash algo)])
Note that (hash algo) in R_SIG is not used.
*/
gcry_error_t
gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
{
gcry_mpi_t *skey = NULL, hash = NULL, *result = NULL;
gcry_pk_spec_t *pubkey = NULL;
gcry_module_t module = NULL;
const char *algo_name, *algo_elems;
struct pk_encoding_ctx ctx;
int i;
int is_ecc;
gcry_err_code_t rc;
*r_sig = NULL;
REGISTER_DEFAULT_PUBKEYS;
rc = sexp_to_key (s_skey, 1, GCRY_PK_USAGE_SIGN, NULL,
&skey, &module, &is_ecc);
if (rc)
goto leave;
gcry_assert (module);
pubkey = (gcry_pk_spec_t *) module->spec;
algo_name = pubkey->aliases? *pubkey->aliases : NULL;
if (!algo_name || !*algo_name)
algo_name = pubkey->name;
algo_elems = pubkey->elements_sig;
/* Get the stuff we want to sign. Note that pk_get_nbits does also
work on a private key. We don't need the number of bits for ECC
here, thus set it to 0 so that we don't need to parse it. */
init_encoding_ctx (&ctx, PUBKEY_OP_SIGN,
is_ecc? 0 : gcry_pk_get_nbits (s_skey));
rc = sexp_data_to_mpi (s_hash, &hash, &ctx);
if (rc)
goto leave;
result = gcry_calloc (strlen (algo_elems) + 1, sizeof (*result));
if (!result)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
- rc = pubkey_sign (module->mod_id, result, hash, skey);
+ rc = pubkey_sign (module->mod_id, result, hash, skey, &ctx);
if (rc)
goto leave;
if (ctx.encoding == PUBKEY_ENC_PSS
|| ctx.encoding == PUBKEY_ENC_PKCS1)
{
/* We need to make sure to return the correct length to avoid
problems with missing leading zeroes. We know that this
encoding does only make sense with RSA thus we don't need to
build the S-expression on the fly. */
unsigned char *em;
size_t emlen = (ctx.nbits+7)/8;
rc = octet_string_from_mpi (&em, NULL, result[0], emlen);
if (rc)
goto leave;
rc = gcry_err_code (gcry_sexp_build (r_sig, NULL,
"(sig-val(%s(s%b)))",
algo_name, (int)emlen, em));
gcry_free (em);
if (rc)
goto leave;
}
else
{
/* General purpose output encoding. Do it on the fly. */
char *string, *p;
size_t nelem, needed = strlen (algo_name) + 20;
void **arg_list;
nelem = strlen (algo_elems);
/* Count elements, so that we can allocate enough space. */
needed += 10 * nelem;
/* Build the string. */
string = p = gcry_malloc (needed);
if (!string)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
p = stpcpy (p, "(sig-val(");
p = stpcpy (p, algo_name);
for (i = 0; algo_elems[i]; i++)
{
*p++ = '(';
*p++ = algo_elems[i];
p = stpcpy (p, "%M)");
}
strcpy (p, "))");
arg_list = malloc (nelem * sizeof *arg_list);
if (!arg_list)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
for (i = 0; i < nelem; i++)
arg_list[i] = result + i;
rc = gcry_sexp_build_array (r_sig, NULL, string, arg_list);
free (arg_list);
if (rc)
BUG ();
gcry_free (string);
}
leave:
if (skey)
{
release_mpi_array (skey);
gcry_free (skey);
}
if (hash)
mpi_free (hash);
if (result)
{
release_mpi_array (result);
gcry_free (result);
}
return gcry_error (rc);
}
/*
Verify a signature.
Caller has to supply the public key pkey, the signature sig and his
hashvalue data. Public key has to be a standard public key given
as an S-Exp, sig is a S-Exp as returned from gcry_pk_sign and data
must be an S-Exp like the one in sign too. */
gcry_error_t
gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey)
{
gcry_module_t module_key = NULL, module_sig = NULL;
gcry_mpi_t *pkey = NULL, hash = NULL, *sig = NULL;
struct pk_encoding_ctx ctx;
gcry_err_code_t rc;
REGISTER_DEFAULT_PUBKEYS;
rc = sexp_to_key (s_pkey, 0, GCRY_PK_USAGE_SIGN, NULL,
&pkey, &module_key, NULL);
if (rc)
goto leave;
rc = sexp_to_sig (s_sig, &sig, &module_sig);
if (rc)
goto leave;
/* Fixme: Check that the algorithm of S_SIG is compatible to the one
of S_PKEY. */
if (module_key->mod_id != module_sig->mod_id)
{
rc = GPG_ERR_CONFLICT;
goto leave;
}
/* Get the stuff we want to verify. */
init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, gcry_pk_get_nbits (s_pkey));
rc = sexp_data_to_mpi (s_hash, &hash, &ctx);
if (rc)
goto leave;
rc = pubkey_verify (module_key->mod_id, hash, sig, pkey,
ctx.verify_cmp, &ctx);
leave:
if (pkey)
{
release_mpi_array (pkey);
gcry_free (pkey);
}
if (sig)
{
release_mpi_array (sig);
gcry_free (sig);
}
if (hash)
mpi_free (hash);
if (module_key || module_sig)
{
ath_mutex_lock (&pubkeys_registered_lock);
if (module_key)
_gcry_module_release (module_key);
if (module_sig)
_gcry_module_release (module_sig);
ath_mutex_unlock (&pubkeys_registered_lock);
}
return gcry_error (rc);
}
/*
Test a key.
This may be used either for a public or a secret key to see whether
the internal structure is okay.
Returns: 0 or an errorcode.
s_key = <key-as-defined-in-sexp_to_key> */
gcry_error_t
gcry_pk_testkey (gcry_sexp_t s_key)
{
gcry_module_t module = NULL;
gcry_mpi_t *key = NULL;
gcry_err_code_t rc;
REGISTER_DEFAULT_PUBKEYS;
/* Note we currently support only secret key checking. */
rc = sexp_to_key (s_key, 1, 0, NULL, &key, &module, NULL);
if (! rc)
{
rc = pubkey_check_secret_key (module->mod_id, key);
release_mpi_array (key);
gcry_free (key);
}
return gcry_error (rc);
}
/*
Create a public key pair and return it in r_key.
How the key is created depends on s_parms:
(genkey
(algo
(parameter_name_1 ....)
....
(parameter_name_n ....)
))
The key is returned in a format depending on the
algorithm. Both, private and secret keys are returned
and optionally some additional informatin.
For elgamal we return this structure:
(key-data
(public-key
(elg
(p <mpi>)
(g <mpi>)
(y <mpi>)
)
)
(private-key
(elg
(p <mpi>)
(g <mpi>)
(y <mpi>)
(x <mpi>)
)
)
(misc-key-info
(pm1-factors n1 n2 ... nn)
))
*/
gcry_error_t
gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
{
gcry_pk_spec_t *pubkey = NULL;
gcry_module_t module = NULL;
gcry_sexp_t list = NULL;
gcry_sexp_t l2 = NULL;
gcry_sexp_t l3 = NULL;
char *name = NULL;
size_t n;
gcry_err_code_t rc = GPG_ERR_NO_ERROR;
int i, j;
const char *algo_name = NULL;
int algo;
const char *sec_elems = NULL, *pub_elems = NULL;
gcry_mpi_t skey[12];
gcry_mpi_t *factors = NULL;
gcry_sexp_t extrainfo = NULL;
unsigned int nbits = 0;
unsigned long use_e = 0;
skey[0] = NULL;
*r_key = NULL;
REGISTER_DEFAULT_PUBKEYS;
list = gcry_sexp_find_token (s_parms, "genkey", 0);
if (!list)
{
rc = GPG_ERR_INV_OBJ; /* Does not contain genkey data. */
goto leave;
}
l2 = gcry_sexp_cadr (list);
gcry_sexp_release (list);
list = l2;
l2 = NULL;
if (! list)
{
rc = GPG_ERR_NO_OBJ; /* No cdr for the genkey. */
goto leave;
}
name = _gcry_sexp_nth_string (list, 0);
if (!name)
{
rc = GPG_ERR_INV_OBJ; /* Algo string missing. */
goto leave;
}
ath_mutex_lock (&pubkeys_registered_lock);
module = gcry_pk_lookup_name (name);
ath_mutex_unlock (&pubkeys_registered_lock);
gcry_free (name);
name = NULL;
if (!module)
{
rc = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
goto leave;
}
pubkey = (gcry_pk_spec_t *) module->spec;
algo = module->mod_id;
algo_name = pubkey->aliases? *pubkey->aliases : NULL;
if (!algo_name || !*algo_name)
algo_name = pubkey->name;
pub_elems = pubkey->elements_pkey;
sec_elems = pubkey->elements_skey;
if (strlen (sec_elems) >= DIM(skey))
BUG ();
/* Handle the optional rsa-use-e element. Actually this belong into
the algorithm module but we have this parameter in the public
module API, so we need to parse it right here. */
l2 = gcry_sexp_find_token (list, "rsa-use-e", 0);
if (l2)
{
char buf[50];
const char *s;
s = gcry_sexp_nth_data (l2, 1, &n);
if ( !s || n >= DIM (buf) - 1 )
{
rc = GPG_ERR_INV_OBJ; /* No value or value too large. */
goto leave;
}
memcpy (buf, s, n);
buf[n] = 0;
use_e = strtoul (buf, NULL, 0);
gcry_sexp_release (l2);
l2 = NULL;
}
else
use_e = 65537; /* Not given, use the value generated by old versions. */
/* Get the "nbits" parameter. */
l2 = gcry_sexp_find_token (list, "nbits", 0);
if (l2)
{
char buf[50];
const char *s;
s = gcry_sexp_nth_data (l2, 1, &n);
if (!s || n >= DIM (buf) - 1 )
{
rc = GPG_ERR_INV_OBJ; /* NBITS given without a cdr. */
goto leave;
}
memcpy (buf, s, n);
buf[n] = 0;
nbits = (unsigned int)strtoul (buf, NULL, 0);
gcry_sexp_release (l2); l2 = NULL;
}
else
nbits = 0;
/* Pass control to the algorithm module. */
rc = pubkey_generate (module->mod_id, nbits, use_e, list, skey,
&factors, &extrainfo);
gcry_sexp_release (list); list = NULL;
if (rc)
goto leave;
/* Key generation succeeded: Build an S-expression. */
{
char *string, *p;
size_t nelem=0, nelem_cp = 0, needed=0;
gcry_mpi_t mpis[30];
int percent_s_idx = -1;
/* Estimate size of format string. */
nelem = strlen (pub_elems) + strlen (sec_elems);
if (factors)
{
for (i = 0; factors[i]; i++)
nelem++;
}
nelem_cp = nelem;
needed += nelem * 10;
/* (+5 is for EXTRAINFO ("%S")). */
needed += 2 * strlen (algo_name) + 300 + 5;
if (nelem > DIM (mpis))
BUG ();
/* Build the string. */
nelem = 0;
string = p = gcry_malloc (needed);
if (!string)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
p = stpcpy (p, "(key-data");
p = stpcpy (p, "(public-key(");
p = stpcpy (p, algo_name);
for(i = 0; pub_elems[i]; i++)
{
*p++ = '(';
*p++ = pub_elems[i];
p = stpcpy (p, "%m)");
mpis[nelem++] = skey[i];
}
if (extrainfo && (algo == GCRY_PK_ECDSA || algo == GCRY_PK_ECDH))
{
/* Very ugly hack to insert the used curve parameter into the
list of public key parameters. */
percent_s_idx = nelem;
p = stpcpy (p, "%S");
}
p = stpcpy (p, "))");
p = stpcpy (p, "(private-key(");
p = stpcpy (p, algo_name);
for (i = 0; sec_elems[i]; i++)
{
*p++ = '(';
*p++ = sec_elems[i];
p = stpcpy (p, "%m)");
mpis[nelem++] = skey[i];
}
p = stpcpy (p, "))");
/* Hack to make release_mpi_array() work. */
skey[i] = NULL;
if (extrainfo && percent_s_idx == -1)
{
/* If we have extrainfo we should not have any factors. */
p = stpcpy (p, "%S");
}
else if (factors && factors[0])
{
p = stpcpy (p, "(misc-key-info(pm1-factors");
for(i = 0; factors[i]; i++)
{
p = stpcpy (p, "%m");
mpis[nelem++] = factors[i];
}
p = stpcpy (p, "))");
}
strcpy (p, ")");
gcry_assert (p - string < needed);
while (nelem < DIM (mpis))
mpis[nelem++] = NULL;
{
int elem_n = strlen (pub_elems) + strlen (sec_elems);
void **arg_list;
/* Allocate one extra for EXTRAINFO ("%S"). */
arg_list = gcry_calloc (nelem_cp+1, sizeof *arg_list);
if (!arg_list)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
for (i = j = 0; i < elem_n; i++)
{
if (i == percent_s_idx)
arg_list[j++] = &extrainfo;
arg_list[j++] = mpis + i;
}
if (extrainfo && percent_s_idx == -1)
arg_list[j] = &extrainfo;
else if (factors && factors[0])
{
for (; i < nelem_cp; i++)
arg_list[j++] = factors + i - elem_n;
}
rc = gcry_sexp_build_array (r_key, NULL, string, arg_list);
gcry_free (arg_list);
if (rc)
BUG ();
gcry_assert (DIM (mpis) == 30); /* Reminder to make sure that
the array gets increased if
new parameters are added. */
}
gcry_free (string);
}
leave:
gcry_free (name);
gcry_sexp_release (extrainfo);
release_mpi_array (skey);
/* Don't free SKEY itself, it is an stack allocated array. */
if (factors)
{
release_mpi_array ( factors );
gcry_free (factors);
}
gcry_sexp_release (l3);
gcry_sexp_release (l2);
gcry_sexp_release (list);
if (module)
{
ath_mutex_lock (&pubkeys_registered_lock);
_gcry_module_release (module);
ath_mutex_unlock (&pubkeys_registered_lock);
}
return gcry_error (rc);
}
/*
Get the number of nbits from the public key.
Hmmm: Should we have really this function or is it better to have a
more general function to retrieve different properties of the key? */
unsigned int
gcry_pk_get_nbits (gcry_sexp_t key)
{
gcry_module_t module = NULL;
gcry_pk_spec_t *pubkey;
gcry_mpi_t *keyarr = NULL;
unsigned int nbits = 0;
gcry_err_code_t rc;
REGISTER_DEFAULT_PUBKEYS;
/* FIXME: Parsing KEY is often too much overhead. For example for
ECC we would only need to look at P and stop parsing right
away. */
rc = sexp_to_key (key, 0, 0, NULL, &keyarr, &module, NULL);
if (rc == GPG_ERR_INV_OBJ)
rc = sexp_to_key (key, 1, 0, NULL, &keyarr, &module, NULL);
if (rc)
return 0; /* Error - 0 is a suitable indication for that. */
pubkey = (gcry_pk_spec_t *) module->spec;
nbits = (*pubkey->get_nbits) (module->mod_id, keyarr);
ath_mutex_lock (&pubkeys_registered_lock);
_gcry_module_release (module);
ath_mutex_unlock (&pubkeys_registered_lock);
release_mpi_array (keyarr);
gcry_free (keyarr);
return nbits;
}
/* Return the so called KEYGRIP which is the SHA-1 hash of the public
key parameters expressed in a way depending on the algorithm.
ARRAY must either be 20 bytes long or NULL; in the latter case a
newly allocated array of that size is returned, otherwise ARRAY or
NULL is returned to indicate an error which is most likely an
unknown algorithm. The function accepts public or secret keys. */
unsigned char *
gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
{
gcry_sexp_t list = NULL, l2 = NULL;
gcry_pk_spec_t *pubkey = NULL;
gcry_module_t module = NULL;
pk_extra_spec_t *extraspec;
const char *s;
char *name = NULL;
int idx;
const char *elems;
gcry_md_hd_t md = NULL;
int okay = 0;
REGISTER_DEFAULT_PUBKEYS;
/* Check that the first element is valid. */
list = gcry_sexp_find_token (key, "public-key", 0);
if (! list)
list = gcry_sexp_find_token (key, "private-key", 0);
if (! list)
list = gcry_sexp_find_token (key, "protected-private-key", 0);
if (! list)
list = gcry_sexp_find_token (key, "shadowed-private-key", 0);
if (! list)
return NULL; /* No public- or private-key object. */
l2 = gcry_sexp_cadr (list);
gcry_sexp_release (list);
list = l2;
l2 = NULL;
name = _gcry_sexp_nth_string (list, 0);
if (!name)
goto fail; /* Invalid structure of object. */
ath_mutex_lock (&pubkeys_registered_lock);
module = gcry_pk_lookup_name (name);
ath_mutex_unlock (&pubkeys_registered_lock);
if (!module)
goto fail; /* Unknown algorithm. */
pubkey = (gcry_pk_spec_t *) module->spec;
extraspec = module->extraspec;
elems = pubkey->elements_grip;
if (!elems)
goto fail; /* No grip parameter. */
if (gcry_md_open (&md, GCRY_MD_SHA1, 0))
goto fail;
if (extraspec && extraspec->comp_keygrip)
{
/* Module specific method to compute a keygrip. */
if (extraspec->comp_keygrip (md, list))
goto fail;
}
else
{
/* Generic method to compute a keygrip. */
for (idx = 0, s = elems; *s; s++, idx++)
{
const char *data;
size_t datalen;
char buf[30];
l2 = gcry_sexp_find_token (list, s, 1);
if (! l2)
goto fail;
data = gcry_sexp_nth_data (l2, 1, &datalen);
if (! data)
goto fail;
snprintf (buf, sizeof buf, "(1:%c%u:", *s, (unsigned int)datalen);
gcry_md_write (md, buf, strlen (buf));
gcry_md_write (md, data, datalen);
gcry_sexp_release (l2);
l2 = NULL;
gcry_md_write (md, ")", 1);
}
}
if (!array)
{
array = gcry_malloc (20);
if (! array)
goto fail;
}
memcpy (array, gcry_md_read (md, GCRY_MD_SHA1), 20);
okay = 1;
fail:
gcry_free (name);
gcry_sexp_release (l2);
gcry_md_close (md);
gcry_sexp_release (list);
return okay? array : NULL;
}
const char *
gcry_pk_get_curve (gcry_sexp_t key, int iterator, unsigned int *r_nbits)
{
gcry_mpi_t *pkey = NULL;
gcry_sexp_t list = NULL;
gcry_sexp_t l2;
gcry_module_t module = NULL;
pk_extra_spec_t *extraspec;
char *name = NULL;
const char *result = NULL;
int want_private = 1;
if (r_nbits)
*r_nbits = 0;
REGISTER_DEFAULT_PUBKEYS;
if (key)
{
iterator = 0;
/* Check that the first element is valid. */
list = gcry_sexp_find_token (key, "public-key", 0);
if (list)
want_private = 0;
if (!list)
list = gcry_sexp_find_token (key, "private-key", 0);
if (!list)
return NULL; /* No public- or private-key object. */
l2 = gcry_sexp_cadr (list);
gcry_sexp_release (list);
list = l2;
l2 = NULL;
name = _gcry_sexp_nth_string (list, 0);
if (!name)
goto leave; /* Invalid structure of object. */
/* Get the key. We pass the names of the parameters for
override_elems; this allows to call this function without the
actual public key parameter. */
if (sexp_to_key (key, want_private, 0, "pabgn", &pkey, &module, NULL))
goto leave;
}
else
{
ath_mutex_lock (&pubkeys_registered_lock);
module = gcry_pk_lookup_name ("ecc");
ath_mutex_unlock (&pubkeys_registered_lock);
if (!module)
goto leave;
}
extraspec = module->extraspec;
if (!extraspec || !extraspec->get_curve)
goto leave;
result = extraspec->get_curve (pkey, iterator, r_nbits);
leave:
if (pkey)
{
release_mpi_array (pkey);
gcry_free (pkey);
}
if (module)
{
ath_mutex_lock (&pubkeys_registered_lock);
_gcry_module_release (module);
ath_mutex_unlock (&pubkeys_registered_lock);
}
gcry_free (name);
gcry_sexp_release (list);
return result;
}
gcry_sexp_t
gcry_pk_get_param (int algo, const char *name)
{
gcry_module_t module = NULL;
pk_extra_spec_t *extraspec;
gcry_sexp_t result = NULL;
if (algo != GCRY_PK_ECDSA && algo != GCRY_PK_ECDH)
return NULL;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
module = gcry_pk_lookup_name ("ecc");
ath_mutex_unlock (&pubkeys_registered_lock);
if (module)
{
extraspec = module->extraspec;
if (extraspec && extraspec->get_curve_param)
result = extraspec->get_curve_param (name);
ath_mutex_lock (&pubkeys_registered_lock);
_gcry_module_release (module);
ath_mutex_unlock (&pubkeys_registered_lock);
}
return result;
}
gcry_error_t
gcry_pk_ctl (int cmd, void *buffer, size_t buflen)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
REGISTER_DEFAULT_PUBKEYS;
switch (cmd)
{
case GCRYCTL_DISABLE_ALGO:
/* This one expects a buffer pointing to an integer with the
algo number. */
if ((! buffer) || (buflen != sizeof (int)))
err = GPG_ERR_INV_ARG;
else
disable_pubkey_algo (*((int *) buffer));
break;
default:
err = GPG_ERR_INV_OP;
}
return gcry_error (err);
}
/* Return information about the given algorithm
WHAT selects the kind of information returned:
GCRYCTL_TEST_ALGO:
Returns 0 when the specified algorithm is available for use.
Buffer must be NULL, nbytes may have the address of a variable
with the required usage of the algorithm. It may be 0 for don't
care or a combination of the GCRY_PK_USAGE_xxx flags;
GCRYCTL_GET_ALGO_USAGE:
Return the usage flags for the given algo. An invalid algo
returns 0. Disabled algos are ignored here because we
only want to know whether the algo is at all capable of
the usage.
Note: Because this function is in most cases used to return an
integer value, we can make it easier for the caller to just look at
the return value. The caller will in all cases consult the value
and thereby detecting whether a error occurred or not (i.e. while
checking the block size) */
gcry_error_t
gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
switch (what)
{
case GCRYCTL_TEST_ALGO:
{
int use = nbytes ? *nbytes : 0;
if (buffer)
err = GPG_ERR_INV_ARG;
else if (check_pubkey_algo (algorithm, use))
err = GPG_ERR_PUBKEY_ALGO;
break;
}
case GCRYCTL_GET_ALGO_USAGE:
{
gcry_module_t pubkey;
int use = 0;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
if (pubkey)
{
use = ((gcry_pk_spec_t *) pubkey->spec)->use;
_gcry_module_release (pubkey);
}
ath_mutex_unlock (&pubkeys_registered_lock);
/* FIXME? */
*nbytes = use;
break;
}
case GCRYCTL_GET_ALGO_NPKEY:
{
/* FIXME? */
int npkey = pubkey_get_npkey (algorithm);
*nbytes = npkey;
break;
}
case GCRYCTL_GET_ALGO_NSKEY:
{
/* FIXME? */
int nskey = pubkey_get_nskey (algorithm);
*nbytes = nskey;
break;
}
case GCRYCTL_GET_ALGO_NSIGN:
{
/* FIXME? */
int nsign = pubkey_get_nsig (algorithm);
*nbytes = nsign;
break;
}
case GCRYCTL_GET_ALGO_NENCR:
{
/* FIXME? */
int nencr = pubkey_get_nenc (algorithm);
*nbytes = nencr;
break;
}
default:
err = GPG_ERR_INV_OP;
}
return gcry_error (err);
}
/* Return an S-expression representing the context CTX. Depending on
the state of that context, the S-expression may either be a public
key, a private key or any other object used with public key
operations. On success a new S-expression is stored at R_SEXP and
0 is returned, on error NULL is store there and an error code is
returned. MODE is either 0 or one of the GCRY_PK_GET_xxx values.
As of now it only support certain ECC operations because a context
object is right now only defined for ECC. Over time this function
will be extended to cover more algorithms. Note also that the name
of the function is gcry_pubkey_xxx and not gcry_pk_xxx. The idea
is that we will eventually provide variants of the existing
gcry_pk_xxx functions which will take a context parameter. */
gcry_err_code_t
_gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp, int mode, gcry_ctx_t ctx)
{
mpi_ec_t ec;
if (!r_sexp)
return GPG_ERR_INV_VALUE;
*r_sexp = NULL;
switch (mode)
{
case 0:
case GCRY_PK_GET_PUBKEY:
case GCRY_PK_GET_SECKEY:
break;
default:
return GPG_ERR_INV_VALUE;
}
if (!ctx)
return GPG_ERR_NO_CRYPT_CTX;
ec = _gcry_ctx_find_pointer (ctx, CONTEXT_TYPE_EC);
if (ec)
return _gcry_pk_ecc_get_sexp (r_sexp, mode, ec);
return GPG_ERR_WRONG_CRYPT_CTX;
}
/* Explicitly initialize this module. */
gcry_err_code_t
_gcry_pk_init (void)
{
gcry_err_code_t err;
err = ath_mutex_init (&pubkeys_registered_lock);
if (err)
return gpg_err_code_from_errno (err);
REGISTER_DEFAULT_PUBKEYS;
return err;
}
/* Run the selftests for pubkey algorithm ALGO with optional reporting
function REPORT. */
gpg_error_t
_gcry_pk_selftest (int algo, int extended, selftest_report_func_t report)
{
gcry_module_t module = NULL;
pk_extra_spec_t *extraspec = NULL;
gcry_err_code_t ec = 0;
REGISTER_DEFAULT_PUBKEYS;
ath_mutex_lock (&pubkeys_registered_lock);
module = _gcry_module_lookup_id (pubkeys_registered, algo);
if (module && !(module->flags & FLAG_MODULE_DISABLED))
extraspec = module->extraspec;
ath_mutex_unlock (&pubkeys_registered_lock);
if (extraspec && extraspec->selftest)
ec = extraspec->selftest (algo, extended, report);
else
{
ec = GPG_ERR_PUBKEY_ALGO;
if (report)
report ("pubkey", algo, "module",
module && !(module->flags & FLAG_MODULE_DISABLED)?
"no selftest available" :
module? "algorithm disabled" : "algorithm not found");
}
if (module)
{
ath_mutex_lock (&pubkeys_registered_lock);
_gcry_module_release (module);
ath_mutex_unlock (&pubkeys_registered_lock);
}
return gpg_error (ec);
}
diff --git a/cipher/rsa.c b/cipher/rsa.c
index 4787f813..c9fcebf0 100644
--- a/cipher/rsa.c
+++ b/cipher/rsa.c
@@ -1,1393 +1,1399 @@
/* rsa.c - RSA implementation
* Copyright (C) 1997, 1998, 1999 by Werner Koch (dd9jn)
* Copyright (C) 2000, 2001, 2002, 2003, 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* This code uses an algorithm protected by U.S. Patent #4,405,829
which expired on September 20, 2000. The patent holder placed that
patent into the public domain on Sep 6th, 2000.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
typedef struct
{
gcry_mpi_t n; /* modulus */
gcry_mpi_t e; /* exponent */
} RSA_public_key;
typedef struct
{
gcry_mpi_t n; /* public modulus */
gcry_mpi_t e; /* public exponent */
gcry_mpi_t d; /* exponent */
gcry_mpi_t p; /* prime p. */
gcry_mpi_t q; /* prime q. */
gcry_mpi_t u; /* inverse of p mod q. */
} RSA_secret_key;
/* A sample 1024 bit RSA key used for the selftests. */
static const char sample_secret_key[] =
"(private-key"
" (rsa"
" (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa"
" 2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291"
" ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7"
" 891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)"
" (e #010001#)"
" (d #046129f2489d71579be0a75fe029bd6cdb574ebf57ea8a5b0fda942cab943b11"
" 7d7bb95e5d28875e0f9fc5fcc06a72f6d502464dabded78ef6b716177b83d5bd"
" c543dc5d3fed932e59f5897e92e6f58a0f33424106a3b6fa2cbf877510e4ac21"
" c3ee47851e97d12996222ac3566d4ccb0b83d164074abf7de655fc2446da1781#)"
" (p #00e861b700e17e8afe6837e7512e35b6ca11d0ae47d8b85161c67baf64377213"
" fe52d772f2035b3ca830af41d8a4120e1c1c70d12cc22f00d28d31dd48a8d424f1#)"
" (q #00f7a7ca5367c661f8e62df34f0d05c10c88e5492348dd7bddc942c9a8f369f9"
" 35a07785d2db805215ed786e4285df1658eed3ce84f469b81b50d358407b4ad361#)"
" (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e"
" ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b#)))";
/* A sample 1024 bit RSA key used for the selftests (public only). */
static const char sample_public_key[] =
"(public-key"
" (rsa"
" (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa"
" 2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291"
" ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7"
" 891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)"
" (e #010001#)))";
static int test_keys (RSA_secret_key *sk, unsigned nbits);
static int check_secret_key (RSA_secret_key *sk);
static void public (gcry_mpi_t output, gcry_mpi_t input, RSA_public_key *skey);
static void secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey);
/* Check that a freshly generated key actually works. Returns 0 on success. */
static int
test_keys (RSA_secret_key *sk, unsigned int nbits)
{
int result = -1; /* Default to failure. */
RSA_public_key pk;
gcry_mpi_t plaintext = gcry_mpi_new (nbits);
gcry_mpi_t ciphertext = gcry_mpi_new (nbits);
gcry_mpi_t decr_plaintext = gcry_mpi_new (nbits);
gcry_mpi_t signature = gcry_mpi_new (nbits);
/* Put the relevant parameters into a public key structure. */
pk.n = sk->n;
pk.e = sk->e;
/* Create a random plaintext. */
gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM);
/* Encrypt using the public key. */
public (ciphertext, plaintext, &pk);
/* Check that the cipher text does not match the plaintext. */
if (!gcry_mpi_cmp (ciphertext, plaintext))
goto leave; /* Ciphertext is identical to the plaintext. */
/* Decrypt using the secret key. */
secret (decr_plaintext, ciphertext, sk);
/* Check that the decrypted plaintext matches the original plaintext. */
if (gcry_mpi_cmp (decr_plaintext, plaintext))
goto leave; /* Plaintext does not match. */
/* Create another random plaintext as data for signature checking. */
gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM);
/* Use the RSA secret function to create a signature of the plaintext. */
secret (signature, plaintext, sk);
/* Use the RSA public function to verify this signature. */
public (decr_plaintext, signature, &pk);
if (gcry_mpi_cmp (decr_plaintext, plaintext))
goto leave; /* Signature does not match. */
/* Modify the signature and check that the signing fails. */
gcry_mpi_add_ui (signature, signature, 1);
public (decr_plaintext, signature, &pk);
if (!gcry_mpi_cmp (decr_plaintext, plaintext))
goto leave; /* Signature matches but should not. */
result = 0; /* All tests succeeded. */
leave:
gcry_mpi_release (signature);
gcry_mpi_release (decr_plaintext);
gcry_mpi_release (ciphertext);
gcry_mpi_release (plaintext);
return result;
}
/* Callback used by the prime generation to test whether the exponent
is suitable. Returns 0 if the test has been passed. */
static int
check_exponent (void *arg, gcry_mpi_t a)
{
gcry_mpi_t e = arg;
gcry_mpi_t tmp;
int result;
mpi_sub_ui (a, a, 1);
tmp = _gcry_mpi_alloc_like (a);
result = !gcry_mpi_gcd(tmp, e, a); /* GCD is not 1. */
gcry_mpi_release (tmp);
mpi_add_ui (a, a, 1);
return result;
}
/****************
* Generate a key pair with a key of size NBITS.
* USE_E = 0 let Libcgrypt decide what exponent to use.
* = 1 request the use of a "secure" exponent; this is required by some
* specification to be 65537.
* > 2 Use this public exponent. If the given exponent
* is not odd one is internally added to it.
* TRANSIENT_KEY: If true, generate the primes using the standard RNG.
* Returns: 2 structures filled with all needed values
*/
static gpg_err_code_t
generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e,
int transient_key)
{
gcry_mpi_t p, q; /* the two primes */
gcry_mpi_t d; /* the private key */
gcry_mpi_t u;
gcry_mpi_t t1, t2;
gcry_mpi_t n; /* the public key */
gcry_mpi_t e; /* the exponent */
gcry_mpi_t phi; /* helper: (p-1)(q-1) */
gcry_mpi_t g;
gcry_mpi_t f;
gcry_random_level_t random_level;
if (fips_mode ())
{
if (nbits < 1024)
return GPG_ERR_INV_VALUE;
if (transient_key)
return GPG_ERR_INV_VALUE;
}
/* The random quality depends on the transient_key flag. */
random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
/* Make sure that nbits is even so that we generate p, q of equal size. */
if ( (nbits&1) )
nbits++;
if (use_e == 1) /* Alias for a secure value */
use_e = 65537; /* as demanded by Sphinx. */
/* Public exponent:
In general we use 41 as this is quite fast and more secure than the
commonly used 17. Benchmarking the RSA verify function
with a 1024 bit key yields (2001-11-08):
e=17 0.54 ms
e=41 0.75 ms
e=257 0.95 ms
e=65537 1.80 ms
*/
e = mpi_alloc( (32+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
if (!use_e)
mpi_set_ui (e, 41); /* This is a reasonable secure and fast value */
else
{
use_e |= 1; /* make sure this is odd */
mpi_set_ui (e, use_e);
}
n = gcry_mpi_new (nbits);
p = q = NULL;
do
{
/* select two (very secret) primes */
if (p)
gcry_mpi_release (p);
if (q)
gcry_mpi_release (q);
if (use_e)
{ /* Do an extra test to ensure that the given exponent is
suitable. */
p = _gcry_generate_secret_prime (nbits/2, random_level,
check_exponent, e);
q = _gcry_generate_secret_prime (nbits/2, random_level,
check_exponent, e);
}
else
{ /* We check the exponent later. */
p = _gcry_generate_secret_prime (nbits/2, random_level, NULL, NULL);
q = _gcry_generate_secret_prime (nbits/2, random_level, NULL, NULL);
}
if (mpi_cmp (p, q) > 0 ) /* p shall be smaller than q (for calc of u)*/
mpi_swap(p,q);
/* calculate the modulus */
mpi_mul( n, p, q );
}
while ( mpi_get_nbits(n) != nbits );
/* calculate Euler totient: phi = (p-1)(q-1) */
t1 = mpi_alloc_secure( mpi_get_nlimbs(p) );
t2 = mpi_alloc_secure( mpi_get_nlimbs(p) );
phi = gcry_mpi_snew ( nbits );
g = gcry_mpi_snew ( nbits );
f = gcry_mpi_snew ( nbits );
mpi_sub_ui( t1, p, 1 );
mpi_sub_ui( t2, q, 1 );
mpi_mul( phi, t1, t2 );
gcry_mpi_gcd(g, t1, t2);
mpi_fdiv_q(f, phi, g);
while (!gcry_mpi_gcd(t1, e, phi)) /* (while gcd is not 1) */
{
if (use_e)
BUG (); /* The prime generator already made sure that we
never can get to here. */
mpi_add_ui (e, e, 2);
}
/* calculate the secret key d = e^1 mod phi */
d = gcry_mpi_snew ( nbits );
mpi_invm(d, e, f );
/* calculate the inverse of p and q (used for chinese remainder theorem)*/
u = gcry_mpi_snew ( nbits );
mpi_invm(u, p, q );
if( DBG_CIPHER )
{
log_mpidump(" p= ", p );
log_mpidump(" q= ", q );
log_mpidump("phi= ", phi );
log_mpidump(" g= ", g );
log_mpidump(" f= ", f );
log_mpidump(" n= ", n );
log_mpidump(" e= ", e );
log_mpidump(" d= ", d );
log_mpidump(" u= ", u );
}
gcry_mpi_release (t1);
gcry_mpi_release (t2);
gcry_mpi_release (phi);
gcry_mpi_release (f);
gcry_mpi_release (g);
sk->n = n;
sk->e = e;
sk->p = p;
sk->q = q;
sk->d = d;
sk->u = u;
/* Now we can test our keys. */
if (test_keys (sk, nbits - 64))
{
gcry_mpi_release (sk->n); sk->n = NULL;
gcry_mpi_release (sk->e); sk->e = NULL;
gcry_mpi_release (sk->p); sk->p = NULL;
gcry_mpi_release (sk->q); sk->q = NULL;
gcry_mpi_release (sk->d); sk->d = NULL;
gcry_mpi_release (sk->u); sk->u = NULL;
fips_signal_error ("self-test after key generation failed");
return GPG_ERR_SELFTEST_FAILED;
}
return 0;
}
/* Helper for generate_x931. */
static gcry_mpi_t
gen_x931_parm_xp (unsigned int nbits)
{
gcry_mpi_t xp;
xp = gcry_mpi_snew (nbits);
gcry_mpi_randomize (xp, nbits, GCRY_VERY_STRONG_RANDOM);
/* The requirement for Xp is:
sqrt{2}*2^{nbits-1} <= xp <= 2^{nbits} - 1
We set the two high order bits to 1 to satisfy the lower bound.
By using mpi_set_highbit we make sure that the upper bound is
satisfied as well. */
mpi_set_highbit (xp, nbits-1);
mpi_set_bit (xp, nbits-2);
gcry_assert ( mpi_get_nbits (xp) == nbits );
return xp;
}
/* Helper for generate_x931. */
static gcry_mpi_t
gen_x931_parm_xi (void)
{
gcry_mpi_t xi;
xi = gcry_mpi_snew (101);
gcry_mpi_randomize (xi, 101, GCRY_VERY_STRONG_RANDOM);
mpi_set_highbit (xi, 100);
gcry_assert ( mpi_get_nbits (xi) == 101 );
return xi;
}
/* Variant of the standard key generation code using the algorithm
from X9.31. Using this algorithm has the advantage that the
generation can be made deterministic which is required for CAVS
testing. */
static gpg_err_code_t
generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value,
gcry_sexp_t deriveparms, int *swapped)
{
gcry_mpi_t p, q; /* The two primes. */
gcry_mpi_t e; /* The public exponent. */
gcry_mpi_t n; /* The public key. */
gcry_mpi_t d; /* The private key */
gcry_mpi_t u; /* The inverse of p and q. */
gcry_mpi_t pm1; /* p - 1 */
gcry_mpi_t qm1; /* q - 1 */
gcry_mpi_t phi; /* Euler totient. */
gcry_mpi_t f, g; /* Helper. */
*swapped = 0;
if (e_value == 1) /* Alias for a secure value. */
e_value = 65537;
/* Point 1 of section 4.1: k = 1024 + 256s with S >= 0 */
if (nbits < 1024 || (nbits % 256))
return GPG_ERR_INV_VALUE;
/* Point 2: 2 <= bitlength(e) < 2^{k-2}
Note that we do not need to check the upper bound because we use
an unsigned long for E and thus there is no way for E to reach
that limit. */
if (e_value < 3)
return GPG_ERR_INV_VALUE;
/* Our implementaion requires E to be odd. */
if (!(e_value & 1))
return GPG_ERR_INV_VALUE;
/* Point 3: e > 0 or e 0 if it is to be randomly generated.
We support only a fixed E and thus there is no need for an extra test. */
/* Compute or extract the derive parameters. */
{
gcry_mpi_t xp1 = NULL;
gcry_mpi_t xp2 = NULL;
gcry_mpi_t xp = NULL;
gcry_mpi_t xq1 = NULL;
gcry_mpi_t xq2 = NULL;
gcry_mpi_t xq = NULL;
gcry_mpi_t tmpval;
if (!deriveparms)
{
/* Not given: Generate them. */
xp = gen_x931_parm_xp (nbits/2);
/* Make sure that |xp - xq| > 2^{nbits - 100} holds. */
tmpval = gcry_mpi_snew (nbits/2);
do
{
gcry_mpi_release (xq);
xq = gen_x931_parm_xp (nbits/2);
mpi_sub (tmpval, xp, xq);
}
while (mpi_get_nbits (tmpval) <= (nbits/2 - 100));
gcry_mpi_release (tmpval);
xp1 = gen_x931_parm_xi ();
xp2 = gen_x931_parm_xi ();
xq1 = gen_x931_parm_xi ();
xq2 = gen_x931_parm_xi ();
}
else
{
/* Parameters to derive the key are given. */
/* Note that we explicitly need to setup the values of tbl
because some compilers (e.g. OpenWatcom, IRIX) don't allow
to initialize a structure with automatic variables. */
struct { const char *name; gcry_mpi_t *value; } tbl[] = {
{ "Xp1" },
{ "Xp2" },
{ "Xp" },
{ "Xq1" },
{ "Xq2" },
{ "Xq" },
{ NULL }
};
int idx;
gcry_sexp_t oneparm;
tbl[0].value = &xp1;
tbl[1].value = &xp2;
tbl[2].value = &xp;
tbl[3].value = &xq1;
tbl[4].value = &xq2;
tbl[5].value = &xq;
for (idx=0; tbl[idx].name; idx++)
{
oneparm = gcry_sexp_find_token (deriveparms, tbl[idx].name, 0);
if (oneparm)
{
*tbl[idx].value = gcry_sexp_nth_mpi (oneparm, 1,
GCRYMPI_FMT_USG);
gcry_sexp_release (oneparm);
}
}
for (idx=0; tbl[idx].name; idx++)
if (!*tbl[idx].value)
break;
if (tbl[idx].name)
{
/* At least one parameter is missing. */
for (idx=0; tbl[idx].name; idx++)
gcry_mpi_release (*tbl[idx].value);
return GPG_ERR_MISSING_VALUE;
}
}
e = mpi_alloc_set_ui (e_value);
/* Find two prime numbers. */
p = _gcry_derive_x931_prime (xp, xp1, xp2, e, NULL, NULL);
q = _gcry_derive_x931_prime (xq, xq1, xq2, e, NULL, NULL);
gcry_mpi_release (xp); xp = NULL;
gcry_mpi_release (xp1); xp1 = NULL;
gcry_mpi_release (xp2); xp2 = NULL;
gcry_mpi_release (xq); xq = NULL;
gcry_mpi_release (xq1); xq1 = NULL;
gcry_mpi_release (xq2); xq2 = NULL;
if (!p || !q)
{
gcry_mpi_release (p);
gcry_mpi_release (q);
gcry_mpi_release (e);
return GPG_ERR_NO_PRIME;
}
}
/* Compute the public modulus. We make sure that p is smaller than
q to allow the use of the CRT. */
if (mpi_cmp (p, q) > 0 )
{
mpi_swap (p, q);
*swapped = 1;
}
n = gcry_mpi_new (nbits);
mpi_mul (n, p, q);
/* Compute the Euler totient: phi = (p-1)(q-1) */
pm1 = gcry_mpi_snew (nbits/2);
qm1 = gcry_mpi_snew (nbits/2);
phi = gcry_mpi_snew (nbits);
mpi_sub_ui (pm1, p, 1);
mpi_sub_ui (qm1, q, 1);
mpi_mul (phi, pm1, qm1);
g = gcry_mpi_snew (nbits);
gcry_assert (gcry_mpi_gcd (g, e, phi));
/* Compute: f = lcm(p-1,q-1) = phi / gcd(p-1,q-1) */
gcry_mpi_gcd (g, pm1, qm1);
f = pm1; pm1 = NULL;
gcry_mpi_release (qm1); qm1 = NULL;
mpi_fdiv_q (f, phi, g);
gcry_mpi_release (phi); phi = NULL;
d = g; g = NULL;
/* Compute the secret key: d = e^{-1} mod lcm(p-1,q-1) */
mpi_invm (d, e, f);
/* Compute the inverse of p and q. */
u = f; f = NULL;
mpi_invm (u, p, q );
if( DBG_CIPHER )
{
if (*swapped)
log_debug ("p and q are swapped\n");
log_mpidump(" p", p );
log_mpidump(" q", q );
log_mpidump(" n", n );
log_mpidump(" e", e );
log_mpidump(" d", d );
log_mpidump(" u", u );
}
sk->n = n;
sk->e = e;
sk->p = p;
sk->q = q;
sk->d = d;
sk->u = u;
/* Now we can test our keys. */
if (test_keys (sk, nbits - 64))
{
gcry_mpi_release (sk->n); sk->n = NULL;
gcry_mpi_release (sk->e); sk->e = NULL;
gcry_mpi_release (sk->p); sk->p = NULL;
gcry_mpi_release (sk->q); sk->q = NULL;
gcry_mpi_release (sk->d); sk->d = NULL;
gcry_mpi_release (sk->u); sk->u = NULL;
fips_signal_error ("self-test after key generation failed");
return GPG_ERR_SELFTEST_FAILED;
}
return 0;
}
/****************
* Test whether the secret key is valid.
* Returns: true if this is a valid key.
*/
static int
check_secret_key( RSA_secret_key *sk )
{
int rc;
gcry_mpi_t temp = mpi_alloc( mpi_get_nlimbs(sk->p)*2 );
mpi_mul(temp, sk->p, sk->q );
rc = mpi_cmp( temp, sk->n );
mpi_free(temp);
return !rc;
}
/****************
* Public key operation. Encrypt INPUT with PKEY and put result into OUTPUT.
*
* c = m^e mod n
*
* Where c is OUTPUT, m is INPUT and e,n are elements of PKEY.
*/
static void
public(gcry_mpi_t output, gcry_mpi_t input, RSA_public_key *pkey )
{
if( output == input ) /* powm doesn't like output and input the same */
{
gcry_mpi_t x = mpi_alloc( mpi_get_nlimbs(input)*2 );
mpi_powm( x, input, pkey->e, pkey->n );
mpi_set(output, x);
mpi_free(x);
}
else
mpi_powm( output, input, pkey->e, pkey->n );
}
#if 0
static void
stronger_key_check ( RSA_secret_key *skey )
{
gcry_mpi_t t = mpi_alloc_secure ( 0 );
gcry_mpi_t t1 = mpi_alloc_secure ( 0 );
gcry_mpi_t t2 = mpi_alloc_secure ( 0 );
gcry_mpi_t phi = mpi_alloc_secure ( 0 );
/* check that n == p * q */
mpi_mul( t, skey->p, skey->q);
if (mpi_cmp( t, skey->n) )
log_info ( "RSA Oops: n != p * q\n" );
/* check that p is less than q */
if( mpi_cmp( skey->p, skey->q ) > 0 )
{
log_info ("RSA Oops: p >= q - fixed\n");
_gcry_mpi_swap ( skey->p, skey->q);
}
/* check that e divides neither p-1 nor q-1 */
mpi_sub_ui(t, skey->p, 1 );
mpi_fdiv_r(t, t, skey->e );
if ( !mpi_cmp_ui( t, 0) )
log_info ( "RSA Oops: e divides p-1\n" );
mpi_sub_ui(t, skey->q, 1 );
mpi_fdiv_r(t, t, skey->e );
if ( !mpi_cmp_ui( t, 0) )
log_info ( "RSA Oops: e divides q-1\n" );
/* check that d is correct */
mpi_sub_ui( t1, skey->p, 1 );
mpi_sub_ui( t2, skey->q, 1 );
mpi_mul( phi, t1, t2 );
gcry_mpi_gcd(t, t1, t2);
mpi_fdiv_q(t, phi, t);
mpi_invm(t, skey->e, t );
if ( mpi_cmp(t, skey->d ) )
{
log_info ( "RSA Oops: d is wrong - fixed\n");
mpi_set (skey->d, t);
_gcry_log_mpidump (" fixed d", skey->d);
}
/* check for correctness of u */
mpi_invm(t, skey->p, skey->q );
if ( mpi_cmp(t, skey->u ) )
{
log_info ( "RSA Oops: u is wrong - fixed\n");
mpi_set (skey->u, t);
_gcry_log_mpidump (" fixed u", skey->u);
}
log_info ( "RSA secret key check finished\n");
mpi_free (t);
mpi_free (t1);
mpi_free (t2);
mpi_free (phi);
}
#endif
/****************
* Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT.
*
* m = c^d mod n
*
* Or faster:
*
* m1 = c ^ (d mod (p-1)) mod p
* m2 = c ^ (d mod (q-1)) mod q
* h = u * (m2 - m1) mod q
* m = m1 + h * p
*
* Where m is OUTPUT, c is INPUT and d,n,p,q,u are elements of SKEY.
*/
static void
-secret(gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey )
+secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey )
{
if (!skey->p || !skey->q || !skey->u)
{
mpi_powm (output, input, skey->d, skey->n);
}
else
{
gcry_mpi_t m1 = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 );
gcry_mpi_t m2 = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 );
gcry_mpi_t h = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 );
/* m1 = c ^ (d mod (p-1)) mod p */
mpi_sub_ui( h, skey->p, 1 );
mpi_fdiv_r( h, skey->d, h );
mpi_powm( m1, input, h, skey->p );
/* m2 = c ^ (d mod (q-1)) mod q */
mpi_sub_ui( h, skey->q, 1 );
mpi_fdiv_r( h, skey->d, h );
mpi_powm( m2, input, h, skey->q );
/* h = u * ( m2 - m1 ) mod q */
mpi_sub( h, m2, m1 );
if ( mpi_is_neg( h ) )
mpi_add ( h, h, skey->q );
mpi_mulm( h, skey->u, h, skey->q );
/* m = m2 + h * p */
mpi_mul ( h, h, skey->p );
mpi_add ( output, m1, h );
mpi_free ( h );
mpi_free ( m1 );
mpi_free ( m2 );
}
}
/* Perform RSA blinding. */
static gcry_mpi_t
rsa_blind (gcry_mpi_t x, gcry_mpi_t r, gcry_mpi_t e, gcry_mpi_t n)
{
/* A helper. */
gcry_mpi_t a;
/* Result. */
gcry_mpi_t y;
a = gcry_mpi_snew (gcry_mpi_get_nbits (n));
y = gcry_mpi_snew (gcry_mpi_get_nbits (n));
/* Now we calculate: y = (x * r^e) mod n, where r is the random
number, e is the public exponent, x is the non-blinded data and n
is the RSA modulus. */
gcry_mpi_powm (a, r, e, n);
gcry_mpi_mulm (y, a, x, n);
gcry_mpi_release (a);
return y;
}
/* Undo RSA blinding. */
static gcry_mpi_t
rsa_unblind (gcry_mpi_t x, gcry_mpi_t ri, gcry_mpi_t n)
{
gcry_mpi_t y;
y = gcry_mpi_snew (gcry_mpi_get_nbits (n));
/* Here we calculate: y = (x * r^-1) mod n, where x is the blinded
decrypted data, ri is the modular multiplicative inverse of r and
n is the RSA modulus. */
gcry_mpi_mulm (y, ri, x, n);
return y;
}
/*********************************************
************** interface ******************
*********************************************/
static gcry_err_code_t
rsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
const gcry_sexp_t genparms,
gcry_mpi_t *skey, gcry_mpi_t **retfactors,
gcry_sexp_t *r_extrainfo)
{
RSA_secret_key sk;
gpg_err_code_t ec;
gcry_sexp_t deriveparms;
int transient_key = 0;
int use_x931 = 0;
gcry_sexp_t l1;
(void)algo;
*retfactors = NULL; /* We don't return them. */
deriveparms = (genparms?
gcry_sexp_find_token (genparms, "derive-parms", 0) : NULL);
if (!deriveparms)
{
/* Parse the optional "use-x931" flag. */
l1 = gcry_sexp_find_token (genparms, "use-x931", 0);
if (l1)
{
use_x931 = 1;
gcry_sexp_release (l1);
}
}
if (deriveparms || use_x931 || fips_mode ())
{
int swapped;
ec = generate_x931 (&sk, nbits, evalue, deriveparms, &swapped);
gcry_sexp_release (deriveparms);
if (!ec && r_extrainfo && swapped)
{
ec = gcry_sexp_new (r_extrainfo,
"(misc-key-info(p-q-swapped))", 0, 1);
if (ec)
{
gcry_mpi_release (sk.n); sk.n = NULL;
gcry_mpi_release (sk.e); sk.e = NULL;
gcry_mpi_release (sk.p); sk.p = NULL;
gcry_mpi_release (sk.q); sk.q = NULL;
gcry_mpi_release (sk.d); sk.d = NULL;
gcry_mpi_release (sk.u); sk.u = NULL;
}
}
}
else
{
/* Parse the optional "transient-key" flag. */
l1 = gcry_sexp_find_token (genparms, "transient-key", 0);
if (l1)
{
transient_key = 1;
gcry_sexp_release (l1);
}
/* Generate. */
ec = generate_std (&sk, nbits, evalue, transient_key);
}
if (!ec)
{
skey[0] = sk.n;
skey[1] = sk.e;
skey[2] = sk.d;
skey[3] = sk.p;
skey[4] = sk.q;
skey[5] = sk.u;
}
return ec;
}
static gcry_err_code_t
rsa_generate (int algo, unsigned int nbits, unsigned long evalue,
gcry_mpi_t *skey, gcry_mpi_t **retfactors)
{
return rsa_generate_ext (algo, nbits, evalue, NULL, skey, retfactors, NULL);
}
static gcry_err_code_t
rsa_check_secret_key (int algo, gcry_mpi_t *skey)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
RSA_secret_key sk;
(void)algo;
sk.n = skey[0];
sk.e = skey[1];
sk.d = skey[2];
sk.p = skey[3];
sk.q = skey[4];
sk.u = skey[5];
if (!sk.p || !sk.q || !sk.u)
err = GPG_ERR_NO_OBJ; /* To check the key we need the optional
parameters. */
else if (!check_secret_key (&sk))
err = GPG_ERR_BAD_SECKEY;
return err;
}
static gcry_err_code_t
rsa_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
gcry_mpi_t *pkey, int flags)
{
RSA_public_key pk;
(void)algo;
(void)flags;
pk.n = pkey[0];
pk.e = pkey[1];
resarr[0] = mpi_alloc (mpi_get_nlimbs (pk.n));
public (resarr[0], data, &pk);
return GPG_ERR_NO_ERROR;
}
static gcry_err_code_t
rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
gcry_mpi_t *skey, int flags)
{
RSA_secret_key sk;
gcry_mpi_t r = MPI_NULL; /* Random number needed for blinding. */
gcry_mpi_t ri = MPI_NULL; /* Modular multiplicative inverse of
r. */
gcry_mpi_t x = MPI_NULL; /* Data to decrypt. */
gcry_mpi_t y; /* Result. */
(void)algo;
/* Extract private key. */
sk.n = skey[0];
sk.e = skey[1];
sk.d = skey[2];
sk.p = skey[3]; /* Optional. */
sk.q = skey[4]; /* Optional. */
sk.u = skey[5]; /* Optional. */
y = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n));
/* We use blinding by default to mitigate timing attacks which can
be practically mounted over the network as shown by Brumley and
Boney in 2003. */
if (! (flags & PUBKEY_FLAG_NO_BLINDING))
{
/* Initialize blinding. */
/* First, we need a random number r between 0 and n - 1, which
is relatively prime to n (i.e. it is neither p nor q). The
random number needs to be only unpredictable, thus we employ
the gcry_create_nonce function by using GCRY_WEAK_RANDOM with
gcry_mpi_randomize. */
r = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n));
ri = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n));
gcry_mpi_randomize (r, gcry_mpi_get_nbits (sk.n), GCRY_WEAK_RANDOM);
gcry_mpi_mod (r, r, sk.n);
/* Calculate inverse of r. It practically impossible that the
following test fails, thus we do not add code to release
allocated resources. */
if (!gcry_mpi_invm (ri, r, sk.n))
return GPG_ERR_INTERNAL;
}
if (! (flags & PUBKEY_FLAG_NO_BLINDING))
x = rsa_blind (data[0], r, sk.e, sk.n);
else
x = data[0];
/* Do the encryption. */
secret (y, x, &sk);
if (! (flags & PUBKEY_FLAG_NO_BLINDING))
{
/* Undo blinding. */
gcry_mpi_t a = gcry_mpi_copy (y);
gcry_mpi_release (y);
y = rsa_unblind (a, ri, sk.n);
gcry_mpi_release (a);
}
if (! (flags & PUBKEY_FLAG_NO_BLINDING))
{
/* Deallocate resources needed for blinding. */
gcry_mpi_release (x);
gcry_mpi_release (r);
gcry_mpi_release (ri);
}
/* Copy out result. */
*result = y;
return GPG_ERR_NO_ERROR;
}
static gcry_err_code_t
rsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
int flags, int hashalgo)
{
RSA_secret_key sk;
(void)algo;
(void)flags;
(void)hashalgo;
+ if (mpi_is_opaque (data))
+ return GPG_ERR_INV_DATA;
+
sk.n = skey[0];
sk.e = skey[1];
sk.d = skey[2];
sk.p = skey[3];
sk.q = skey[4];
sk.u = skey[5];
resarr[0] = mpi_alloc( mpi_get_nlimbs (sk.n));
secret (resarr[0], data, &sk);
return GPG_ERR_NO_ERROR;
}
static gcry_err_code_t
rsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
int (*cmp) (void *opaque, gcry_mpi_t tmp),
void *opaquev)
{
RSA_public_key pk;
gcry_mpi_t result;
gcry_err_code_t rc;
(void)algo;
(void)cmp;
(void)opaquev;
+ if (mpi_is_opaque (hash))
+ return GPG_ERR_INV_DATA;
+
pk.n = pkey[0];
pk.e = pkey[1];
result = gcry_mpi_new ( 160 );
public( result, data[0], &pk );
#ifdef IS_DEVELOPMENT_VERSION
if (DBG_CIPHER)
{
log_mpidump ("rsa verify result:", result );
log_mpidump (" hash:", hash );
}
#endif /*IS_DEVELOPMENT_VERSION*/
if (cmp)
rc = (*cmp) (opaquev, result);
else
rc = mpi_cmp (result, hash) ? GPG_ERR_BAD_SIGNATURE : GPG_ERR_NO_ERROR;
gcry_mpi_release (result);
return rc;
}
static unsigned int
rsa_get_nbits (int algo, gcry_mpi_t *pkey)
{
(void)algo;
return mpi_get_nbits (pkey[0]);
}
/* Compute a keygrip. MD is the hash context which we are going to
update. KEYPARAM is an S-expression with the key parameters, this
is usually a public key but may also be a secret key. An example
of such an S-expression is:
(rsa
(n #00B...#)
(e #010001#))
PKCS-15 says that for RSA only the modulus should be hashed -
however, it is not clear whether this is meant to use the raw bytes
(assuming this is an unsigned integer) or whether the DER required
0 should be prefixed. We hash the raw bytes. */
static gpg_err_code_t
compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
{
gcry_sexp_t l1;
const char *data;
size_t datalen;
l1 = gcry_sexp_find_token (keyparam, "n", 1);
if (!l1)
return GPG_ERR_NO_OBJ;
data = gcry_sexp_nth_data (l1, 1, &datalen);
if (!data)
{
gcry_sexp_release (l1);
return GPG_ERR_NO_OBJ;
}
gcry_md_write (md, data, datalen);
gcry_sexp_release (l1);
return 0;
}
/*
Self-test section.
*/
static const char *
selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey)
{
static const char sample_data[] =
"(data (flags pkcs1)"
" (hash sha1 #11223344556677889900aabbccddeeff10203040#))";
static const char sample_data_bad[] =
"(data (flags pkcs1)"
" (hash sha1 #11223344556677889900aabbccddeeff80203040#))";
const char *errtxt = NULL;
gcry_error_t err;
gcry_sexp_t data = NULL;
gcry_sexp_t data_bad = NULL;
gcry_sexp_t sig = NULL;
err = gcry_sexp_sscan (&data, NULL,
sample_data, strlen (sample_data));
if (!err)
err = gcry_sexp_sscan (&data_bad, NULL,
sample_data_bad, strlen (sample_data_bad));
if (err)
{
errtxt = "converting data failed";
goto leave;
}
err = gcry_pk_sign (&sig, data, skey);
if (err)
{
errtxt = "signing failed";
goto leave;
}
err = gcry_pk_verify (sig, data, pkey);
if (err)
{
errtxt = "verify failed";
goto leave;
}
err = gcry_pk_verify (sig, data_bad, pkey);
if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE)
{
errtxt = "bad signature not detected";
goto leave;
}
leave:
gcry_sexp_release (sig);
gcry_sexp_release (data_bad);
gcry_sexp_release (data);
return errtxt;
}
/* Given an S-expression ENCR_DATA of the form:
(enc-val
(rsa
(a a-value)))
as returned by gcry_pk_decrypt, return the the A-VALUE. On error,
return NULL. */
static gcry_mpi_t
extract_a_from_sexp (gcry_sexp_t encr_data)
{
gcry_sexp_t l1, l2, l3;
gcry_mpi_t a_value;
l1 = gcry_sexp_find_token (encr_data, "enc-val", 0);
if (!l1)
return NULL;
l2 = gcry_sexp_find_token (l1, "rsa", 0);
gcry_sexp_release (l1);
if (!l2)
return NULL;
l3 = gcry_sexp_find_token (l2, "a", 0);
gcry_sexp_release (l2);
if (!l3)
return NULL;
a_value = gcry_sexp_nth_mpi (l3, 1, 0);
gcry_sexp_release (l3);
return a_value;
}
static const char *
selftest_encr_1024 (gcry_sexp_t pkey, gcry_sexp_t skey)
{
const char *errtxt = NULL;
gcry_error_t err;
const unsigned int nbits = 1000; /* Encrypt 1000 random bits. */
gcry_mpi_t plaintext = NULL;
gcry_sexp_t plain = NULL;
gcry_sexp_t encr = NULL;
gcry_mpi_t ciphertext = NULL;
gcry_sexp_t decr = NULL;
gcry_mpi_t decr_plaintext = NULL;
gcry_sexp_t tmplist = NULL;
/* Create plaintext. The plaintext is actually a big integer number. */
plaintext = gcry_mpi_new (nbits);
gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM);
/* Put the plaintext into an S-expression. */
err = gcry_sexp_build (&plain, NULL,
"(data (flags raw) (value %m))", plaintext);
if (err)
{
errtxt = "converting data failed";
goto leave;
}
/* Encrypt. */
err = gcry_pk_encrypt (&encr, plain, pkey);
if (err)
{
errtxt = "encrypt failed";
goto leave;
}
/* Extraxt the ciphertext from the returned S-expression. */
/*gcry_sexp_dump (encr);*/
ciphertext = extract_a_from_sexp (encr);
if (!ciphertext)
{
errtxt = "gcry_pk_decrypt returned garbage";
goto leave;
}
/* Check that the ciphertext does no match the plaintext. */
/* _gcry_log_mpidump ("plaintext", plaintext); */
/* _gcry_log_mpidump ("ciphertxt", ciphertext); */
if (!gcry_mpi_cmp (plaintext, ciphertext))
{
errtxt = "ciphertext matches plaintext";
goto leave;
}
/* Decrypt. */
err = gcry_pk_decrypt (&decr, encr, skey);
if (err)
{
errtxt = "decrypt failed";
goto leave;
}
/* Extract the decrypted data from the S-expression. Note that the
output of gcry_pk_decrypt depends on whether a flags lists occurs
in its input data. Because we passed the output of
gcry_pk_encrypt directly to gcry_pk_decrypt, such a flag value
won't be there as of today. To be prepared for future changes we
take care of it anyway. */
tmplist = gcry_sexp_find_token (decr, "value", 0);
if (tmplist)
decr_plaintext = gcry_sexp_nth_mpi (tmplist, 1, GCRYMPI_FMT_USG);
else
decr_plaintext = gcry_sexp_nth_mpi (decr, 0, GCRYMPI_FMT_USG);
if (!decr_plaintext)
{
errtxt = "decrypt returned no plaintext";
goto leave;
}
/* Check that the decrypted plaintext matches the original plaintext. */
if (gcry_mpi_cmp (plaintext, decr_plaintext))
{
errtxt = "mismatch";
goto leave;
}
leave:
gcry_sexp_release (tmplist);
gcry_mpi_release (decr_plaintext);
gcry_sexp_release (decr);
gcry_mpi_release (ciphertext);
gcry_sexp_release (encr);
gcry_sexp_release (plain);
gcry_mpi_release (plaintext);
return errtxt;
}
static gpg_err_code_t
selftests_rsa (selftest_report_func_t report)
{
const char *what;
const char *errtxt;
gcry_error_t err;
gcry_sexp_t skey = NULL;
gcry_sexp_t pkey = NULL;
/* Convert the S-expressions into the internal representation. */
what = "convert";
err = gcry_sexp_sscan (&skey, NULL,
sample_secret_key, strlen (sample_secret_key));
if (!err)
err = gcry_sexp_sscan (&pkey, NULL,
sample_public_key, strlen (sample_public_key));
if (err)
{
errtxt = gcry_strerror (err);
goto failed;
}
what = "key consistency";
err = gcry_pk_testkey (skey);
if (err)
{
errtxt = gcry_strerror (err);
goto failed;
}
what = "sign";
errtxt = selftest_sign_1024 (pkey, skey);
if (errtxt)
goto failed;
what = "encrypt";
errtxt = selftest_encr_1024 (pkey, skey);
if (errtxt)
goto failed;
gcry_sexp_release (pkey);
gcry_sexp_release (skey);
return 0; /* Succeeded. */
failed:
gcry_sexp_release (pkey);
gcry_sexp_release (skey);
if (report)
report ("pubkey", GCRY_PK_RSA, what, errtxt);
return GPG_ERR_SELFTEST_FAILED;
}
/* Run a full self-test for ALGO and return 0 on success. */
static gpg_err_code_t
run_selftests (int algo, int extended, selftest_report_func_t report)
{
gpg_err_code_t ec;
(void)extended;
switch (algo)
{
case GCRY_PK_RSA:
ec = selftests_rsa (report);
break;
default:
ec = GPG_ERR_PUBKEY_ALGO;
break;
}
return ec;
}
static const char *rsa_names[] =
{
"rsa",
"openpgp-rsa",
"oid.1.2.840.113549.1.1.1",
NULL,
};
gcry_pk_spec_t _gcry_pubkey_spec_rsa =
{
"RSA", rsa_names,
"ne", "nedpqu", "a", "s", "n",
GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR,
rsa_generate,
rsa_check_secret_key,
rsa_encrypt,
rsa_decrypt,
rsa_sign,
rsa_verify,
rsa_get_nbits,
};
pk_extra_spec_t _gcry_pubkey_extraspec_rsa =
{
run_selftests,
rsa_generate_ext,
compute_keygrip
};
diff --git a/tests/basic.c b/tests/basic.c
index 88ae1316..46e213cb 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -1,3845 +1,3855 @@
/* basic.c - basic regression tests
* Copyright (C) 2001, 2002, 2003, 2005, 2008,
* 2009 Free Software Foundation, Inc.
* Copyright (C) 2013 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include "../src/gcrypt-int.h"
#ifndef DIM
# define DIM(v) (sizeof(v)/sizeof((v)[0]))
#endif
typedef struct test_spec_pubkey_key
{
const char *secret;
const char *public;
const char *grip;
}
test_spec_pubkey_key_t;
typedef struct test_spec_pubkey
{
int id;
int flags;
test_spec_pubkey_key_t key;
}
test_spec_pubkey_t;
#define FLAG_CRYPT (1 << 0)
#define FLAG_SIGN (1 << 1)
#define FLAG_GRIP (1 << 2)
static int verbose;
static int error_count;
static int in_fips_mode;
static int die_on_error;
static void
fail (const char *format, ...)
{
va_list arg_ptr;
va_start (arg_ptr, format);
vfprintf (stderr, format, arg_ptr);
va_end (arg_ptr);
error_count++;
if (die_on_error)
exit (1);
}
static void
mismatch (const void *expected, size_t expectedlen,
const void *computed, size_t computedlen)
{
const unsigned char *p;
fprintf (stderr, "expected:");
for (p = expected; expectedlen; p++, expectedlen--)
fprintf (stderr, " %02x", *p);
fprintf (stderr, "\ncomputed:");
for (p = computed; computedlen; p++, computedlen--)
fprintf (stderr, " %02x", *p);
fprintf (stderr, "\n");
}
static void
die (const char *format, ...)
{
va_list arg_ptr;
va_start (arg_ptr, format);
vfprintf (stderr, format, arg_ptr);
va_end (arg_ptr);
exit (1);
}
static void
show_sexp (const char *prefix, gcry_sexp_t a)
{
char *buf;
size_t size;
if (prefix)
fputs (prefix, stderr);
size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
buf = gcry_xmalloc (size);
gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size);
fprintf (stderr, "%.*s", (int)size, buf);
gcry_free (buf);
}
#define MAX_DATA_LEN 100
void
progress_handler (void *cb_data, const char *what, int printchar,
int current, int total)
{
(void)cb_data;
(void)what;
(void)current;
(void)total;
if (printchar == '\n')
fputs ( "<LF>", stdout);
else
putchar (printchar);
fflush (stdout);
}
static void
check_cbc_mac_cipher (void)
{
struct tv
{
int algo;
char key[MAX_DATA_LEN];
unsigned char plaintext[MAX_DATA_LEN];
size_t plaintextlen;
char mac[MAX_DATA_LEN];
}
tv[] =
{
{ GCRY_CIPHER_AES,
"chicken teriyaki",
"This is a sample plaintext for CBC MAC of sixtyfour bytes.......",
0, "\x23\x8f\x6d\xc7\x53\x6a\x62\x97\x11\xc4\xa5\x16\x43\xea\xb0\xb6" },
{ GCRY_CIPHER_3DES,
"abcdefghABCDEFGH01234567",
"This is a sample plaintext for CBC MAC of sixtyfour bytes.......",
0, "\x5c\x11\xf0\x01\x47\xbd\x3d\x3a" },
{ GCRY_CIPHER_DES,
"abcdefgh",
"This is a sample plaintext for CBC MAC of sixtyfour bytes.......",
0, "\xfa\x4b\xdf\x9d\xfa\xab\x01\x70" }
};
gcry_cipher_hd_t hd;
unsigned char out[MAX_DATA_LEN];
int i, blklen, keylen;
gcry_error_t err = 0;
if (verbose)
fprintf (stderr, " Starting CBC MAC checks.\n");
for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
{
if (gcry_cipher_test_algo (tv[i].algo) && in_fips_mode)
{
if (verbose)
fprintf (stderr, " algorithm %d not available in fips mode\n",
tv[i].algo);
continue;
}
err = gcry_cipher_open (&hd,
tv[i].algo,
GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_MAC);
if (!hd)
{
fail ("cbc-mac algo %d, gcry_cipher_open failed: %s\n",
tv[i].algo, gpg_strerror (err));
return;
}
blklen = gcry_cipher_get_algo_blklen(tv[i].algo);
if (!blklen)
{
fail ("cbc-mac algo %d, gcry_cipher_get_algo_blklen failed\n",
tv[i].algo);
gcry_cipher_close (hd);
return;
}
keylen = gcry_cipher_get_algo_keylen (tv[i].algo);
if (!keylen)
{
fail ("cbc-mac algo %d, gcry_cipher_get_algo_keylen failed\n",
tv[i].algo);
return;
}
err = gcry_cipher_setkey (hd, tv[i].key, keylen);
if (err)
{
fail ("cbc-mac algo %d, gcry_cipher_setkey failed: %s\n",
tv[i].algo, gpg_strerror (err));
gcry_cipher_close (hd);
return;
}
err = gcry_cipher_setiv (hd, NULL, 0);
if (err)
{
fail ("cbc-mac algo %d, gcry_cipher_setiv failed: %s\n",
tv[i].algo, gpg_strerror (err));
gcry_cipher_close (hd);
return;
}
if (verbose)
fprintf (stderr, " checking CBC MAC for %s [%i]\n",
gcry_cipher_algo_name (tv[i].algo),
tv[i].algo);
err = gcry_cipher_encrypt (hd,
out, blklen,
tv[i].plaintext,
tv[i].plaintextlen ?
tv[i].plaintextlen :
strlen ((char*)tv[i].plaintext));
if (err)
{
fail ("cbc-mac algo %d, gcry_cipher_encrypt failed: %s\n",
tv[i].algo, gpg_strerror (err));
gcry_cipher_close (hd);
return;
}
#if 0
{
int j;
for (j = 0; j < gcry_cipher_get_algo_blklen (tv[i].algo); j++)
printf ("\\x%02x", out[j] & 0xFF);
printf ("\n");
}
#endif
if (memcmp (tv[i].mac, out, blklen))
fail ("cbc-mac algo %d, encrypt mismatch entry %d\n", tv[i].algo, i);
gcry_cipher_close (hd);
}
if (verbose)
fprintf (stderr, " Completed CBC MAC checks.\n");
}
static void
check_aes128_cbc_cts_cipher (void)
{
char key[128 / 8] = "chicken teriyaki";
unsigned char plaintext[] =
"I would like the General Gau's Chicken, please, and wonton soup.";
struct tv
{
unsigned char out[MAX_DATA_LEN];
int inlen;
} tv[] =
{
{ "\xc6\x35\x35\x68\xf2\xbf\x8c\xb4\xd8\xa5\x80\x36\x2d\xa7\xff\x7f"
"\x97",
17 },
{ "\xfc\x00\x78\x3e\x0e\xfd\xb2\xc1\xd4\x45\xd4\xc8\xef\xf7\xed\x22"
"\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5",
31 },
{ "\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
"\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84",
32 },
{ "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
"\xb3\xff\xfd\x94\x0c\x16\xa1\x8c\x1b\x55\x49\xd2\xf8\x38\x02\x9e"
"\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5",
47 },
{ "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
"\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8"
"\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8",
48 },
{ "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
"\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
"\x48\x07\xef\xe8\x36\xee\x89\xa5\x26\x73\x0d\xbc\x2f\x7b\xc8\x40"
"\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8",
64 },
};
gcry_cipher_hd_t hd;
unsigned char out[MAX_DATA_LEN];
int i;
gcry_error_t err = 0;
if (verbose)
fprintf (stderr, " Starting AES128 CBC CTS checks.\n");
err = gcry_cipher_open (&hd,
GCRY_CIPHER_AES,
GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_CTS);
if (err)
{
fail ("aes-cbc-cts, gcry_cipher_open failed: %s\n", gpg_strerror (err));
return;
}
err = gcry_cipher_setkey (hd, key, 128 / 8);
if (err)
{
fail ("aes-cbc-cts, gcry_cipher_setkey failed: %s\n",
gpg_strerror (err));
gcry_cipher_close (hd);
return;
}
for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
{
err = gcry_cipher_setiv (hd, NULL, 0);
if (err)
{
fail ("aes-cbc-cts, gcry_cipher_setiv failed: %s\n",
gpg_strerror (err));
gcry_cipher_close (hd);
return;
}
if (verbose)
fprintf (stderr, " checking encryption for length %i\n", tv[i].inlen);
err = gcry_cipher_encrypt (hd, out, MAX_DATA_LEN,
plaintext, tv[i].inlen);
if (err)
{
fail ("aes-cbc-cts, gcry_cipher_encrypt failed: %s\n",
gpg_strerror (err));
gcry_cipher_close (hd);
return;
}
if (memcmp (tv[i].out, out, tv[i].inlen))
fail ("aes-cbc-cts, encrypt mismatch entry %d\n", i);
err = gcry_cipher_setiv (hd, NULL, 0);
if (err)
{
fail ("aes-cbc-cts, gcry_cipher_setiv failed: %s\n",
gpg_strerror (err));
gcry_cipher_close (hd);
return;
}
if (verbose)
fprintf (stderr, " checking decryption for length %i\n", tv[i].inlen);
err = gcry_cipher_decrypt (hd, out, tv[i].inlen, NULL, 0);
if (err)
{
fail ("aes-cbc-cts, gcry_cipher_decrypt failed: %s\n",
gpg_strerror (err));
gcry_cipher_close (hd);
return;
}
if (memcmp (plaintext, out, tv[i].inlen))
fail ("aes-cbc-cts, decrypt mismatch entry %d\n", i);
}
gcry_cipher_close (hd);
if (verbose)
fprintf (stderr, " Completed AES128 CBC CTS checks.\n");
}
static void
check_ctr_cipher (void)
{
struct tv
{
int algo;
char key[MAX_DATA_LEN];
char ctr[MAX_DATA_LEN];
struct data
{
unsigned char plaintext[MAX_DATA_LEN];
int inlen;
char out[MAX_DATA_LEN];
} data[8];
} tv[] =
{
/* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf */
{ GCRY_CIPHER_AES,
"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
{ { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\x87\x4d\x61\x91\xb6\x20\xe3\x26\x1b\xef\x68\x64\x99\x0d\xb6\xce" },
{ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
16,
"\x98\x06\xf6\x6b\x79\x70\xfd\xff\x86\x17\x18\x7b\xb9\xff\xfd\xff" },
{ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
16,
"\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e\x5b\x4f\x09\x02\x0d\xb0\x3e\xab" },
{ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
"\x1e\x03\x1d\xda\x2f\xbe\x03\xd1\x79\x21\x70\xa0\xf3\x00\x9c\xee" },
{ "", 0, "" }
}
},
{ GCRY_CIPHER_AES192,
"\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b"
"\x80\x90\x79\xe5\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
{ { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\x1a\xbc\x93\x24\x17\x52\x1c\xa2\x4f\x2b\x04\x59\xfe\x7e\x6e\x0b" },
{ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
16,
"\x09\x03\x39\xec\x0a\xa6\xfa\xef\xd5\xcc\xc2\xc6\xf4\xce\x8e\x94" },
{ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
16,
"\x1e\x36\xb2\x6b\xd1\xeb\xc6\x70\xd1\xbd\x1d\x66\x56\x20\xab\xf7" },
{ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
"\x4f\x78\xa7\xf6\xd2\x98\x09\x58\x5a\x97\xda\xec\x58\xc6\xb0\x50" },
{ "", 0, "" }
}
},
{ GCRY_CIPHER_AES256,
"\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
"\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
{ { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\x60\x1e\xc3\x13\x77\x57\x89\xa5\xb7\xa7\xf5\x04\xbb\xf3\xd2\x28" },
{ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
16,
"\xf4\x43\xe3\xca\x4d\x62\xb5\x9a\xca\x84\xe9\x90\xca\xca\xf5\xc5" },
{ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
16,
"\x2b\x09\x30\xda\xa2\x3d\xe9\x4c\xe8\x70\x17\xba\x2d\x84\x98\x8d" },
{ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
"\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6\x13\xc2\xdd\x08\x45\x79\x41\xa6" },
{ "", 0, "" }
}
},
/* Some truncation tests. With a truncated second block and
also with a single truncated block. */
{ GCRY_CIPHER_AES,
"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
{{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\x87\x4d\x61\x91\xb6\x20\xe3\x26\x1b\xef\x68\x64\x99\x0d\xb6\xce" },
{"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e",
15,
"\x98\x06\xf6\x6b\x79\x70\xfd\xff\x86\x17\x18\x7b\xb9\xff\xfd" },
{"", 0, "" }
}
},
{ GCRY_CIPHER_AES,
"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
{{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\x87\x4d\x61\x91\xb6\x20\xe3\x26\x1b\xef\x68\x64\x99\x0d\xb6\xce" },
{"\xae",
1,
"\x98" },
{"", 0, "" }
}
},
{ GCRY_CIPHER_AES,
"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
{{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17",
15,
"\x87\x4d\x61\x91\xb6\x20\xe3\x26\x1b\xef\x68\x64\x99\x0d\xb6" },
{"", 0, "" }
}
},
{ GCRY_CIPHER_AES,
"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
{{"\x6b",
1,
"\x87" },
{"", 0, "" }
}
},
/* Tests to see whether it works correctly as a stream cipher. */
{ GCRY_CIPHER_AES,
"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
{{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\x87\x4d\x61\x91\xb6\x20\xe3\x26\x1b\xef\x68\x64\x99\x0d\xb6\xce" },
{"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e",
15,
"\x98\x06\xf6\x6b\x79\x70\xfd\xff\x86\x17\x18\x7b\xb9\xff\xfd" },
{"\x51\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
17,
"\xff\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e\x5b\x4f\x09\x02\x0d\xb0\x3e\xab" },
{"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
"\x1e\x03\x1d\xda\x2f\xbe\x03\xd1\x79\x21\x70\xa0\xf3\x00\x9c\xee" },
{ "", 0, "" }
}
},
{ GCRY_CIPHER_AES,
"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
{{"\x6b",
1,
"\x87" },
{"\xc1\xbe",
2,
"\x4d\x61" },
{"\xe2\x2e\x40",
3,
"\x91\xb6\x20" },
{"\x9f",
1,
"\xe3" },
{"\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
9,
"\x26\x1b\xef\x68\x64\x99\x0d\xb6\xce" },
{"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e",
15,
"\x98\x06\xf6\x6b\x79\x70\xfd\xff\x86\x17\x18\x7b\xb9\xff\xfd" },
{"\x51\x30\xc8\x1c\x46\xa3\x5c\xe4\x11",
9,
"\xff\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e" },
{ "", 0, "" }
}
},
#if USE_CAST5
/* A selfmade test vector using an 64 bit block cipher. */
{ GCRY_CIPHER_CAST5,
"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8",
{{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\xe8\xa7\xac\x68\xca\xca\xa0\x20\x10\xcb\x1b\xcc\x79\x2c\xc4\x48" },
{"\xae\x2d\x8a\x57\x1e\x03\xac\x9c",
8,
"\x16\xe8\x72\x77\xb0\x98\x29\x68" },
{"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
8,
"\x9a\xb3\xa8\x03\x3b\xb4\x14\xba" },
{"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\xa1\x00",
10,
"\x31\x5e\xd3\xfb\x1b\x8d\xd1\xf9\xb0\x83" },
{ "", 0, "" }
}
},
#endif /*USE_CAST5*/
{ 0,
"",
"",
{
{"", 0, "" }
}
}
};
gcry_cipher_hd_t hde, hdd;
unsigned char out[MAX_DATA_LEN];
int i, j, keylen, blklen;
gcry_error_t err = 0;
if (verbose)
fprintf (stderr, " Starting CTR cipher checks.\n");
for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
{
if (!tv[i].algo)
continue;
err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_CTR, 0);
if (!err)
err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_CTR, 0);
if (err)
{
fail ("aes-ctr, gcry_cipher_open failed: %s\n", gpg_strerror (err));
return;
}
keylen = gcry_cipher_get_algo_keylen(tv[i].algo);
if (!keylen)
{
fail ("aes-ctr, gcry_cipher_get_algo_keylen failed\n");
return;
}
err = gcry_cipher_setkey (hde, tv[i].key, keylen);
if (!err)
err = gcry_cipher_setkey (hdd, tv[i].key, keylen);
if (err)
{
fail ("aes-ctr, gcry_cipher_setkey failed: %s\n",
gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
blklen = gcry_cipher_get_algo_blklen(tv[i].algo);
if (!blklen)
{
fail ("aes-ctr, gcry_cipher_get_algo_blklen failed\n");
return;
}
err = gcry_cipher_setctr (hde, tv[i].ctr, blklen);
if (!err)
err = gcry_cipher_setctr (hdd, tv[i].ctr, blklen);
if (err)
{
fail ("aes-ctr, gcry_cipher_setctr failed: %s\n",
gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
if (verbose)
fprintf (stderr, " checking CTR mode for %s [%i]\n",
gcry_cipher_algo_name (tv[i].algo),
tv[i].algo);
for (j = 0; tv[i].data[j].inlen; j++)
{
err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
tv[i].data[j].plaintext,
tv[i].data[j].inlen == -1 ?
strlen ((char*)tv[i].data[j].plaintext) :
tv[i].data[j].inlen);
if (err)
{
fail ("aes-ctr, gcry_cipher_encrypt (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen))
{
fail ("aes-ctr, encrypt mismatch entry %d:%d\n", i, j);
mismatch (tv[i].data[j].out, tv[i].data[j].inlen,
out, tv[i].data[j].inlen);
}
err = gcry_cipher_decrypt (hdd, out, tv[i].data[j].inlen, NULL, 0);
if (err)
{
fail ("aes-ctr, gcry_cipher_decrypt (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
{
fail ("aes-ctr, decrypt mismatch entry %d:%d\n", i, j);
mismatch (tv[i].data[j].plaintext, tv[i].data[j].inlen,
out, tv[i].data[j].inlen);
}
}
/* Now check that we get valid return codes back for good and
bad inputs. */
err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
"1234567890123456", 16);
if (err)
fail ("aes-ctr, encryption failed for valid input");
err = gcry_cipher_encrypt (hde, out, 15,
"1234567890123456", 16);
if (gpg_err_code (err) != GPG_ERR_BUFFER_TOO_SHORT)
fail ("aes-ctr, too short output buffer returned wrong error: %s\n",
gpg_strerror (err));
err = gcry_cipher_encrypt (hde, out, 0,
"1234567890123456", 16);
if (gpg_err_code (err) != GPG_ERR_BUFFER_TOO_SHORT)
fail ("aes-ctr, 0 length output buffer returned wrong error: %s\n",
gpg_strerror (err));
err = gcry_cipher_encrypt (hde, out, 16,
"1234567890123456", 16);
if (err)
fail ("aes-ctr, correct length output buffer returned error: %s\n",
gpg_strerror (err));
/* Again, now for decryption. */
err = gcry_cipher_decrypt (hde, out, MAX_DATA_LEN,
"1234567890123456", 16);
if (err)
fail ("aes-ctr, decryption failed for valid input");
err = gcry_cipher_decrypt (hde, out, 15,
"1234567890123456", 16);
if (gpg_err_code (err) != GPG_ERR_BUFFER_TOO_SHORT)
fail ("aes-ctr, too short output buffer returned wrong error: %s\n",
gpg_strerror (err));
err = gcry_cipher_decrypt (hde, out, 0,
"1234567890123456", 16);
if (gpg_err_code (err) != GPG_ERR_BUFFER_TOO_SHORT)
fail ("aes-ctr, 0 length output buffer returned wrong error: %s\n",
gpg_strerror (err));
err = gcry_cipher_decrypt (hde, out, 16,
"1234567890123456", 16);
if (err)
fail ("aes-ctr, correct length output buffer returned error: %s\n",
gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
}
if (verbose)
fprintf (stderr, " Completed CTR cipher checks.\n");
}
static void
check_cfb_cipher (void)
{
struct tv
{
int algo;
char key[MAX_DATA_LEN];
char iv[MAX_DATA_LEN];
struct data
{
unsigned char plaintext[MAX_DATA_LEN];
int inlen;
char out[MAX_DATA_LEN];
}
data[MAX_DATA_LEN];
} tv[] =
{
/* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf */
{ GCRY_CIPHER_AES,
"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
{ { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" },
{ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
16,
"\xc8\xa6\x45\x37\xa0\xb3\xa9\x3f\xcd\xe3\xcd\xad\x9f\x1c\xe5\x8b"},
{ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
16,
"\x26\x75\x1f\x67\xa3\xcb\xb1\x40\xb1\x80\x8c\xf1\x87\xa4\xf4\xdf" },
{ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
"\xc0\x4b\x05\x35\x7c\x5d\x1c\x0e\xea\xc4\xc6\x6f\x9f\xf7\xf2\xe6" },
}
},
{ GCRY_CIPHER_AES192,
"\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b"
"\x80\x90\x79\xe5\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
{ { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\xcd\xc8\x0d\x6f\xdd\xf1\x8c\xab\x34\xc2\x59\x09\xc9\x9a\x41\x74" },
{ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
16,
"\x67\xce\x7f\x7f\x81\x17\x36\x21\x96\x1a\x2b\x70\x17\x1d\x3d\x7a" },
{ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
16,
"\x2e\x1e\x8a\x1d\xd5\x9b\x88\xb1\xc8\xe6\x0f\xed\x1e\xfa\xc4\xc9" },
{ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
"\xc0\x5f\x9f\x9c\xa9\x83\x4f\xa0\x42\xae\x8f\xba\x58\x4b\x09\xff" },
}
},
{ GCRY_CIPHER_AES256,
"\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
"\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
{ { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\xdc\x7e\x84\xbf\xda\x79\x16\x4b\x7e\xcd\x84\x86\x98\x5d\x38\x60" },
{ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
16,
"\x39\xff\xed\x14\x3b\x28\xb1\xc8\x32\x11\x3c\x63\x31\xe5\x40\x7b" },
{ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
16,
"\xdf\x10\x13\x24\x15\xe5\x4b\x92\xa1\x3e\xd0\xa8\x26\x7a\xe2\xf9" },
{ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
"\x75\xa3\x85\x74\x1a\xb9\xce\xf8\x20\x31\x62\x3d\x55\xb1\xe4\x71" }
}
}
};
gcry_cipher_hd_t hde, hdd;
unsigned char out[MAX_DATA_LEN];
int i, j, keylen, blklen;
gcry_error_t err = 0;
if (verbose)
fprintf (stderr, " Starting CFB checks.\n");
for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
{
if (verbose)
fprintf (stderr, " checking CFB mode for %s [%i]\n",
gcry_cipher_algo_name (tv[i].algo),
tv[i].algo);
err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_CFB, 0);
if (!err)
err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_CFB, 0);
if (err)
{
fail ("aes-cfb, gcry_cipher_open failed: %s\n", gpg_strerror (err));
return;
}
keylen = gcry_cipher_get_algo_keylen(tv[i].algo);
if (!keylen)
{
fail ("aes-cfb, gcry_cipher_get_algo_keylen failed\n");
return;
}
err = gcry_cipher_setkey (hde, tv[i].key, keylen);
if (!err)
err = gcry_cipher_setkey (hdd, tv[i].key, keylen);
if (err)
{
fail ("aes-cfb, gcry_cipher_setkey failed: %s\n",
gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
blklen = gcry_cipher_get_algo_blklen(tv[i].algo);
if (!blklen)
{
fail ("aes-cfb, gcry_cipher_get_algo_blklen failed\n");
return;
}
err = gcry_cipher_setiv (hde, tv[i].iv, blklen);
if (!err)
err = gcry_cipher_setiv (hdd, tv[i].iv, blklen);
if (err)
{
fail ("aes-cfb, gcry_cipher_setiv failed: %s\n",
gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
for (j = 0; tv[i].data[j].inlen; j++)
{
err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
tv[i].data[j].plaintext,
tv[i].data[j].inlen);
if (err)
{
fail ("aes-cfb, gcry_cipher_encrypt (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen)) {
fail ("aes-cfb, encrypt mismatch entry %d:%d\n", i, j);
}
err = gcry_cipher_decrypt (hdd, out, tv[i].data[j].inlen, NULL, 0);
if (err)
{
fail ("aes-cfb, gcry_cipher_decrypt (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
fail ("aes-cfb, decrypt mismatch entry %d:%d\n", i, j);
}
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
}
if (verbose)
fprintf (stderr, " Completed CFB checks.\n");
}
static void
check_ofb_cipher (void)
{
struct tv
{
int algo;
char key[MAX_DATA_LEN];
char iv[MAX_DATA_LEN];
struct data
{
unsigned char plaintext[MAX_DATA_LEN];
int inlen;
char out[MAX_DATA_LEN];
}
data[MAX_DATA_LEN];
} tv[] =
{
/* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf */
{ GCRY_CIPHER_AES,
"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
{ { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" },
{ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
16,
"\x77\x89\x50\x8d\x16\x91\x8f\x03\xf5\x3c\x52\xda\xc5\x4e\xd8\x25"},
{ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
16,
"\x97\x40\x05\x1e\x9c\x5f\xec\xf6\x43\x44\xf7\xa8\x22\x60\xed\xcc" },
{ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
"\x30\x4c\x65\x28\xf6\x59\xc7\x78\x66\xa5\x10\xd9\xc1\xd6\xae\x5e" },
}
},
{ GCRY_CIPHER_AES192,
"\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b"
"\x80\x90\x79\xe5\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
{ { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\xcd\xc8\x0d\x6f\xdd\xf1\x8c\xab\x34\xc2\x59\x09\xc9\x9a\x41\x74" },
{ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
16,
"\xfc\xc2\x8b\x8d\x4c\x63\x83\x7c\x09\xe8\x17\x00\xc1\x10\x04\x01" },
{ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
16,
"\x8d\x9a\x9a\xea\xc0\xf6\x59\x6f\x55\x9c\x6d\x4d\xaf\x59\xa5\xf2" },
{ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
"\x6d\x9f\x20\x08\x57\xca\x6c\x3e\x9c\xac\x52\x4b\xd9\xac\xc9\x2a" },
}
},
{ GCRY_CIPHER_AES256,
"\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
"\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
{ { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
16,
"\xdc\x7e\x84\xbf\xda\x79\x16\x4b\x7e\xcd\x84\x86\x98\x5d\x38\x60" },
{ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
16,
"\x4f\xeb\xdc\x67\x40\xd2\x0b\x3a\xc8\x8f\x6a\xd8\x2a\x4f\xb0\x8d" },
{ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
16,
"\x71\xab\x47\xa0\x86\xe8\x6e\xed\xf3\x9d\x1c\x5b\xba\x97\xc4\x08" },
{ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
"\x01\x26\x14\x1d\x67\xf3\x7b\xe8\x53\x8f\x5a\x8b\xe7\x40\xe4\x84" }
}
}
};
gcry_cipher_hd_t hde, hdd;
unsigned char out[MAX_DATA_LEN];
int i, j, keylen, blklen;
gcry_error_t err = 0;
if (verbose)
fprintf (stderr, " Starting OFB checks.\n");
for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
{
if (verbose)
fprintf (stderr, " checking OFB mode for %s [%i]\n",
gcry_cipher_algo_name (tv[i].algo),
tv[i].algo);
err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_OFB, 0);
if (!err)
err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_OFB, 0);
if (err)
{
fail ("aes-ofb, gcry_cipher_open failed: %s\n", gpg_strerror (err));
return;
}
keylen = gcry_cipher_get_algo_keylen(tv[i].algo);
if (!keylen)
{
fail ("aes-ofb, gcry_cipher_get_algo_keylen failed\n");
return;
}
err = gcry_cipher_setkey (hde, tv[i].key, keylen);
if (!err)
err = gcry_cipher_setkey (hdd, tv[i].key, keylen);
if (err)
{
fail ("aes-ofb, gcry_cipher_setkey failed: %s\n",
gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
blklen = gcry_cipher_get_algo_blklen(tv[i].algo);
if (!blklen)
{
fail ("aes-ofb, gcry_cipher_get_algo_blklen failed\n");
return;
}
err = gcry_cipher_setiv (hde, tv[i].iv, blklen);
if (!err)
err = gcry_cipher_setiv (hdd, tv[i].iv, blklen);
if (err)
{
fail ("aes-ofb, gcry_cipher_setiv failed: %s\n",
gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
for (j = 0; tv[i].data[j].inlen; j++)
{
err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
tv[i].data[j].plaintext,
tv[i].data[j].inlen);
if (err)
{
fail ("aes-ofb, gcry_cipher_encrypt (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen))
fail ("aes-ofb, encrypt mismatch entry %d:%d\n", i, j);
err = gcry_cipher_decrypt (hdd, out, tv[i].data[j].inlen, NULL, 0);
if (err)
{
fail ("aes-ofb, gcry_cipher_decrypt (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
fail ("aes-ofb, decrypt mismatch entry %d:%d\n", i, j);
}
err = gcry_cipher_reset(hde);
if (!err)
err = gcry_cipher_reset(hdd);
if (err)
{
fail ("aes-ofb, gcry_cipher_reset (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
/* gcry_cipher_reset clears the IV */
err = gcry_cipher_setiv (hde, tv[i].iv, blklen);
if (!err)
err = gcry_cipher_setiv (hdd, tv[i].iv, blklen);
if (err)
{
fail ("aes-ofb, gcry_cipher_setiv failed: %s\n",
gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
/* this time we encrypt and decrypt one byte at a time */
for (j = 0; tv[i].data[j].inlen; j++)
{
int byteNum;
for (byteNum = 0; byteNum < tv[i].data[j].inlen; ++byteNum)
{
err = gcry_cipher_encrypt (hde, out+byteNum, 1,
(tv[i].data[j].plaintext) + byteNum,
1);
if (err)
{
fail ("aes-ofb, gcry_cipher_encrypt (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
}
if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen))
fail ("aes-ofb, encrypt mismatch entry %d:%d\n", i, j);
for (byteNum = 0; byteNum < tv[i].data[j].inlen; ++byteNum)
{
err = gcry_cipher_decrypt (hdd, out+byteNum, 1, NULL, 0);
if (err)
{
fail ("aes-ofb, gcry_cipher_decrypt (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
}
if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
fail ("aes-ofb, decrypt mismatch entry %d:%d\n", i, j);
}
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
}
if (verbose)
fprintf (stderr, " Completed OFB checks.\n");
}
static void
check_stream_cipher (void)
{
struct tv
{
const char *name;
int algo;
int keylen;
int ivlen;
const char *key;
const char *iv;
struct data
{
int inlen;
const char *plaintext;
const char *out;
} data[MAX_DATA_LEN];
} tv[] = {
#ifdef USE_SALSA20
{
"Salsa20 128 bit, test 1",
GCRY_CIPHER_SALSA20, 16, 8,
"\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
"\x00\x00\x00\x00\x00\x00\x00\x00",
{
{ 8,
"\x00\x00\x00\x00\x00\x00\x00\x00",
"\x4D\xFA\x5E\x48\x1D\xA2\x3E\xA0"
}
}
},
{
"Salsa20 128 bit, test 2",
GCRY_CIPHER_SALSA20, 16, 8,
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
"\x80\x00\x00\x00\x00\x00\x00\x00",
{
{ 8,
"\x00\x00\x00\x00\x00\x00\x00\x00",
"\xB6\x6C\x1E\x44\x46\xDD\x95\x57"
}
}
},
{
"Salsa20 128 bit, test 3",
GCRY_CIPHER_SALSA20, 16, 8,
"\x00\x53\xA6\xF9\x4C\x9F\xF2\x45\x98\xEB\x3E\x91\xE4\x37\x8A\xDD",
"\x0D\x74\xDB\x42\xA9\x10\x77\xDE",
{
{ 8,
"\x00\x00\x00\x00\x00\x00\x00\x00",
"\x05\xE1\xE7\xBE\xB6\x97\xD9\x99"
}
}
},
{
"Salsa20 256 bit, test 1",
GCRY_CIPHER_SALSA20, 32, 8,
"\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
"\x00\x00\x00\x00\x00\x00\x00\x00",
{
{ 8,
"\x00\x00\x00\x00\x00\x00\x00\x00",
"\xE3\xBE\x8F\xDD\x8B\xEC\xA2\xE3"
}
}
},
{
"Salsa20 256 bit, test 2",
GCRY_CIPHER_SALSA20, 32, 8,
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
"\x80\x00\x00\x00\x00\x00\x00\x00",
{
{ 8,
"\x00\x00\x00\x00\x00\x00\x00\x00",
"\x2A\xBA\x3D\xC4\x5B\x49\x47\x00"
}
}
},
{
"Salsa20 256 bit, ecrypt verified, set 6, vector 0",
GCRY_CIPHER_SALSA20, 32, 8,
"\x00\x53\xA6\xF9\x4C\x9F\xF2\x45\x98\xEB\x3E\x91\xE4\x37\x8A\xDD"
"\x30\x83\xD6\x29\x7C\xCF\x22\x75\xC8\x1B\x6E\xC1\x14\x67\xBA\x0D",
"\x0D\x74\xDB\x42\xA9\x10\x77\xDE",
{
{ 8,
"\x00\x00\x00\x00\x00\x00\x00\x00",
"\xF5\xFA\xD5\x3F\x79\xF9\xDF\x58"
},
{ 64,
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
"\xF5\xFA\xD5\x3F\x79\xF9\xDF\x58\xC4\xAE\xA0\xD0\xED\x9A\x96\x01"
"\xF2\x78\x11\x2C\xA7\x18\x0D\x56\x5B\x42\x0A\x48\x01\x96\x70\xEA"
"\xF2\x4C\xE4\x93\xA8\x62\x63\xF6\x77\xB4\x6A\xCE\x19\x24\x77\x3D"
"\x2B\xB2\x55\x71\xE1\xAA\x85\x93\x75\x8F\xC3\x82\xB1\x28\x0B\x71"
}
}
}
#endif /*USE_SALSA20*/
};
gcry_cipher_hd_t hde, hdd;
unsigned char out[MAX_DATA_LEN];
int i, j;
gcry_error_t err = 0;
if (verbose)
fprintf (stderr, " Starting stream cipher checks.\n");
for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
{
if (verbose)
fprintf (stderr, " checking stream mode for %s [%i] (%s)\n",
gcry_cipher_algo_name (tv[i].algo), tv[i].algo, tv[i].name);
if (gcry_cipher_get_algo_blklen(tv[i].algo) != 1)
{
fail ("stream, gcry_cipher_get_algo_blklen: bad block length\n");
continue;
}
err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_STREAM, 0);
if (!err)
err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_STREAM, 0);
if (err)
{
fail ("stream, gcry_cipher_open for stream mode failed: %s\n",
gpg_strerror (err));
continue;
}
/* Now loop over all the data samples. */
for (j = 0; tv[i].data[j].inlen; j++)
{
err = gcry_cipher_setkey (hde, tv[i].key, tv[i].keylen);
if (!err)
err = gcry_cipher_setkey (hdd, tv[i].key, tv[i].keylen);
if (err)
{
fail ("stream, gcry_cipher_setkey failed: %s\n",
gpg_strerror (err));
goto next;
}
err = gcry_cipher_setiv (hde, tv[i].iv, tv[i].ivlen);
if (!err)
err = gcry_cipher_setiv (hdd, tv[i].iv, tv[i].ivlen);
if (err)
{
fail ("stream, gcry_cipher_setiv failed: %s\n",
gpg_strerror (err));
goto next;
}
err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
tv[i].data[j].plaintext,
tv[i].data[j].inlen);
if (err)
{
fail ("stream, gcry_cipher_encrypt (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
goto next;
}
if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen))
{
fail ("stream, encrypt mismatch entry %d:%d\n", i, j);
mismatch (tv[i].data[j].out, tv[i].data[j].inlen,
out, tv[i].data[j].inlen);
}
err = gcry_cipher_decrypt (hdd, out, tv[i].data[j].inlen, NULL, 0);
if (err)
{
fail ("stream, gcry_cipher_decrypt (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
goto next;
}
if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
fail ("stream, decrypt mismatch entry %d:%d\n", i, j);
}
/* This time we encrypt and decrypt one byte at a time */
for (j = 0; tv[i].data[j].inlen; j++)
{
int byteNum;
err = gcry_cipher_setkey (hde, tv[i].key, tv[i].keylen);
if (!err)
err = gcry_cipher_setkey (hdd, tv[i].key, tv[i].keylen);
if (err)
{
fail ("stream, gcry_cipher_setkey failed: %s\n",
gpg_strerror (err));
goto next;
}
err = gcry_cipher_setiv (hde, tv[i].iv, tv[i].ivlen);
if (!err)
err = gcry_cipher_setiv (hdd, tv[i].iv, tv[i].ivlen);
if (err)
{
fail ("stream, gcry_cipher_setiv failed: %s\n",
gpg_strerror (err));
goto next;
}
for (byteNum = 0; byteNum < tv[i].data[j].inlen; ++byteNum)
{
err = gcry_cipher_encrypt (hde, out+byteNum, 1,
(tv[i].data[j].plaintext) + byteNum,
1);
if (err)
{
fail ("stream, gcry_cipher_encrypt (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
goto next;
}
}
if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen))
fail ("stream, encrypt mismatch entry %d:%d (byte-wise)\n", i, j);
for (byteNum = 0; byteNum < tv[i].data[j].inlen; ++byteNum)
{
err = gcry_cipher_decrypt (hdd, out+byteNum, 1, NULL, 0);
if (err)
{
fail ("stream, gcry_cipher_decrypt (%d, %d) failed: %s\n",
i, j, gpg_strerror (err));
goto next;
}
}
if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
fail ("stream, decrypt mismatch entry %d:%d (byte-wise)\n", i, j);
}
next:
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
}
if (verbose)
fprintf (stderr, " Completed stream cipher checks.\n");
}
static void
check_stream_cipher_large_block (void)
{
struct tv
{
const char *name;
int algo;
int keylen;
int ivlen;
const char *key;
const char *iv;
struct data
{
int offset, length;
const char *result;
} data[MAX_DATA_LEN];
} tv[] = {
#ifdef USE_SALSA20
{
"Salsa20 256 bit, ecrypt verified, set 6, vector 0",
GCRY_CIPHER_SALSA20, 32, 8,
"\x00\x53\xA6\xF9\x4C\x9F\xF2\x45\x98\xEB\x3E\x91\xE4\x37\x8A\xDD"
"\x30\x83\xD6\x29\x7C\xCF\x22\x75\xC8\x1B\x6E\xC1\x14\x67\xBA\x0D",
"\x0D\x74\xDB\x42\xA9\x10\x77\xDE",
{
{ 0, 64,
"\xF5\xFA\xD5\x3F\x79\xF9\xDF\x58\xC4\xAE\xA0\xD0\xED\x9A\x96\x01"
"\xF2\x78\x11\x2C\xA7\x18\x0D\x56\x5B\x42\x0A\x48\x01\x96\x70\xEA"
"\xF2\x4C\xE4\x93\xA8\x62\x63\xF6\x77\xB4\x6A\xCE\x19\x24\x77\x3D"
"\x2B\xB2\x55\x71\xE1\xAA\x85\x93\x75\x8F\xC3\x82\xB1\x28\x0B\x71"
},
{ 65472, 64,
"\xB7\x0C\x50\x13\x9C\x63\x33\x2E\xF6\xE7\x7A\xC5\x43\x38\xA4\x07"
"\x9B\x82\xBE\xC9\xF9\xA4\x03\xDF\xEA\x82\x1B\x83\xF7\x86\x07\x91"
"\x65\x0E\xF1\xB2\x48\x9D\x05\x90\xB1\xDE\x77\x2E\xED\xA4\xE3\xBC"
"\xD6\x0F\xA7\xCE\x9C\xD6\x23\xD9\xD2\xFD\x57\x58\xB8\x65\x3E\x70"
},
{ 65536, 64,
"\x81\x58\x2C\x65\xD7\x56\x2B\x80\xAE\xC2\xF1\xA6\x73\xA9\xD0\x1C"
"\x9F\x89\x2A\x23\xD4\x91\x9F\x6A\xB4\x7B\x91\x54\xE0\x8E\x69\x9B"
"\x41\x17\xD7\xC6\x66\x47\x7B\x60\xF8\x39\x14\x81\x68\x2F\x5D\x95"
"\xD9\x66\x23\xDB\xC4\x89\xD8\x8D\xAA\x69\x56\xB9\xF0\x64\x6B\x6E"
},
{ 131008, 64,
"\xA1\x3F\xFA\x12\x08\xF8\xBF\x50\x90\x08\x86\xFA\xAB\x40\xFD\x10"
"\xE8\xCA\xA3\x06\xE6\x3D\xF3\x95\x36\xA1\x56\x4F\xB7\x60\xB2\x42"
"\xA9\xD6\xA4\x62\x8C\xDC\x87\x87\x62\x83\x4E\x27\xA5\x41\xDA\x2A"
"\x5E\x3B\x34\x45\x98\x9C\x76\xF6\x11\xE0\xFE\xC6\xD9\x1A\xCA\xCC"
}
}
},
{
"Salsa20 256 bit, ecrypt verified, set 6, vector 1",
GCRY_CIPHER_SALSA20, 32, 8,
"\x05\x58\xAB\xFE\x51\xA4\xF7\x4A\x9D\xF0\x43\x96\xE9\x3C\x8F\xE2"
"\x35\x88\xDB\x2E\x81\xD4\x27\x7A\xCD\x20\x73\xC6\x19\x6C\xBF\x12",
"\x16\x7D\xE4\x4B\xB2\x19\x80\xE7",
{
{ 0, 64,
"\x39\x44\xF6\xDC\x9F\x85\xB1\x28\x08\x38\x79\xFD\xF1\x90\xF7\xDE"
"\xE4\x05\x3A\x07\xBC\x09\x89\x6D\x51\xD0\x69\x0B\xD4\xDA\x4A\xC1"
"\x06\x2F\x1E\x47\xD3\xD0\x71\x6F\x80\xA9\xB4\xD8\x5E\x6D\x60\x85"
"\xEE\x06\x94\x76\x01\xC8\x5F\x1A\x27\xA2\xF7\x6E\x45\xA6\xAA\x87"
},
{ 65472, 64,
"\x36\xE0\x3B\x4B\x54\xB0\xB2\xE0\x4D\x06\x9E\x69\x00\x82\xC8\xC5"
"\x92\xDF\x56\xE6\x33\xF5\xD8\xC7\x68\x2A\x02\xA6\x5E\xCD\x13\x71"
"\x8C\xA4\x35\x2A\xAC\xCB\x0D\xA2\x0E\xD6\xBB\xBA\x62\xE1\x77\xF2"
"\x10\xE3\x56\x0E\x63\xBB\x82\x2C\x41\x58\xCA\xA8\x06\xA8\x8C\x82"
},
{ 65536, 64,
"\x1B\x77\x9E\x7A\x91\x7C\x8C\x26\x03\x9F\xFB\x23\xCF\x0E\xF8\xE0"
"\x8A\x1A\x13\xB4\x3A\xCD\xD9\x40\x2C\xF5\xDF\x38\x50\x10\x98\xDF"
"\xC9\x45\xA6\xCC\x69\xA6\xA1\x73\x67\xBC\x03\x43\x1A\x86\xB3\xED"
"\x04\xB0\x24\x5B\x56\x37\x9B\xF9\x97\xE2\x58\x00\xAD\x83\x7D\x7D"
},
{ 131008, 64,
"\x7E\xC6\xDA\xE8\x1A\x10\x5E\x67\x17\x2A\x0B\x8C\x4B\xBE\x7D\x06"
"\xA7\xA8\x75\x9F\x91\x4F\xBE\xB1\xAF\x62\xC8\xA5\x52\xEF\x4A\x4F"
"\x56\x96\x7E\xA2\x9C\x74\x71\xF4\x6F\x3B\x07\xF7\xA3\x74\x6E\x95"
"\x3D\x31\x58\x21\xB8\x5B\x6E\x8C\xB4\x01\x22\xB9\x66\x35\x31\x3C"
}
}
},
{
"Salsa20 256 bit, ecrypt verified, set 6, vector 2",
GCRY_CIPHER_SALSA20, 32, 8,
"\x0A\x5D\xB0\x03\x56\xA9\xFC\x4F\xA2\xF5\x48\x9B\xEE\x41\x94\xE7"
"\x3A\x8D\xE0\x33\x86\xD9\x2C\x7F\xD2\x25\x78\xCB\x1E\x71\xC4\x17",
"\x1F\x86\xED\x54\xBB\x22\x89\xF0",
{
{ 0, 64,
"\x3F\xE8\x5D\x5B\xB1\x96\x0A\x82\x48\x0B\x5E\x6F\x4E\x96\x5A\x44"
"\x60\xD7\xA5\x45\x01\x66\x4F\x7D\x60\xB5\x4B\x06\x10\x0A\x37\xFF"
"\xDC\xF6\xBD\xE5\xCE\x3F\x48\x86\xBA\x77\xDD\x5B\x44\xE9\x56\x44"
"\xE4\x0A\x8A\xC6\x58\x01\x15\x5D\xB9\x0F\x02\x52\x2B\x64\x40\x23"
},
{ 65472, 64,
"\xC8\xD6\xE5\x4C\x29\xCA\x20\x40\x18\xA8\x30\xE2\x66\xCE\xEE\x0D"
"\x03\x7D\xC4\x7E\x92\x19\x47\x30\x2A\xCE\x40\xD1\xB9\x96\xA6\xD8"
"\x0B\x59\x86\x77\xF3\x35\x2F\x1D\xAA\x6D\x98\x88\xF8\x91\xAD\x95"
"\xA1\xC3\x2F\xFE\xB7\x1B\xB8\x61\xE8\xB0\x70\x58\x51\x51\x71\xC9"
},
{ 65536, 64,
"\xB7\x9F\xD7\x76\x54\x2B\x46\x20\xEF\xCB\x88\x44\x95\x99\xF2\x34"
"\x03\xE7\x4A\x6E\x91\xCA\xCC\x50\xA0\x5A\x8F\x8F\x3C\x0D\xEA\x8B"
"\x00\xE1\xA5\xE6\x08\x1F\x55\x26\xAE\x97\x5B\x3B\xC0\x45\x0F\x1A"
"\x0C\x8B\x66\xF8\x08\xF1\x90\x4B\x97\x13\x61\x13\x7C\x93\x15\x6F"
},
{ 131008, 64,
"\x79\x98\x20\x4F\xED\x70\xCE\x8E\x0D\x02\x7B\x20\x66\x35\xC0\x8C"
"\x8B\xC4\x43\x62\x26\x08\x97\x0E\x40\xE3\xAE\xDF\x3C\xE7\x90\xAE"
"\xED\xF8\x9F\x92\x26\x71\xB4\x53\x78\xE2\xCD\x03\xF6\xF6\x23\x56"
"\x52\x9C\x41\x58\xB7\xFF\x41\xEE\x85\x4B\x12\x35\x37\x39\x88\xC8"
}
}
},
{
"Salsa20 256 bit, ecrypt verified, set 6, vector 3",
GCRY_CIPHER_SALSA20, 32, 8,
"\x0F\x62\xB5\x08\x5B\xAE\x01\x54\xA7\xFA\x4D\xA0\xF3\x46\x99\xEC"
"\x3F\x92\xE5\x38\x8B\xDE\x31\x84\xD7\x2A\x7D\xD0\x23\x76\xC9\x1C",
"\x28\x8F\xF6\x5D\xC4\x2B\x92\xF9",
{
{ 0, 64,
"\x5E\x5E\x71\xF9\x01\x99\x34\x03\x04\xAB\xB2\x2A\x37\xB6\x62\x5B"
"\xF8\x83\xFB\x89\xCE\x3B\x21\xF5\x4A\x10\xB8\x10\x66\xEF\x87\xDA"
"\x30\xB7\x76\x99\xAA\x73\x79\xDA\x59\x5C\x77\xDD\x59\x54\x2D\xA2"
"\x08\xE5\x95\x4F\x89\xE4\x0E\xB7\xAA\x80\xA8\x4A\x61\x76\x66\x3F"
},
{ 65472, 64,
"\x2D\xA2\x17\x4B\xD1\x50\xA1\xDF\xEC\x17\x96\xE9\x21\xE9\xD6\xE2"
"\x4E\xCF\x02\x09\xBC\xBE\xA4\xF9\x83\x70\xFC\xE6\x29\x05\x6F\x64"
"\x91\x72\x83\x43\x6E\x2D\x3F\x45\x55\x62\x25\x30\x7D\x5C\xC5\xA5"
"\x65\x32\x5D\x89\x93\xB3\x7F\x16\x54\x19\x5C\x24\x0B\xF7\x5B\x16"
},
{ 65536, 64,
"\xAB\xF3\x9A\x21\x0E\xEE\x89\x59\x8B\x71\x33\x37\x70\x56\xC2\xFE"
"\xF4\x2D\xA7\x31\x32\x75\x63\xFB\x67\xC7\xBE\xDB\x27\xF3\x8C\x7C"
"\x5A\x3F\xC2\x18\x3A\x4C\x6B\x27\x7F\x90\x11\x52\x47\x2C\x6B\x2A"
"\xBC\xF5\xE3\x4C\xBE\x31\x5E\x81\xFD\x3D\x18\x0B\x5D\x66\xCB\x6C"
},
{ 131008, 64,
"\x1B\xA8\x9D\xBD\x3F\x98\x83\x97\x28\xF5\x67\x91\xD5\xB7\xCE\x23"
"\x50\x36\xDE\x84\x3C\xCC\xAB\x03\x90\xB8\xB5\x86\x2F\x1E\x45\x96"
"\xAE\x8A\x16\xFB\x23\xDA\x99\x7F\x37\x1F\x4E\x0A\xAC\xC2\x6D\xB8"
"\xEB\x31\x4E\xD4\x70\xB1\xAF\x6B\x9F\x8D\x69\xDD\x79\xA9\xD7\x50"
}
}
}
#endif /*USE_SALSA20*/
};
char zeroes[512];
gcry_cipher_hd_t hde;
unsigned char *buffer;
unsigned char *p;
size_t buffersize;
unsigned int n;
int i, j;
gcry_error_t err = 0;
if (verbose)
fprintf (stderr, " Starting large block stream cipher checks.\n");
memset (zeroes, 0, 512);
buffersize = 128 * 1024;
buffer = gcry_xmalloc (buffersize+1024);
memset (buffer+buffersize, 0x5a, 1024);
for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
{
if (verbose)
fprintf (stderr, " checking large block stream for %s [%i] (%s)\n",
gcry_cipher_algo_name (tv[i].algo), tv[i].algo, tv[i].name);
err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_STREAM, 0);
if (err)
{
fail ("large stream, gcry_cipher_open for stream mode failed: %s\n",
gpg_strerror (err));
continue;
}
err = gcry_cipher_setkey (hde, tv[i].key, tv[i].keylen);
if (err)
{
fail ("large stream, gcry_cipher_setkey failed: %s\n",
gpg_strerror (err));
goto next;
}
err = gcry_cipher_setiv (hde, tv[i].iv, tv[i].ivlen);
if (err)
{
fail ("large stream, gcry_cipher_setiv failed: %s\n",
gpg_strerror (err));
goto next;
}
for (j=0, p=buffer; j < buffersize/512; j++, p += 512)
{
err = gcry_cipher_encrypt (hde, p, 512, zeroes, 512);
if (err)
{
fail ("large stream, "
"gcry_cipher_encrypt (%d) block %d failed: %s\n",
i, j, gpg_strerror (err));
goto next;
}
}
for (j=0, p=buffer+buffersize; j < 1024; j++, p++)
if (*p != 0x5a)
die ("large stream, buffer corrupted at j=%d\n", j);
/* Now loop over all the data samples. */
for (j = 0; tv[i].data[j].length; j++)
{
assert (tv[i].data[j].offset + tv[i].data[j].length <= buffersize);
if (memcmp (tv[i].data[j].result,
buffer + tv[i].data[j].offset, tv[i].data[j].length))
{
fail ("large stream, encrypt mismatch entry %d:%d\n", i, j);
mismatch (tv[i].data[j].result, tv[i].data[j].length,
buffer + tv[i].data[j].offset, tv[i].data[j].length);
}
}
/*
* Let's do the same thing again but using changing block sizes.
*/
err = gcry_cipher_setkey (hde, tv[i].key, tv[i].keylen);
if (err)
{
fail ("large stream, gcry_cipher_setkey failed: %s\n",
gpg_strerror (err));
goto next;
}
err = gcry_cipher_setiv (hde, tv[i].iv, tv[i].ivlen);
if (err)
{
fail ("large stream, gcry_cipher_setiv failed: %s\n",
gpg_strerror (err));
goto next;
}
for (n=0, p=buffer, j = 0; n < buffersize; n += j, p += j)
{
switch (j)
{
case 0: j = 1; break;
case 1: j = 64; break;
case 64: j= 384; break;
case 384: j = 63; break;
case 63: j = 512; break;
case 512: j = 32; break;
case 32: j = 503; break;
default: j = 509; break;
}
if ( n + j >= buffersize )
j = buffersize - n;
assert (j <= 512);
err = gcry_cipher_encrypt (hde, p, j, zeroes, j);
if (err)
{
fail ("large stream, "
"gcry_cipher_encrypt (%d) offset %u failed: %s\n",
i, n, gpg_strerror (err));
goto next;
}
}
for (j=0, p=buffer+buffersize; j < 1024; j++, p++)
if (*p != 0x5a)
die ("large stream, buffer corrupted at j=%d (line %d)\n",
j, __LINE__);
/* Now loop over all the data samples. */
for (j = 0; tv[i].data[j].length; j++)
{
assert (tv[i].data[j].offset + tv[i].data[j].length <= buffersize);
if (memcmp (tv[i].data[j].result,
buffer + tv[i].data[j].offset, tv[i].data[j].length))
{
fail ("large stream var, encrypt mismatch entry %d:%d\n", i, j);
mismatch (tv[i].data[j].result, tv[i].data[j].length,
buffer + tv[i].data[j].offset, tv[i].data[j].length);
}
}
next:
gcry_cipher_close (hde);
}
gcry_free (buffer);
if (verbose)
fprintf (stderr, " Completed large block stream cipher checks.\n");
}
/* Check that our bulk encryption fucntions work properly. */
static void
check_bulk_cipher_modes (void)
{
struct
{
int algo;
int mode;
const char *key;
int keylen;
const char *iv;
int ivlen;
char t1_hash[20];
} tv[] = {
{ GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CFB,
"abcdefghijklmnop", 16,
"1234567890123456", 16,
/*[0]*/
{ 0x53, 0xda, 0x27, 0x3c, 0x78, 0x3d, 0x54, 0x66, 0x19, 0x63,
0xd7, 0xe6, 0x20, 0x10, 0xcd, 0xc0, 0x5a, 0x0b, 0x06, 0xcc }
},
{ GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB,
"abcdefghijklmnopABCDEFG", 24,
"1234567890123456", 16,
/*[1]*/
{ 0xc7, 0xb1, 0xd0, 0x09, 0x95, 0x04, 0x34, 0x61, 0x2b, 0xd9,
0xcb, 0xb3, 0xc7, 0xcb, 0xef, 0xea, 0x16, 0x19, 0x9b, 0x3e }
},
{ GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB,
"abcdefghijklmnopABCDEFGHIJKLMNOP", 32,
"1234567890123456", 16,
/*[2]*/
{ 0x31, 0xe1, 0x1f, 0x63, 0x65, 0x47, 0x8c, 0x3f, 0x53, 0xdb,
0xd9, 0x4d, 0x91, 0x1d, 0x02, 0x9c, 0x05, 0x25, 0x58, 0x29 }
},
{ GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC,
"abcdefghijklmnop", 16,
"1234567890123456", 16,
/*[3]*/
{ 0xdc, 0x0c, 0xc2, 0xd9, 0x6b, 0x47, 0xf9, 0xeb, 0x06, 0xb4,
0x2f, 0x6e, 0xec, 0x72, 0xbf, 0x55, 0x26, 0x7f, 0xa9, 0x97 }
},
{ GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC,
"abcdefghijklmnopABCDEFG", 24,
"1234567890123456", 16,
/*[4]*/
{ 0x2b, 0x90, 0x9b, 0xe6, 0x40, 0xab, 0x6e, 0xc2, 0xc5, 0xb1,
0x87, 0xf5, 0x43, 0x84, 0x7b, 0x04, 0x06, 0x47, 0xd1, 0x8f }
},
{ GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC,
"abcdefghijklmnopABCDEFGHIJKLMNOP", 32,
"1234567890123456", 16,
/*[5]*/
{ 0xaa, 0xa8, 0xdf, 0x03, 0xb0, 0xba, 0xc4, 0xe3, 0xc1, 0x02,
0x38, 0x31, 0x8d, 0x86, 0xcb, 0x49, 0x6d, 0xad, 0xae, 0x01 }
},
{ GCRY_CIPHER_AES, GCRY_CIPHER_MODE_OFB,
"abcdefghijklmnop", 16,
"1234567890123456", 16,
/*[6]*/
{ 0x65, 0xfe, 0xde, 0x48, 0xd0, 0xa1, 0xa6, 0xf9, 0x24, 0x6b,
0x52, 0x5f, 0x21, 0x8a, 0x6f, 0xc7, 0x70, 0x3b, 0xd8, 0x4a }
},
{ GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB,
"abcdefghijklmnopABCDEFG", 24,
"1234567890123456", 16,
/*[7]*/
{ 0x59, 0x5b, 0x02, 0xa2, 0x88, 0xc0, 0xbe, 0x94, 0x43, 0xaa,
0x39, 0xf6, 0xbd, 0xcc, 0x83, 0x99, 0xee, 0x00, 0xa1, 0x91 }
},
{ GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB,
"abcdefghijklmnopABCDEFGHIJKLMNOP", 32,
"1234567890123456", 16,
/*[8]*/
{ 0x38, 0x8c, 0xe1, 0xe2, 0xbe, 0x67, 0x60, 0xe8, 0xeb, 0xce,
0xd0, 0xc6, 0xaa, 0xd6, 0xf6, 0x26, 0x15, 0x56, 0xd0, 0x2b }
},
{ GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR,
"abcdefghijklmnop", 16,
"1234567890123456", 16,
/*[9]*/
{ 0x9a, 0x48, 0x94, 0xd6, 0x50, 0x46, 0x81, 0xdb, 0x68, 0x34,
0x3b, 0xc5, 0x9e, 0x66, 0x94, 0x81, 0x98, 0xa0, 0xf9, 0xff }
},
{ GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR,
"abcdefghijklmnopABCDEFG", 24,
"1234567890123456", 16,
/*[10]*/
{ 0x2c, 0x2c, 0xd3, 0x75, 0x81, 0x2a, 0x59, 0x07, 0xeb, 0x08,
0xce, 0x28, 0x4c, 0x0c, 0x6a, 0xa8, 0x8f, 0xa3, 0x98, 0x7e }
},
{ GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR,
"abcdefghijklmnopABCDEFGHIJKLMNOP", 32,
"1234567890123456", 16,
/*[11]*/
{ 0x64, 0xce, 0x73, 0x03, 0xc7, 0x89, 0x99, 0x1f, 0xf1, 0xce,
0xfe, 0xfb, 0xb9, 0x42, 0x30, 0xdf, 0xbb, 0x68, 0x6f, 0xd3 }
},
{ GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB,
"abcdefghijklmnop", 16,
"1234567890123456", 16,
/*[12]*/
{ 0x51, 0xae, 0xf5, 0xac, 0x22, 0xa0, 0xba, 0x11, 0xc5, 0xaa,
0xb4, 0x70, 0x99, 0xce, 0x18, 0x08, 0x12, 0x9b, 0xb1, 0xc5 }
},
{ GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB,
"abcdefghijklmnopABCDEFG", 24,
"1234567890123456", 16,
/*[13]*/
{ 0x57, 0x91, 0xea, 0x48, 0xd8, 0xbf, 0x9e, 0xc1, 0xae, 0x33,
0xb3, 0xfd, 0xf7, 0x7a, 0xeb, 0x30, 0xb1, 0x62, 0x0d, 0x82 }
},
{ GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB,
"abcdefghijklmnopABCDEFGHIJKLMNOP", 32,
"1234567890123456", 16,
/*[14]*/
{ 0x2d, 0x71, 0x54, 0xb9, 0xc5, 0x28, 0x76, 0xff, 0x76, 0xb5,
0x99, 0x37, 0x99, 0x9d, 0xf7, 0x10, 0x6d, 0x86, 0x4f, 0x3f }
}
};
gcry_cipher_hd_t hde = NULL;
gcry_cipher_hd_t hdd = NULL;
unsigned char *buffer_base, *outbuf_base; /* Allocated buffers. */
unsigned char *buffer, *outbuf; /* Aligned buffers. */
size_t buflen;
unsigned char hash[20];
int i, j, keylen, blklen;
gcry_error_t err = 0;
if (verbose)
fprintf (stderr, "Starting bulk cipher checks.\n");
buflen = 16*100; /* We check a 1600 byte buffer. */
buffer_base = gcry_xmalloc (buflen+16);
buffer = buffer_base + (16 - ((size_t)buffer_base & 0x0f));
outbuf_base = gcry_xmalloc (buflen+16);
outbuf = outbuf_base + (16 - ((size_t)outbuf_base & 0x0f));
for (i = 0; i < DIM (tv); i++)
{
if (verbose)
fprintf (stderr, " checking bulk encryption for %s [%i], mode %d\n",
gcry_cipher_algo_name (tv[i].algo),
tv[i].algo, tv[i].mode);
err = gcry_cipher_open (&hde, tv[i].algo, tv[i].mode, 0);
if (!err)
err = gcry_cipher_open (&hdd, tv[i].algo, tv[i].mode, 0);
if (err)
{
fail ("gcry_cipher_open failed: %s\n", gpg_strerror (err));
goto leave;
}
keylen = gcry_cipher_get_algo_keylen(tv[i].algo);
if (!keylen)
{
fail ("gcry_cipher_get_algo_keylen failed\n");
goto leave;
}
err = gcry_cipher_setkey (hde, tv[i].key, tv[i].keylen);
if (!err)
err = gcry_cipher_setkey (hdd, tv[i].key, tv[i].keylen);
if (err)
{
fail ("gcry_cipher_setkey failed: %s\n", gpg_strerror (err));
goto leave;
}
blklen = gcry_cipher_get_algo_blklen(tv[i].algo);
if (!blklen)
{
fail ("gcry_cipher_get_algo_blklen failed\n");
goto leave;
}
err = gcry_cipher_setiv (hde, tv[i].iv, tv[i].ivlen);
if (!err)
err = gcry_cipher_setiv (hdd, tv[i].iv, tv[i].ivlen);
if (err)
{
fail ("gcry_cipher_setiv failed: %s\n", gpg_strerror (err));
goto leave;
}
/* Fill the buffer with our test pattern. */
for (j=0; j < buflen; j++)
buffer[j] = ((j & 0xff) ^ ((j >> 8) & 0xff));
err = gcry_cipher_encrypt (hde, outbuf, buflen, buffer, buflen);
if (err)
{
fail ("gcry_cipher_encrypt (algo %d, mode %d) failed: %s\n",
tv[i].algo, tv[i].mode, gpg_strerror (err));
goto leave;
}
gcry_md_hash_buffer (GCRY_MD_SHA1, hash, outbuf, buflen);
#if 0
printf ("/*[%d]*/\n", i);
fputs (" {", stdout);
for (j=0; j < 20; j++)
printf (" 0x%02x%c%s", hash[j], j==19? ' ':',', j == 9? "\n ":"");
puts ("}");
#endif
if (memcmp (hash, tv[i].t1_hash, 20))
fail ("encrypt mismatch (algo %d, mode %d)\n",
tv[i].algo, tv[i].mode);
err = gcry_cipher_decrypt (hdd, outbuf, buflen, NULL, 0);
if (err)
{
fail ("gcry_cipher_decrypt (algo %d, mode %d) failed: %s\n",
tv[i].algo, tv[i].mode, gpg_strerror (err));
goto leave;
}
if (memcmp (buffer, outbuf, buflen))
fail ("decrypt mismatch (algo %d, mode %d)\n",
tv[i].algo, tv[i].mode);
gcry_cipher_close (hde); hde = NULL;
gcry_cipher_close (hdd); hdd = NULL;
}
if (verbose)
fprintf (stderr, "Completed bulk cipher checks.\n");
leave:
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
gcry_free (buffer_base);
gcry_free (outbuf_base);
}
/* The core of the cipher check. In addition to the parameters passed
to check_one_cipher it also receives the KEY and the plain data.
PASS is printed with error messages. The function returns 0 on
success. */
static int
check_one_cipher_core (int algo, int mode, int flags,
const char *key, size_t nkey,
const unsigned char *plain, size_t nplain,
int bufshift, int pass)
{
gcry_cipher_hd_t hd;
unsigned char in_buffer[1040+1], out_buffer[1040+1];
unsigned char *in, *out;
int keylen;
gcry_error_t err = 0;
assert (nkey == 32);
assert (nplain == 1040);
assert (sizeof(in_buffer) == nplain + 1);
assert (sizeof(out_buffer) == sizeof(in_buffer));
if (!bufshift)
{
in = in_buffer;
out = out_buffer;
}
else if (bufshift == 1)
{
in = in_buffer+1;
out = out_buffer;
}
else if (bufshift == 2)
{
in = in_buffer+1;
out = out_buffer+1;
}
else
{
in = in_buffer;
out = out_buffer+1;
}
keylen = gcry_cipher_get_algo_keylen (algo);
if (!keylen)
{
fail ("pass %d, algo %d, mode %d, gcry_cipher_get_algo_keylen failed\n",
pass, algo, mode);
return -1;
}
if (keylen < 40 / 8 || keylen > 32)
{
fail ("pass %d, algo %d, mode %d, keylength problem (%d)\n", pass, algo, mode, keylen);
return -1;
}
err = gcry_cipher_open (&hd, algo, mode, flags);
if (err)
{
fail ("pass %d, algo %d, mode %d, gcry_cipher_open failed: %s\n",
pass, algo, mode, gpg_strerror (err));
return -1;
}
err = gcry_cipher_setkey (hd, key, keylen);
if (err)
{
fail ("pass %d, algo %d, mode %d, gcry_cipher_setkey failed: %s\n",
pass, algo, mode, gpg_strerror (err));
gcry_cipher_close (hd);
return -1;
}
err = gcry_cipher_encrypt (hd, out, nplain, plain, nplain);
if (err)
{
fail ("pass %d, algo %d, mode %d, gcry_cipher_encrypt failed: %s\n",
pass, algo, mode, gpg_strerror (err));
gcry_cipher_close (hd);
return -1;
}
gcry_cipher_reset (hd);
err = gcry_cipher_decrypt (hd, in, nplain, out, nplain);
if (err)
{
fail ("pass %d, algo %d, mode %d, gcry_cipher_decrypt failed: %s\n",
pass, algo, mode, gpg_strerror (err));
gcry_cipher_close (hd);
return -1;
}
if (memcmp (plain, in, nplain))
fail ("pass %d, algo %d, mode %d, encrypt-decrypt mismatch\n",
pass, algo, mode);
/* Again, using in-place encryption. */
gcry_cipher_reset (hd);
memcpy (out, plain, nplain);
err = gcry_cipher_encrypt (hd, out, nplain, NULL, 0);
if (err)
{
fail ("pass %d, algo %d, mode %d, in-place, gcry_cipher_encrypt failed:"
" %s\n",
pass, algo, mode, gpg_strerror (err));
gcry_cipher_close (hd);
return -1;
}
gcry_cipher_reset (hd);
err = gcry_cipher_decrypt (hd, out, nplain, NULL, 0);
if (err)
{
fail ("pass %d, algo %d, mode %d, in-place, gcry_cipher_decrypt failed:"
" %s\n",
pass, algo, mode, gpg_strerror (err));
gcry_cipher_close (hd);
return -1;
}
if (memcmp (plain, out, nplain))
fail ("pass %d, algo %d, mode %d, in-place, encrypt-decrypt mismatch\n",
pass, algo, mode);
gcry_cipher_close (hd);
return 0;
}
static void
check_one_cipher (int algo, int mode, int flags)
{
char key[32+1];
unsigned char plain[1040+1];
int bufshift, i;
for (bufshift=0; bufshift < 4; bufshift++)
{
/* Pass 0: Standard test. */
memcpy (key, "0123456789abcdef.,;/[]{}-=ABCDEF", 32);
memcpy (plain, "foobar42FOOBAR17", 16);
for (i = 16; i < 1040; i += 16)
{
memcpy (&plain[i], &plain[i-16], 16);
if (!++plain[i+7])
plain[i+6]++;
if (!++plain[i+15])
plain[i+14]++;
}
if (check_one_cipher_core (algo, mode, flags, key, 32, plain, 1040,
bufshift, 0+10*bufshift))
return;
/* Pass 1: Key not aligned. */
memmove (key+1, key, 32);
if (check_one_cipher_core (algo, mode, flags, key+1, 32, plain, 1040,
bufshift, 1+10*bufshift))
return;
/* Pass 2: Key not aligned and data not aligned. */
memmove (plain+1, plain, 1024);
if (check_one_cipher_core (algo, mode, flags, key+1, 32, plain+1, 1040,
bufshift, 2+10*bufshift))
return;
/* Pass 3: Key aligned and data not aligned. */
memmove (key, key+1, 32);
if (check_one_cipher_core (algo, mode, flags, key, 32, plain+1, 1040,
bufshift, 3+10*bufshift))
return;
}
return;
}
static void
check_ciphers (void)
{
static int algos[] = {
#if USE_BLOWFISH
GCRY_CIPHER_BLOWFISH,
#endif
#if USE_DES
GCRY_CIPHER_DES,
GCRY_CIPHER_3DES,
#endif
#if USE_CAST5
GCRY_CIPHER_CAST5,
#endif
#if USE_AES
GCRY_CIPHER_AES,
GCRY_CIPHER_AES192,
GCRY_CIPHER_AES256,
#endif
#if USE_TWOFISH
GCRY_CIPHER_TWOFISH,
GCRY_CIPHER_TWOFISH128,
#endif
#if USE_SERPENT
GCRY_CIPHER_SERPENT128,
GCRY_CIPHER_SERPENT192,
GCRY_CIPHER_SERPENT256,
#endif
#if USE_RFC2268
GCRY_CIPHER_RFC2268_40,
#endif
#if USE_SEED
GCRY_CIPHER_SEED,
#endif
#if USE_CAMELLIA
GCRY_CIPHER_CAMELLIA128,
GCRY_CIPHER_CAMELLIA192,
GCRY_CIPHER_CAMELLIA256,
#endif
#if USE_IDEA
GCRY_CIPHER_IDEA,
#endif
0
};
static int algos2[] = {
#if USE_ARCFOUR
GCRY_CIPHER_ARCFOUR,
#endif
#if USE_SALSA20
GCRY_CIPHER_SALSA20,
#endif
0
};
int i;
if (verbose)
fprintf (stderr, "Starting Cipher checks.\n");
for (i = 0; algos[i]; i++)
{
if (gcry_cipher_test_algo (algos[i]) && in_fips_mode)
{
if (verbose)
fprintf (stderr, " algorithm %d not available in fips mode\n",
algos[i]);
continue;
}
if (verbose)
fprintf (stderr, " checking %s [%i]\n",
gcry_cipher_algo_name (algos[i]),
gcry_cipher_map_name (gcry_cipher_algo_name (algos[i])));
check_one_cipher (algos[i], GCRY_CIPHER_MODE_ECB, 0);
check_one_cipher (algos[i], GCRY_CIPHER_MODE_CFB, 0);
check_one_cipher (algos[i], GCRY_CIPHER_MODE_OFB, 0);
check_one_cipher (algos[i], GCRY_CIPHER_MODE_CBC, 0);
check_one_cipher (algos[i], GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_CTS);
check_one_cipher (algos[i], GCRY_CIPHER_MODE_CTR, 0);
}
for (i = 0; algos2[i]; i++)
{
if (gcry_cipher_test_algo (algos[i]) && in_fips_mode)
{
if (verbose)
fprintf (stderr, " algorithm %d not available in fips mode\n",
algos[i]);
continue;
}
if (verbose)
fprintf (stderr, " checking %s\n",
gcry_cipher_algo_name (algos2[i]));
check_one_cipher (algos2[i], GCRY_CIPHER_MODE_STREAM, 0);
}
/* we have now run all cipher's selftests */
if (verbose)
fprintf (stderr, "Completed Cipher checks.\n");
/* TODO: add some extra encryption to test the higher level functions */
}
static void
check_cipher_modes(void)
{
if (verbose)
fprintf (stderr, "Starting Cipher Mode checks.\n");
check_aes128_cbc_cts_cipher ();
check_cbc_mac_cipher ();
check_ctr_cipher ();
check_cfb_cipher ();
check_ofb_cipher ();
check_stream_cipher ();
check_stream_cipher_large_block ();
if (verbose)
fprintf (stderr, "Completed Cipher Mode checks.\n");
}
static void
check_one_md (int algo, const char *data, int len, const char *expect)
{
gcry_md_hd_t hd, hd2;
unsigned char *p;
int mdlen;
int i;
gcry_error_t err = 0;
err = gcry_md_open (&hd, algo, 0);
if (err)
{
fail ("algo %d, gcry_md_open failed: %s\n", algo, gpg_strerror (err));
return;
}
mdlen = gcry_md_get_algo_dlen (algo);
if (mdlen < 1 || mdlen > 500)
{
fail ("algo %d, gcry_md_get_algo_dlen failed: %d\n", algo, mdlen);
return;
}
if (*data == '!' && !data[1])
{ /* hash one million times a "a" */
char aaa[1000];
/* Write in odd size chunks so that we test the buffering. */
memset (aaa, 'a', 1000);
for (i = 0; i < 1000; i++)
gcry_md_write (hd, aaa, 1000);
}
else
gcry_md_write (hd, data, len);
err = gcry_md_copy (&hd2, hd);
if (err)
{
fail ("algo %d, gcry_md_copy failed: %s\n", algo, gpg_strerror (err));
}
gcry_md_close (hd);
p = gcry_md_read (hd2, algo);
if (memcmp (p, expect, mdlen))
{
printf ("computed: ");
for (i = 0; i < mdlen; i++)
printf ("%02x ", p[i] & 0xFF);
printf ("\nexpected: ");
for (i = 0; i < mdlen; i++)
printf ("%02x ", expect[i] & 0xFF);
printf ("\n");
fail ("algo %d, digest mismatch\n", algo);
}
gcry_md_close (hd2);
}
static void
check_digests (void)
{
static struct algos
{
int md;
const char *data;
const char *expect;
} algos[] =
{
{ GCRY_MD_MD4, "",
"\x31\xD6\xCF\xE0\xD1\x6A\xE9\x31\xB7\x3C\x59\xD7\xE0\xC0\x89\xC0" },
{ GCRY_MD_MD4, "a",
"\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46\x24\x5e\x05\xfb\xdb\xd6\xfb\x24" },
{ GCRY_MD_MD4, "message digest",
"\xd9\x13\x0a\x81\x64\x54\x9f\xe8\x18\x87\x48\x06\xe1\xc7\x01\x4b" },
{ GCRY_MD_MD5, "",
"\xD4\x1D\x8C\xD9\x8F\x00\xB2\x04\xE9\x80\x09\x98\xEC\xF8\x42\x7E" },
{ GCRY_MD_MD5, "a",
"\x0C\xC1\x75\xB9\xC0\xF1\xB6\xA8\x31\xC3\x99\xE2\x69\x77\x26\x61" },
{ GCRY_MD_MD5, "abc",
"\x90\x01\x50\x98\x3C\xD2\x4F\xB0\xD6\x96\x3F\x7D\x28\xE1\x7F\x72" },
{ GCRY_MD_MD5, "message digest",
"\xF9\x6B\x69\x7D\x7C\xB7\x93\x8D\x52\x5A\x2F\x31\xAA\xF1\x61\xD0" },
{ GCRY_MD_SHA1, "abc",
"\xA9\x99\x3E\x36\x47\x06\x81\x6A\xBA\x3E"
"\x25\x71\x78\x50\xC2\x6C\x9C\xD0\xD8\x9D" },
{ GCRY_MD_SHA1,
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"\x84\x98\x3E\x44\x1C\x3B\xD2\x6E\xBA\xAE"
"\x4A\xA1\xF9\x51\x29\xE5\xE5\x46\x70\xF1" },
{ GCRY_MD_SHA1, "!" /* kludge for "a"*1000000 */ ,
"\x34\xAA\x97\x3C\xD4\xC4\xDA\xA4\xF6\x1E"
"\xEB\x2B\xDB\xAD\x27\x31\x65\x34\x01\x6F" },
/* From RFC3874 */
{ GCRY_MD_SHA224, "abc",
"\x23\x09\x7d\x22\x34\x05\xd8\x22\x86\x42\xa4\x77\xbd\xa2\x55\xb3"
"\x2a\xad\xbc\xe4\xbd\xa0\xb3\xf7\xe3\x6c\x9d\xa7" },
{ GCRY_MD_SHA224,
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"\x75\x38\x8b\x16\x51\x27\x76\xcc\x5d\xba\x5d\xa1\xfd\x89\x01\x50"
"\xb0\xc6\x45\x5c\xb4\xf5\x8b\x19\x52\x52\x25\x25" },
{ GCRY_MD_SHA224, "!",
"\x20\x79\x46\x55\x98\x0c\x91\xd8\xbb\xb4\xc1\xea\x97\x61\x8a\x4b"
"\xf0\x3f\x42\x58\x19\x48\xb2\xee\x4e\xe7\xad\x67" },
{ GCRY_MD_SHA256, "abc",
"\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23"
"\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad" },
{ GCRY_MD_SHA256,
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39"
"\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1" },
{ GCRY_MD_SHA256, "!",
"\xcd\xc7\x6e\x5c\x99\x14\xfb\x92\x81\xa1\xc7\xe2\x84\xd7\x3e\x67"
"\xf1\x80\x9a\x48\xa4\x97\x20\x0e\x04\x6d\x39\xcc\xc7\x11\x2c\xd0" },
{ GCRY_MD_SHA384, "abc",
"\xcb\x00\x75\x3f\x45\xa3\x5e\x8b\xb5\xa0\x3d\x69\x9a\xc6\x50\x07"
"\x27\x2c\x32\xab\x0e\xde\xd1\x63\x1a\x8b\x60\x5a\x43\xff\x5b\xed"
"\x80\x86\x07\x2b\xa1\xe7\xcc\x23\x58\xba\xec\xa1\x34\xc8\x25\xa7" },
{ GCRY_MD_SHA512, "abc",
"\xDD\xAF\x35\xA1\x93\x61\x7A\xBA\xCC\x41\x73\x49\xAE\x20\x41\x31"
"\x12\xE6\xFA\x4E\x89\xA9\x7E\xA2\x0A\x9E\xEE\xE6\x4B\x55\xD3\x9A"
"\x21\x92\x99\x2A\x27\x4F\xC1\xA8\x36\xBA\x3C\x23\xA3\xFE\xEB\xBD"
"\x45\x4D\x44\x23\x64\x3C\xE8\x0E\x2A\x9A\xC9\x4F\xA5\x4C\xA4\x9F" },
{ GCRY_MD_RMD160, "",
"\x9c\x11\x85\xa5\xc5\xe9\xfc\x54\x61\x28"
"\x08\x97\x7e\xe8\xf5\x48\xb2\x25\x8d\x31" },
{ GCRY_MD_RMD160, "a",
"\x0b\xdc\x9d\x2d\x25\x6b\x3e\xe9\xda\xae"
"\x34\x7b\xe6\xf4\xdc\x83\x5a\x46\x7f\xfe" },
{ GCRY_MD_RMD160, "abc",
"\x8e\xb2\x08\xf7\xe0\x5d\x98\x7a\x9b\x04"
"\x4a\x8e\x98\xc6\xb0\x87\xf1\x5a\x0b\xfc" },
{ GCRY_MD_RMD160, "message digest",
"\x5d\x06\x89\xef\x49\xd2\xfa\xe5\x72\xb8"
"\x81\xb1\x23\xa8\x5f\xfa\x21\x59\x5f\x36" },
{ GCRY_MD_CRC32, "", "\x00\x00\x00\x00" },
{ GCRY_MD_CRC32, "foo", "\x8c\x73\x65\x21" },
{ GCRY_MD_CRC32_RFC1510, "", "\x00\x00\x00\x00" },
{ GCRY_MD_CRC32_RFC1510, "foo", "\x73\x32\xbc\x33" },
{ GCRY_MD_CRC32_RFC1510, "test0123456789", "\xb8\x3e\x88\xd6" },
{ GCRY_MD_CRC32_RFC1510, "MASSACHVSETTS INSTITVTE OF TECHNOLOGY",
"\xe3\x41\x80\xf7" },
#if 0
{ GCRY_MD_CRC32_RFC1510, "\x80\x00", "\x3b\x83\x98\x4b" },
{ GCRY_MD_CRC32_RFC1510, "\x00\x08", "\x0e\xdb\x88\x32" },
{ GCRY_MD_CRC32_RFC1510, "\x00\x80", "\xed\xb8\x83\x20" },
#endif
{ GCRY_MD_CRC32_RFC1510, "\x80", "\xed\xb8\x83\x20" },
#if 0
{ GCRY_MD_CRC32_RFC1510, "\x80\x00\x00\x00", "\xed\x59\xb6\x3b" },
{ GCRY_MD_CRC32_RFC1510, "\x00\x00\x00\x01", "\x77\x07\x30\x96" },
#endif
{ GCRY_MD_CRC24_RFC2440, "", "\xb7\x04\xce" },
{ GCRY_MD_CRC24_RFC2440, "foo", "\x4f\xc2\x55" },
{ GCRY_MD_TIGER, "",
"\x24\xF0\x13\x0C\x63\xAC\x93\x32\x16\x16\x6E\x76"
"\xB1\xBB\x92\x5F\xF3\x73\xDE\x2D\x49\x58\x4E\x7A" },
{ GCRY_MD_TIGER, "abc",
"\xF2\x58\xC1\xE8\x84\x14\xAB\x2A\x52\x7A\xB5\x41"
"\xFF\xC5\xB8\xBF\x93\x5F\x7B\x95\x1C\x13\x29\x51" },
{ GCRY_MD_TIGER, "Tiger",
"\x9F\x00\xF5\x99\x07\x23\x00\xDD\x27\x6A\xBB\x38"
"\xC8\xEB\x6D\xEC\x37\x79\x0C\x11\x6F\x9D\x2B\xDF" },
{ GCRY_MD_TIGER, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg"
"hijklmnopqrstuvwxyz0123456789+-",
"\x87\xFB\x2A\x90\x83\x85\x1C\xF7\x47\x0D\x2C\xF8"
"\x10\xE6\xDF\x9E\xB5\x86\x44\x50\x34\xA5\xA3\x86" },
{ GCRY_MD_TIGER, "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdef"
"ghijklmnopqrstuvwxyz+0123456789",
"\x46\x7D\xB8\x08\x63\xEB\xCE\x48\x8D\xF1\xCD\x12"
"\x61\x65\x5D\xE9\x57\x89\x65\x65\x97\x5F\x91\x97" },
{ GCRY_MD_TIGER, "Tiger - A Fast New Hash Function, "
"by Ross Anderson and Eli Biham",
"\x0C\x41\x0A\x04\x29\x68\x86\x8A\x16\x71\xDA\x5A"
"\x3F\xD2\x9A\x72\x5E\xC1\xE4\x57\xD3\xCD\xB3\x03" },
{ GCRY_MD_TIGER, "Tiger - A Fast New Hash Function, "
"by Ross Anderson and Eli Biham, proceedings of Fa"
"st Software Encryption 3, Cambridge.",
"\xEB\xF5\x91\xD5\xAF\xA6\x55\xCE\x7F\x22\x89\x4F"
"\xF8\x7F\x54\xAC\x89\xC8\x11\xB6\xB0\xDA\x31\x93" },
{ GCRY_MD_TIGER, "Tiger - A Fast New Hash Function, "
"by Ross Anderson and Eli Biham, proceedings of Fa"
"st Software Encryption 3, Cambridge, 1996.",
"\x3D\x9A\xEB\x03\xD1\xBD\x1A\x63\x57\xB2\x77\x4D"
"\xFD\x6D\x5B\x24\xDD\x68\x15\x1D\x50\x39\x74\xFC" },
{ GCRY_MD_TIGER, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefgh"
"ijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRS"
"TUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
"\x00\xB8\x3E\xB4\xE5\x34\x40\xC5\x76\xAC\x6A\xAE"
"\xE0\xA7\x48\x58\x25\xFD\x15\xE7\x0A\x59\xFF\xE4" },
{ GCRY_MD_TIGER1, "",
"\x32\x93\xAC\x63\x0C\x13\xF0\x24\x5F\x92\xBB\xB1"
"\x76\x6E\x16\x16\x7A\x4E\x58\x49\x2D\xDE\x73\xF3" },
{ GCRY_MD_TIGER1, "a",
"\x77\xBE\xFB\xEF\x2E\x7E\xF8\xAB\x2E\xC8\xF9\x3B"
"\xF5\x87\xA7\xFC\x61\x3E\x24\x7F\x5F\x24\x78\x09" },
{ GCRY_MD_TIGER1, "abc",
"\x2A\xAB\x14\x84\xE8\xC1\x58\xF2\xBF\xB8\xC5\xFF"
"\x41\xB5\x7A\x52\x51\x29\x13\x1C\x95\x7B\x5F\x93" },
{ GCRY_MD_TIGER1, "message digest",
"\xD9\x81\xF8\xCB\x78\x20\x1A\x95\x0D\xCF\x30\x48"
"\x75\x1E\x44\x1C\x51\x7F\xCA\x1A\xA5\x5A\x29\xF6" },
{ GCRY_MD_TIGER1, "abcdefghijklmnopqrstuvwxyz",
"\x17\x14\xA4\x72\xEE\xE5\x7D\x30\x04\x04\x12\xBF"
"\xCC\x55\x03\x2A\x0B\x11\x60\x2F\xF3\x7B\xEE\xE9" },
{ GCRY_MD_TIGER1,
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"\x0F\x7B\xF9\xA1\x9B\x9C\x58\xF2\xB7\x61\x0D\xF7"
"\xE8\x4F\x0A\xC3\xA7\x1C\x63\x1E\x7B\x53\xF7\x8E" },
{ GCRY_MD_TIGER1,
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz" "0123456789",
"\x8D\xCE\xA6\x80\xA1\x75\x83\xEE\x50\x2B\xA3\x8A"
"\x3C\x36\x86\x51\x89\x0F\xFB\xCC\xDC\x49\xA8\xCC" },
{ GCRY_MD_TIGER1,
"1234567890" "1234567890" "1234567890" "1234567890"
"1234567890" "1234567890" "1234567890" "1234567890",
"\x1C\x14\x79\x55\x29\xFD\x9F\x20\x7A\x95\x8F\x84"
"\xC5\x2F\x11\xE8\x87\xFA\x0C\xAB\xDF\xD9\x1B\xFD" },
{ GCRY_MD_TIGER1, "!",
"\x6D\xB0\xE2\x72\x9C\xBE\xAD\x93\xD7\x15\xC6\xA7"
"\xD3\x63\x02\xE9\xB3\xCE\xE0\xD2\xBC\x31\x4B\x41" },
{ GCRY_MD_TIGER2, "",
"\x44\x41\xBE\x75\xF6\x01\x87\x73\xC2\x06\xC2\x27"
"\x45\x37\x4B\x92\x4A\xA8\x31\x3F\xEF\x91\x9F\x41" },
{ GCRY_MD_TIGER2, "a",
"\x67\xE6\xAE\x8E\x9E\x96\x89\x99\xF7\x0A\x23\xE7"
"\x2A\xEA\xA9\x25\x1C\xBC\x7C\x78\xA7\x91\x66\x36" },
{ GCRY_MD_TIGER2, "abc",
"\xF6\x8D\x7B\xC5\xAF\x4B\x43\xA0\x6E\x04\x8D\x78"
"\x29\x56\x0D\x4A\x94\x15\x65\x8B\xB0\xB1\xF3\xBF" },
{ GCRY_MD_TIGER2, "message digest",
"\xE2\x94\x19\xA1\xB5\xFA\x25\x9D\xE8\x00\x5E\x7D"
"\xE7\x50\x78\xEA\x81\xA5\x42\xEF\x25\x52\x46\x2D" },
{ GCRY_MD_TIGER2, "abcdefghijklmnopqrstuvwxyz",
"\xF5\xB6\xB6\xA7\x8C\x40\x5C\x85\x47\xE9\x1C\xD8"
"\x62\x4C\xB8\xBE\x83\xFC\x80\x4A\x47\x44\x88\xFD" },
{ GCRY_MD_TIGER2,
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"\xA6\x73\x7F\x39\x97\xE8\xFB\xB6\x3D\x20\xD2\xDF"
"\x88\xF8\x63\x76\xB5\xFE\x2D\x5C\xE3\x66\x46\xA9" },
{ GCRY_MD_TIGER2,
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz" "0123456789",
"\xEA\x9A\xB6\x22\x8C\xEE\x7B\x51\xB7\x75\x44\xFC"
"\xA6\x06\x6C\x8C\xBB\x5B\xBA\xE6\x31\x95\x05\xCD" },
{ GCRY_MD_TIGER2,
"1234567890" "1234567890" "1234567890" "1234567890"
"1234567890" "1234567890" "1234567890" "1234567890",
"\xD8\x52\x78\x11\x53\x29\xEB\xAA\x0E\xEC\x85\xEC"
"\xDC\x53\x96\xFD\xA8\xAA\x3A\x58\x20\x94\x2F\xFF" },
{ GCRY_MD_TIGER2, "!",
"\xE0\x68\x28\x1F\x06\x0F\x55\x16\x28\xCC\x57\x15"
"\xB9\xD0\x22\x67\x96\x91\x4D\x45\xF7\x71\x7C\xF4" },
{ GCRY_MD_WHIRLPOOL, "",
"\x19\xFA\x61\xD7\x55\x22\xA4\x66\x9B\x44\xE3\x9C\x1D\x2E\x17\x26"
"\xC5\x30\x23\x21\x30\xD4\x07\xF8\x9A\xFE\xE0\x96\x49\x97\xF7\xA7"
"\x3E\x83\xBE\x69\x8B\x28\x8F\xEB\xCF\x88\xE3\xE0\x3C\x4F\x07\x57"
"\xEA\x89\x64\xE5\x9B\x63\xD9\x37\x08\xB1\x38\xCC\x42\xA6\x6E\xB3" },
{ GCRY_MD_WHIRLPOOL, "a",
"\x8A\xCA\x26\x02\x79\x2A\xEC\x6F\x11\xA6\x72\x06\x53\x1F\xB7\xD7"
"\xF0\xDF\xF5\x94\x13\x14\x5E\x69\x73\xC4\x50\x01\xD0\x08\x7B\x42"
"\xD1\x1B\xC6\x45\x41\x3A\xEF\xF6\x3A\x42\x39\x1A\x39\x14\x5A\x59"
"\x1A\x92\x20\x0D\x56\x01\x95\xE5\x3B\x47\x85\x84\xFD\xAE\x23\x1A" },
{ GCRY_MD_WHIRLPOOL, "a",
"\x8A\xCA\x26\x02\x79\x2A\xEC\x6F\x11\xA6\x72\x06\x53\x1F\xB7\xD7"
"\xF0\xDF\xF5\x94\x13\x14\x5E\x69\x73\xC4\x50\x01\xD0\x08\x7B\x42"
"\xD1\x1B\xC6\x45\x41\x3A\xEF\xF6\x3A\x42\x39\x1A\x39\x14\x5A\x59"
"\x1A\x92\x20\x0D\x56\x01\x95\xE5\x3B\x47\x85\x84\xFD\xAE\x23\x1A" },
{ GCRY_MD_WHIRLPOOL,
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
"\xDC\x37\xE0\x08\xCF\x9E\xE6\x9B\xF1\x1F\x00\xED\x9A\xBA\x26\x90"
"\x1D\xD7\xC2\x8C\xDE\xC0\x66\xCC\x6A\xF4\x2E\x40\xF8\x2F\x3A\x1E"
"\x08\xEB\xA2\x66\x29\x12\x9D\x8F\xB7\xCB\x57\x21\x1B\x92\x81\xA6"
"\x55\x17\xCC\x87\x9D\x7B\x96\x21\x42\xC6\x5F\x5A\x7A\xF0\x14\x67" },
{ GCRY_MD_WHIRLPOOL,
"!",
"\x0C\x99\x00\x5B\xEB\x57\xEF\xF5\x0A\x7C\xF0\x05\x56\x0D\xDF\x5D"
"\x29\x05\x7F\xD8\x6B\x20\xBF\xD6\x2D\xEC\xA0\xF1\xCC\xEA\x4A\xF5"
"\x1F\xC1\x54\x90\xED\xDC\x47\xAF\x32\xBB\x2B\x66\xC3\x4F\xF9\xAD"
"\x8C\x60\x08\xAD\x67\x7F\x77\x12\x69\x53\xB2\x26\xE4\xED\x8B\x01" },
{ 0 },
};
int i;
if (verbose)
fprintf (stderr, "Starting hash checks.\n");
for (i = 0; algos[i].md; i++)
{
if ((gcry_md_test_algo (algos[i].md) || algos[i].md == GCRY_MD_MD5)
&& in_fips_mode)
{
if (verbose)
fprintf (stderr, " algorithm %d not available in fips mode\n",
algos[i].md);
continue;
}
if (verbose)
fprintf (stderr, " checking %s [%i] for length %zi\n",
gcry_md_algo_name (algos[i].md),
algos[i].md,
!strcmp (algos[i].data, "!")?
1000000 : strlen(algos[i].data));
check_one_md (algos[i].md, algos[i].data, strlen (algos[i].data),
algos[i].expect);
}
if (verbose)
fprintf (stderr, "Completed hash checks.\n");
}
static void
check_one_hmac (int algo, const char *data, int datalen,
const char *key, int keylen, const char *expect)
{
gcry_md_hd_t hd, hd2;
unsigned char *p;
int mdlen;
int i;
gcry_error_t err = 0;
err = gcry_md_open (&hd, algo, GCRY_MD_FLAG_HMAC);
if (err)
{
fail ("algo %d, gcry_md_open failed: %s\n", algo, gpg_strerror (err));
return;
}
mdlen = gcry_md_get_algo_dlen (algo);
if (mdlen < 1 || mdlen > 500)
{
fail ("algo %d, gcry_md_get_algo_dlen failed: %d\n", algo, mdlen);
return;
}
gcry_md_setkey( hd, key, keylen );
gcry_md_write (hd, data, datalen);
err = gcry_md_copy (&hd2, hd);
if (err)
{
fail ("algo %d, gcry_md_copy failed: %s\n", algo, gpg_strerror (err));
}
gcry_md_close (hd);
p = gcry_md_read (hd2, algo);
if (!p)
fail("algo %d, hmac gcry_md_read failed\n", algo);
if (memcmp (p, expect, mdlen))
{
printf ("computed: ");
for (i = 0; i < mdlen; i++)
printf ("%02x ", p[i] & 0xFF);
printf ("\nexpected: ");
for (i = 0; i < mdlen; i++)
printf ("%02x ", expect[i] & 0xFF);
printf ("\n");
fail ("algo %d, digest mismatch\n", algo);
}
gcry_md_close (hd2);
}
static void
check_hmac (void)
{
static struct algos
{
int md;
const char *data;
const char *key;
const char *expect;
} algos[] =
{
{ GCRY_MD_MD5, "what do ya want for nothing?", "Jefe",
"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38" },
{ GCRY_MD_MD5,
"Hi There",
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
"\x92\x94\x72\x7a\x36\x38\xbb\x1c\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d" },
{ GCRY_MD_MD5,
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd",
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
"\x56\xbe\x34\x52\x1d\x14\x4c\x88\xdb\xb8\xc7\x33\xf0\xe8\xb3\xf6" },
{ GCRY_MD_MD5,
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd",
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
"\x69\x7e\xaf\x0a\xca\x3a\x3a\xea\x3a\x75\x16\x47\x46\xff\xaa\x79" },
{ GCRY_MD_MD5, "Test With Truncation",
"\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
"\x56\x46\x1e\xf2\x34\x2e\xdc\x00\xf9\xba\xb9\x95\x69\x0e\xfd\x4c" },
{ GCRY_MD_MD5, "Test Using Larger Than Block-Size Key - Hash Key First",
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa",
"\x6b\x1a\xb7\xfe\x4b\xd7\xbf\x8f\x0b\x62\xe6\xce\x61\xb9\xd0\xcd" },
{ GCRY_MD_MD5,
"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa",
"\x6f\x63\x0f\xad\x67\xcd\xa0\xee\x1f\xb1\xf5\x62\xdb\x3a\xa5\x3e", },
{ GCRY_MD_SHA256, "what do ya want for nothing?", "Jefe",
"\x5b\xdc\xc1\x46\xbf\x60\x75\x4e\x6a\x04\x24\x26\x08\x95\x75\xc7\x5a"
"\x00\x3f\x08\x9d\x27\x39\x83\x9d\xec\x58\xb9\x64\xec\x38\x43" },
{ GCRY_MD_SHA256,
"Hi There",
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
"\x0b\x0b\x0b",
"\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf\x0b\xf1\x2b\x88"
"\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9\x37\x6c\x2e\x32\xcf\xf7" },
{ GCRY_MD_SHA256,
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd",
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
"\xAA\xAA\xAA\xAA",
"\x77\x3e\xa9\x1e\x36\x80\x0e\x46\x85\x4d\xb8\xeb\xd0\x91\x81\xa7"
"\x29\x59\x09\x8b\x3e\xf8\xc1\x22\xd9\x63\x55\x14\xce\xd5\x65\xfe" },
{ GCRY_MD_SHA256,
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd",
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
"\x82\x55\x8a\x38\x9a\x44\x3c\x0e\xa4\xcc\x81\x98\x99\xf2\x08"
"\x3a\x85\xf0\xfa\xa3\xe5\x78\xf8\x07\x7a\x2e\x3f\xf4\x67\x29\x66\x5b" },
{ GCRY_MD_SHA256,
"Test Using Larger Than Block-Size Key - Hash Key First",
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa",
"\x60\xe4\x31\x59\x1e\xe0\xb6\x7f\x0d\x8a\x26\xaa\xcb\xf5\xb7\x7f"
"\x8e\x0b\xc6\x21\x37\x28\xc5\x14\x05\x46\x04\x0f\x0e\xe3\x7f\x54" },
{ GCRY_MD_SHA256,
"This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa",
"\x9b\x09\xff\xa7\x1b\x94\x2f\xcb\x27\x63\x5f\xbc\xd5\xb0\xe9\x44"
"\xbf\xdc\x63\x64\x4f\x07\x13\x93\x8a\x7f\x51\x53\x5c\x3a\x35\xe2" },
{ GCRY_MD_SHA224, "what do ya want for nothing?", "Jefe",
"\xa3\x0e\x01\x09\x8b\xc6\xdb\xbf\x45\x69\x0f\x3a\x7e\x9e\x6d\x0f"
"\x8b\xbe\xa2\xa3\x9e\x61\x48\x00\x8f\xd0\x5e\x44" },
{ GCRY_MD_SHA224,
"Hi There",
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
"\x0b\x0b\x0b",
"\x89\x6f\xb1\x12\x8a\xbb\xdf\x19\x68\x32\x10\x7c\xd4\x9d\xf3\x3f\x47"
"\xb4\xb1\x16\x99\x12\xba\x4f\x53\x68\x4b\x22" },
{ GCRY_MD_SHA224,
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd",
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
"\xAA\xAA\xAA\xAA",
"\x7f\xb3\xcb\x35\x88\xc6\xc1\xf6\xff\xa9\x69\x4d\x7d\x6a\xd2\x64"
"\x93\x65\xb0\xc1\xf6\x5d\x69\xd1\xec\x83\x33\xea" },
{ GCRY_MD_SHA224,
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd",
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
"\x6c\x11\x50\x68\x74\x01\x3c\xac\x6a\x2a\xbc\x1b\xb3\x82\x62"
"\x7c\xec\x6a\x90\xd8\x6e\xfc\x01\x2d\xe7\xaf\xec\x5a" },
{ GCRY_MD_SHA224,
"Test Using Larger Than Block-Size Key - Hash Key First",
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa",
"\x95\xe9\xa0\xdb\x96\x20\x95\xad\xae\xbe\x9b\x2d\x6f\x0d\xbc\xe2"
"\xd4\x99\xf1\x12\xf2\xd2\xb7\x27\x3f\xa6\x87\x0e" },
{ GCRY_MD_SHA224,
"This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa",
"\x3a\x85\x41\x66\xac\x5d\x9f\x02\x3f\x54\xd5\x17\xd0\xb3\x9d\xbd"
"\x94\x67\x70\xdb\x9c\x2b\x95\xc9\xf6\xf5\x65\xd1" },
{ GCRY_MD_SHA384, "what do ya want for nothing?", "Jefe",
"\xaf\x45\xd2\xe3\x76\x48\x40\x31\x61\x7f\x78\xd2\xb5\x8a\x6b\x1b"
"\x9c\x7e\xf4\x64\xf5\xa0\x1b\x47\xe4\x2e\xc3\x73\x63\x22\x44\x5e"
"\x8e\x22\x40\xca\x5e\x69\xe2\xc7\x8b\x32\x39\xec\xfa\xb2\x16\x49" },
{ GCRY_MD_SHA384,
"Hi There",
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
"\x0b\x0b\x0b",
"\xaf\xd0\x39\x44\xd8\x48\x95\x62\x6b\x08\x25\xf4\xab\x46\x90\x7f\x15"
"\xf9\xda\xdb\xe4\x10\x1e\xc6\x82\xaa\x03\x4c\x7c\xeb\xc5\x9c\xfa\xea"
"\x9e\xa9\x07\x6e\xde\x7f\x4a\xf1\x52\xe8\xb2\xfa\x9c\xb6" },
{ GCRY_MD_SHA384,
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd",
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
"\xAA\xAA\xAA\xAA",
"\x88\x06\x26\x08\xd3\xe6\xad\x8a\x0a\xa2\xac\xe0\x14\xc8\xa8\x6f"
"\x0a\xa6\x35\xd9\x47\xac\x9f\xeb\xe8\x3e\xf4\xe5\x59\x66\x14\x4b"
"\x2a\x5a\xb3\x9d\xc1\x38\x14\xb9\x4e\x3a\xb6\xe1\x01\xa3\x4f\x27" },
{ GCRY_MD_SHA384,
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd",
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
"\x3e\x8a\x69\xb7\x78\x3c\x25\x85\x19\x33\xab\x62\x90\xaf\x6c\xa7"
"\x7a\x99\x81\x48\x08\x50\x00\x9c\xc5\x57\x7c\x6e\x1f\x57\x3b\x4e"
"\x68\x01\xdd\x23\xc4\xa7\xd6\x79\xcc\xf8\xa3\x86\xc6\x74\xcf\xfb" },
{ GCRY_MD_SHA384,
"Test Using Larger Than Block-Size Key - Hash Key First",
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa",
"\x4e\xce\x08\x44\x85\x81\x3e\x90\x88\xd2\xc6\x3a\x04\x1b\xc5\xb4"
"\x4f\x9e\xf1\x01\x2a\x2b\x58\x8f\x3c\xd1\x1f\x05\x03\x3a\xc4\xc6"
"\x0c\x2e\xf6\xab\x40\x30\xfe\x82\x96\x24\x8d\xf1\x63\xf4\x49\x52" },
{ GCRY_MD_SHA384,
"This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa",
"\x66\x17\x17\x8e\x94\x1f\x02\x0d\x35\x1e\x2f\x25\x4e\x8f\xd3\x2c"
"\x60\x24\x20\xfe\xb0\xb8\xfb\x9a\xdc\xce\xbb\x82\x46\x1e\x99\xc5"
"\xa6\x78\xcc\x31\xe7\x99\x17\x6d\x38\x60\xe6\x11\x0c\x46\x52\x3e" },
{ GCRY_MD_SHA512, "what do ya want for nothing?", "Jefe",
"\x16\x4b\x7a\x7b\xfc\xf8\x19\xe2\xe3\x95\xfb\xe7\x3b\x56\xe0\xa3"
"\x87\xbd\x64\x22\x2e\x83\x1f\xd6\x10\x27\x0c\xd7\xea\x25\x05\x54"
"\x97\x58\xbf\x75\xc0\x5a\x99\x4a\x6d\x03\x4f\x65\xf8\xf0\xe6\xfd"
"\xca\xea\xb1\xa3\x4d\x4a\x6b\x4b\x63\x6e\x07\x0a\x38\xbc\xe7\x37" },
{ GCRY_MD_SHA512,
"Hi There",
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
"\x0b\x0b\x0b",
"\x87\xaa\x7c\xde\xa5\xef\x61\x9d\x4f\xf0\xb4\x24\x1a\x1d\x6c\xb0"
"\x23\x79\xf4\xe2\xce\x4e\xc2\x78\x7a\xd0\xb3\x05\x45\xe1\x7c\xde"
"\xda\xa8\x33\xb7\xd6\xb8\xa7\x02\x03\x8b\x27\x4e\xae\xa3\xf4\xe4"
"\xbe\x9d\x91\x4e\xeb\x61\xf1\x70\x2e\x69\x6c\x20\x3a\x12\x68\x54" },
{ GCRY_MD_SHA512,
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
"\xdd\xdd\xdd\xdd\xdd",
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
"\xAA\xAA\xAA\xAA",
"\xfa\x73\xb0\x08\x9d\x56\xa2\x84\xef\xb0\xf0\x75\x6c\x89\x0b\xe9"
"\xb1\xb5\xdb\xdd\x8e\xe8\x1a\x36\x55\xf8\x3e\x33\xb2\x27\x9d\x39"
"\xbf\x3e\x84\x82\x79\xa7\x22\xc8\x06\xb4\x85\xa4\x7e\x67\xc8\x07"
"\xb9\x46\xa3\x37\xbe\xe8\x94\x26\x74\x27\x88\x59\xe1\x32\x92\xfb" },
{ GCRY_MD_SHA512,
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
"\xcd\xcd\xcd\xcd\xcd",
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
"\xb0\xba\x46\x56\x37\x45\x8c\x69\x90\xe5\xa8\xc5\xf6\x1d\x4a\xf7"
"\xe5\x76\xd9\x7f\xf9\x4b\x87\x2d\xe7\x6f\x80\x50\x36\x1e\xe3\xdb"
"\xa9\x1c\xa5\xc1\x1a\xa2\x5e\xb4\xd6\x79\x27\x5c\xc5\x78\x80\x63"
"\xa5\xf1\x97\x41\x12\x0c\x4f\x2d\xe2\xad\xeb\xeb\x10\xa2\x98\xdd" },
{ GCRY_MD_SHA512,
"Test Using Larger Than Block-Size Key - Hash Key First",
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa",
"\x80\xb2\x42\x63\xc7\xc1\xa3\xeb\xb7\x14\x93\xc1\xdd\x7b\xe8\xb4"
"\x9b\x46\xd1\xf4\x1b\x4a\xee\xc1\x12\x1b\x01\x37\x83\xf8\xf3\x52"
"\x6b\x56\xd0\x37\xe0\x5f\x25\x98\xbd\x0f\xd2\x21\x5d\x6a\x1e\x52"
"\x95\xe6\x4f\x73\xf6\x3f\x0a\xec\x8b\x91\x5a\x98\x5d\x78\x65\x98" },
{ GCRY_MD_SHA512,
"This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa",
"\xe3\x7b\x6a\x77\x5d\xc8\x7d\xba\xa4\xdf\xa9\xf9\x6e\x5e\x3f\xfd"
"\xde\xbd\x71\xf8\x86\x72\x89\x86\x5d\xf5\xa3\x2d\x20\xcd\xc9\x44"
"\xb6\x02\x2c\xac\x3c\x49\x82\xb1\x0d\x5e\xeb\x55\xc3\xe4\xde\x15"
"\x13\x46\x76\xfb\x6d\xe0\x44\x60\x65\xc9\x74\x40\xfa\x8c\x6a\x58" },
{ 0 },
};
int i;
if (verbose)
fprintf (stderr, "Starting hashed MAC checks.\n");
for (i = 0; algos[i].md; i++)
{
if ((gcry_md_test_algo (algos[i].md) || algos[i].md == GCRY_MD_MD5)
&& in_fips_mode)
{
if (verbose)
fprintf (stderr, " algorithm %d not available in fips mode\n",
algos[i].md);
continue;
}
if (verbose)
fprintf (stderr,
" checking %s [%i] for %zi byte key and %zi byte data\n",
gcry_md_algo_name (algos[i].md),
algos[i].md,
strlen(algos[i].key), strlen(algos[i].data));
check_one_hmac (algos[i].md, algos[i].data, strlen (algos[i].data),
algos[i].key, strlen(algos[i].key),
algos[i].expect);
}
if (verbose)
fprintf (stderr, "Completed hashed MAC checks.\n");
}
/* Check that the signature SIG matches the hash HASH. PKEY is the
public key used for the verification. BADHASH is a hash value which
should result in a bad signature status. */
static void
verify_one_signature (gcry_sexp_t pkey, gcry_sexp_t hash,
gcry_sexp_t badhash, gcry_sexp_t sig)
{
gcry_error_t rc;
rc = gcry_pk_verify (sig, hash, pkey);
if (rc)
fail ("gcry_pk_verify failed: %s\n", gpg_strerror (rc));
rc = gcry_pk_verify (sig, badhash, pkey);
if (gcry_err_code (rc) != GPG_ERR_BAD_SIGNATURE)
fail ("gcry_pk_verify failed to detect a bad signature: %s\n",
gpg_strerror (rc));
}
/* Test the public key sign function using the private ket SKEY. PKEY
is used for verification. */
static void
check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo)
{
gcry_error_t rc;
gcry_sexp_t sig, badhash, hash;
int dataidx;
static const char baddata[] =
"(data\n (flags pkcs1)\n"
" (hash sha1 #11223344556677889900AABBCCDDEEFF10203041#))\n";
static struct
{
const char *data;
int algo;
int expected_rc;
} datas[] =
{
{ "(data\n (flags pkcs1)\n"
" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
GCRY_PK_RSA,
0 },
{ "(data\n (flags oaep)\n"
" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
0,
GPG_ERR_CONFLICT },
/* This test is to see whether hash algorithms not hard wired in
pubkey.c are detected: */
{ "(data\n (flags pkcs1)\n"
" (hash oid.1.3.14.3.2.29 "
" #11223344556677889900AABBCCDDEEFF10203040#))\n",
GCRY_PK_RSA,
0 },
{ "(data\n (flags )\n"
" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
0,
GPG_ERR_CONFLICT },
{ "(data\n (flags pkcs1)\n"
" (hash foo #11223344556677889900AABBCCDDEEFF10203040#))\n",
GCRY_PK_RSA,
GPG_ERR_DIGEST_ALGO },
{ "(data\n (flags )\n" " (value #11223344556677889900AA#))\n",
0,
0 },
{ "(data\n (flags )\n" " (value #0090223344556677889900AA#))\n",
0,
0 },
{ "(data\n (flags raw)\n" " (value #11223344556677889900AA#))\n",
0,
0 },
{ "(data\n (flags pkcs1)\n"
" (value #11223344556677889900AA#))\n",
GCRY_PK_RSA,
GPG_ERR_CONFLICT },
{ "(data\n (flags raw foo)\n"
" (value #11223344556677889900AA#))\n",
0,
GPG_ERR_INV_FLAG },
{ "(data\n (flags pss)\n"
" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
GCRY_PK_RSA,
0 },
{ "(data\n (flags pss)\n"
" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#)\n"
" (random-override #4253647587980912233445566778899019283747#))\n",
GCRY_PK_RSA,
0 },
{ NULL }
};
rc = gcry_sexp_sscan (&badhash, NULL, baddata, strlen (baddata));
if (rc)
die ("converting data failed: %s\n", gpg_strerror (rc));
for (dataidx = 0; datas[dataidx].data; dataidx++)
{
if (datas[dataidx].algo && datas[dataidx].algo != algo)
continue;
if (verbose)
fprintf (stderr, " test %d, signature test %d\n", n, dataidx);
rc = gcry_sexp_sscan (&hash, NULL, datas[dataidx].data,
strlen (datas[dataidx].data));
if (rc)
die ("converting data failed: %s\n", gpg_strerror (rc));
rc = gcry_pk_sign (&sig, hash, skey);
if (gcry_err_code (rc) != datas[dataidx].expected_rc)
fail ("gcry_pk_sign failed: %s\n", gpg_strerror (rc));
if (!rc)
verify_one_signature (pkey, hash, badhash, sig);
gcry_sexp_release (sig);
sig = NULL;
gcry_sexp_release (hash);
hash = NULL;
}
gcry_sexp_release (badhash);
}
/* Test the public key sign function using the private ket SKEY. PKEY
is used for verification. This variant is only used for ECDSA. */
static void
check_pubkey_sign_ecdsa (int n, gcry_sexp_t skey, gcry_sexp_t pkey)
{
gcry_error_t rc;
gcry_sexp_t sig, badhash, hash;
unsigned int nbits;
int dataidx;
static struct
{
unsigned int nbits;
const char *data;
int expected_rc;
const char *baddata;
int dummy;
} datas[] =
{
+ { 192,
+ "(data (flags raw)\n"
+ " (value #00112233445566778899AABBCCDDEEFF0001020304050607#))",
+ 0,
+ "(data (flags raw)\n"
+ " (value #80112233445566778899AABBCCDDEEFF0001020304050607#))",
+ 0
+ },
{ 256,
"(data (flags raw)\n"
" (value #00112233445566778899AABBCCDDEEFF"
/* */ "000102030405060708090A0B0C0D0E0F#))",
0,
"(data (flags raw)\n"
" (value #80112233445566778899AABBCCDDEEFF"
/* */ "000102030405060708090A0B0C0D0E0F#))",
0
},
- { 192,
+ { 256,
"(data (flags raw)\n"
- " (value #00112233445566778899AABBCCDDEEFF0001020304050607#))",
+ " (hash sha256 #00112233445566778899AABBCCDDEEFF"
+ /* */ "000102030405060708090A0B0C0D0E0F#))",
0,
"(data (flags raw)\n"
- " (value #80112233445566778899AABBCCDDEEFF0001020304050607#))",
+ " (hash sha256 #80112233445566778899AABBCCDDEEFF"
+ /* */ "000102030405060708090A0B0C0D0E0F#))",
0
},
{ 0, NULL }
};
nbits = gcry_pk_get_nbits (skey);
for (dataidx = 0; datas[dataidx].data; dataidx++)
{
if (datas[dataidx].nbits != nbits)
continue;
if (verbose)
fprintf (stderr, " test %d, signature test %d (%u bit ecdsa)\n",
n, dataidx, nbits);
rc = gcry_sexp_sscan (&hash, NULL, datas[dataidx].data,
strlen (datas[dataidx].data));
if (rc)
die ("converting data failed: %s\n", gpg_strerror (rc));
rc = gcry_sexp_sscan (&badhash, NULL, datas[dataidx].baddata,
strlen (datas[dataidx].baddata));
if (rc)
die ("converting data failed: %s\n", gpg_strerror (rc));
rc = gcry_pk_sign (&sig, hash, skey);
if (gcry_err_code (rc) != datas[dataidx].expected_rc)
fail ("gcry_pk_sign failed: %s\n", gpg_strerror (rc));
if (!rc && verbose > 1)
show_sexp ("ECDSA signature:\n", sig);
if (!rc)
verify_one_signature (pkey, hash, badhash, sig);
gcry_sexp_release (sig);
sig = NULL;
gcry_sexp_release (badhash);
badhash = NULL;
gcry_sexp_release (hash);
hash = NULL;
}
}
static void
check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo)
{
gcry_error_t rc;
gcry_sexp_t plain, ciph, data;
int dataidx;
static struct
{
int algo; /* If not 0 run test only if ALGO matches. */
const char *data;
const char *hint;
int unpadded;
int encrypt_expected_rc;
int decrypt_expected_rc;
} datas[] =
{
{ GCRY_PK_RSA,
"(data\n (flags pkcs1)\n"
" (value #11223344556677889900AA#))\n",
NULL,
0,
0,
0 },
{ GCRY_PK_RSA,
"(data\n (flags pkcs1)\n"
" (value #11223344556677889900AA#))\n",
"(flags pkcs1)",
1,
0,
0 },
{ GCRY_PK_RSA,
"(data\n (flags oaep)\n"
" (value #11223344556677889900AA#))\n",
"(flags oaep)",
1,
0,
0 },
{ GCRY_PK_RSA,
"(data\n (flags oaep)\n (hash-algo sha1)\n"
" (value #11223344556677889900AA#))\n",
"(flags oaep)(hash-algo sha1)",
1,
0,
0 },
{ GCRY_PK_RSA,
"(data\n (flags oaep)\n (hash-algo sha1)\n (label \"test\")\n"
" (value #11223344556677889900AA#))\n",
"(flags oaep)(hash-algo sha1)(label \"test\")",
1,
0,
0 },
{ GCRY_PK_RSA,
"(data\n (flags oaep)\n (hash-algo sha1)\n (label \"test\")\n"
" (value #11223344556677889900AA#)\n"
" (random-override #4253647587980912233445566778899019283747#))\n",
"(flags oaep)(hash-algo sha1)(label \"test\")",
1,
0,
0 },
{ 0,
"(data\n (flags )\n" " (value #11223344556677889900AA#))\n",
NULL,
1,
0,
0 },
{ 0,
"(data\n (flags )\n" " (value #0090223344556677889900AA#))\n",
NULL,
1,
0,
0 },
{ 0,
"(data\n (flags raw)\n" " (value #11223344556677889900AA#))\n",
NULL,
1,
0,
0 },
{ GCRY_PK_RSA,
"(data\n (flags pkcs1)\n"
" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
NULL,
0,
GPG_ERR_CONFLICT,
0},
{ 0,
"(data\n (flags raw foo)\n"
" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
NULL,
0,
GPG_ERR_INV_FLAG,
0},
{ 0,
"(data\n (flags raw)\n"
" (value #11223344556677889900AA#))\n",
"(flags oaep)",
1,
0,
GPG_ERR_ENCODING_PROBLEM },
{ GCRY_PK_RSA,
"(data\n (flags oaep)\n"
" (value #11223344556677889900AA#))\n",
"(flags pkcs1)",
1,
0,
GPG_ERR_ENCODING_PROBLEM },
{ 0,
"(data\n (flags pss)\n"
" (value #11223344556677889900AA#))\n",
NULL,
0,
GPG_ERR_CONFLICT },
{ 0, NULL }
};
(void)n;
for (dataidx = 0; datas[dataidx].data; dataidx++)
{
if (datas[dataidx].algo && datas[dataidx].algo != algo)
continue;
if (verbose)
fprintf (stderr, " encryption/decryption test %d (algo %d)\n",
dataidx, algo);
rc = gcry_sexp_sscan (&data, NULL, datas[dataidx].data,
strlen (datas[dataidx].data));
if (rc)
die ("converting data failed: %s\n", gpg_strerror (rc));
rc = gcry_pk_encrypt (&ciph, data, pkey);
if (gcry_err_code (rc) != datas[dataidx].encrypt_expected_rc)
fail ("gcry_pk_encrypt failed: %s\n", gpg_strerror (rc));
if (!rc)
{
/* Insert decoding hint to CIPH. */
if (datas[dataidx].hint)
{
size_t hint_len, len;
char *hint, *buf;
gcry_sexp_t list;
/* Convert decoding hint into canonical sexp. */
hint_len = gcry_sexp_new (&list, datas[dataidx].hint,
strlen (datas[dataidx].hint), 1);
hint_len = gcry_sexp_sprint (list, GCRYSEXP_FMT_CANON, NULL, 0);
hint = gcry_malloc (hint_len);
if (!hint)
die ("can't allocate memory\n");
hint_len = gcry_sexp_sprint (list, GCRYSEXP_FMT_CANON, hint,
hint_len);
gcry_sexp_release (list);
/* Convert CIPH into canonical sexp. */
len = gcry_sexp_sprint (ciph, GCRYSEXP_FMT_CANON, NULL, 0);
buf = gcry_malloc (len + hint_len);
if (!buf)
die ("can't allocate memory\n");
len = gcry_sexp_sprint (ciph, GCRYSEXP_FMT_CANON, buf, len);
/* assert (!strcmp (buf, "(7:enc-val", 10)); */
/* Copy decoding hint into CIPH. */
memmove (buf + 10 + hint_len, buf + 10, len - 10);
memcpy (buf + 10, hint, hint_len);
gcry_free (hint);
gcry_sexp_new (&list, buf, len + hint_len, 1);
gcry_free (buf);
gcry_sexp_release (ciph);
ciph = list;
}
rc = gcry_pk_decrypt (&plain, ciph, skey);
if (gcry_err_code (rc) != datas[dataidx].decrypt_expected_rc)
fail ("gcry_pk_decrypt failed: %s\n", gpg_strerror (rc));
if (!rc && datas[dataidx].unpadded)
{
gcry_sexp_t p1, p2;
p1 = gcry_sexp_find_token (data, "value", 0);
p2 = gcry_sexp_find_token (plain, "value", 0);
if (p1 && p2)
{
const char *s1, *s2;
size_t n1, n2;
s1 = gcry_sexp_nth_data (p1, 1, &n1);
s2 = gcry_sexp_nth_data (p2, 1, &n2);
if (n1 != n2 || memcmp (s1, s2, n1))
fail ("gcry_pk_encrypt/gcry_pk_decrypt do not roundtrip\n");
}
gcry_sexp_release (p1);
gcry_sexp_release (p2);
}
}
gcry_sexp_release (plain);
plain = NULL;
gcry_sexp_release (ciph);
ciph = NULL;
gcry_sexp_release (data);
data = NULL;
}
}
static void
check_pubkey_grip (int n, const unsigned char *grip,
gcry_sexp_t skey, gcry_sexp_t pkey, int algo)
{
unsigned char sgrip[20], pgrip[20];
(void)algo;
if (!gcry_pk_get_keygrip (skey, sgrip))
die ("get keygrip for private RSA key failed\n");
if (!gcry_pk_get_keygrip (pkey, pgrip))
die ("[%i] get keygrip for public RSA key failed\n", n);
if (memcmp (sgrip, pgrip, 20))
fail ("[%i] keygrips don't match\n", n);
if (memcmp (sgrip, grip, 20))
fail ("wrong keygrip for RSA key\n");
}
static void
do_check_one_pubkey (int n, gcry_sexp_t skey, gcry_sexp_t pkey,
const unsigned char *grip, int algo, int flags)
{
if (flags & FLAG_SIGN)
{
if (algo == GCRY_PK_ECDSA)
check_pubkey_sign_ecdsa (n, skey, pkey);
else
check_pubkey_sign (n, skey, pkey, algo);
}
if (flags & FLAG_CRYPT)
check_pubkey_crypt (n, skey, pkey, algo);
if (grip && (flags & FLAG_GRIP))
check_pubkey_grip (n, grip, skey, pkey, algo);
}
static void
check_one_pubkey (int n, test_spec_pubkey_t spec)
{
gcry_error_t err = GPG_ERR_NO_ERROR;
gcry_sexp_t skey, pkey;
err = gcry_sexp_sscan (&skey, NULL, spec.key.secret,
strlen (spec.key.secret));
if (!err)
err = gcry_sexp_sscan (&pkey, NULL, spec.key.public,
strlen (spec.key.public));
if (err)
die ("converting sample key failed: %s\n", gpg_strerror (err));
do_check_one_pubkey (n, skey, pkey,
(const unsigned char*)spec.key.grip,
spec.id, spec.flags);
gcry_sexp_release (skey);
gcry_sexp_release (pkey);
}
static void
get_keys_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
{
gcry_sexp_t key_spec, key, pub_key, sec_key;
int rc;
if (verbose)
fprintf (stderr, " generating RSA key:");
rc = gcry_sexp_new (&key_spec,
in_fips_mode ? "(genkey (rsa (nbits 4:1024)))"
: "(genkey (rsa (nbits 4:1024)(transient-key)))",
0, 1);
if (rc)
die ("error creating S-expression: %s\n", gpg_strerror (rc));
rc = gcry_pk_genkey (&key, key_spec);
gcry_sexp_release (key_spec);
if (rc)
die ("error generating RSA key: %s\n", gpg_strerror (rc));
pub_key = gcry_sexp_find_token (key, "public-key", 0);
if (! pub_key)
die ("public part missing in key\n");
sec_key = gcry_sexp_find_token (key, "private-key", 0);
if (! sec_key)
die ("private part missing in key\n");
gcry_sexp_release (key);
*pkey = pub_key;
*skey = sec_key;
}
static void
check_one_pubkey_new (int n)
{
gcry_sexp_t skey, pkey;
get_keys_new (&pkey, &skey);
do_check_one_pubkey (n, skey, pkey, NULL,
GCRY_PK_RSA, FLAG_SIGN | FLAG_CRYPT);
gcry_sexp_release (pkey);
gcry_sexp_release (skey);
}
/* Run all tests for the public key functions. */
static void
check_pubkey (void)
{
test_spec_pubkey_t pubkeys[] = {
{
GCRY_PK_RSA, FLAG_CRYPT | FLAG_SIGN,
{
"(private-key\n"
" (rsa\n"
" (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa"
" 2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291"
" ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7"
" 891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea2"
" 51#)\n"
" (e #010001#)\n"
" (d #046129F2489D71579BE0A75FE029BD6CDB574EBF57EA8A5B0FDA942CAB943B11"
" 7D7BB95E5D28875E0F9FC5FCC06A72F6D502464DABDED78EF6B716177B83D5BD"
" C543DC5D3FED932E59F5897E92E6F58A0F33424106A3B6FA2CBF877510E4AC21"
" C3EE47851E97D12996222AC3566D4CCB0B83D164074ABF7DE655FC2446DA1781"
" #)\n"
" (p #00e861b700e17e8afe6837e7512e35b6ca11d0ae47d8b85161c67baf64377213"
" fe52d772f2035b3ca830af41d8a4120e1c1c70d12cc22f00d28d31dd48a8d424"
" f1#)\n"
" (q #00f7a7ca5367c661f8e62df34f0d05c10c88e5492348dd7bddc942c9a8f369f9"
" 35a07785d2db805215ed786e4285df1658eed3ce84f469b81b50d358407b4ad3"
" 61#)\n"
" (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e"
" ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b"
" #)))\n",
"(public-key\n"
" (rsa\n"
" (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa"
" 2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291"
" ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7"
" 891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea2"
" 51#)\n"
" (e #010001#)))\n",
"\x32\x10\x0c\x27\x17\x3e\xf6\xe9\xc4\xe9"
"\xa2\x5d\x3d\x69\xf8\x6d\x37\xa4\xf9\x39"}
},
{
GCRY_PK_DSA, FLAG_SIGN,
{
"(private-key\n"
" (DSA\n"
" (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB"
" 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191"
" CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44"
" 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D877"
" 7B#)\n"
" (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)\n"
" (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503"
" AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E"
" B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984"
" 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15"
" #)\n"
" (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46"
" A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827"
" 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20"
" 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB"
" #)\n"
" (x #11D54E4ADBD3034160F2CED4B7CD292A4EBF3EC0#)))\n",
"(public-key\n"
" (DSA\n"
" (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB"
" 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191"
" CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44"
" 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D877"
" 7B#)\n"
" (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)\n"
" (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503"
" AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E"
" B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984"
" 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15"
" #)\n"
" (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46"
" A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827"
" 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20"
" 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB"
" #)))\n",
"\xc6\x39\x83\x1a\x43\xe5\x05\x5d\xc6\xd8"
"\x4a\xa6\xf9\xeb\x23\xbf\xa9\x12\x2d\x5b" }
},
{
GCRY_PK_ELG, FLAG_SIGN | FLAG_CRYPT,
{
"(private-key\n"
" (ELG\n"
" (p #00B93B93386375F06C2D38560F3B9C6D6D7B7506B20C1773F73F8DE56E6CD65D"
" F48DFAAA1E93F57A2789B168362A0F787320499F0B2461D3A4268757A7B27517"
" B7D203654A0CD484DEC6AF60C85FEB84AAC382EAF2047061FE5DAB81A20A0797"
" 6E87359889BAE3B3600ED718BE61D4FC993CC8098A703DD0DC942E965E8F18D2"
" A7#)\n"
" (g #05#)\n"
" (y #72DAB3E83C9F7DD9A931FDECDC6522C0D36A6F0A0FEC955C5AC3C09175BBFF2B"
" E588DB593DC2E420201BEB3AC17536918417C497AC0F8657855380C1FCF11C5B"
" D20DB4BEE9BDF916648DE6D6E419FA446C513AAB81C30CB7B34D6007637BE675"
" 56CE6473E9F9EE9B9FADD275D001563336F2186F424DEC6199A0F758F6A00FF4"
" #)\n"
" (x #03C28900087B38DABF4A0AB98ACEA39BB674D6557096C01D72E31C16BDD32214"
" #)))\n",
"(public-key\n"
" (ELG\n"
" (p #00B93B93386375F06C2D38560F3B9C6D6D7B7506B20C1773F73F8DE56E6CD65D"
" F48DFAAA1E93F57A2789B168362A0F787320499F0B2461D3A4268757A7B27517"
" B7D203654A0CD484DEC6AF60C85FEB84AAC382EAF2047061FE5DAB81A20A0797"
" 6E87359889BAE3B3600ED718BE61D4FC993CC8098A703DD0DC942E965E8F18D2"
" A7#)\n"
" (g #05#)\n"
" (y #72DAB3E83C9F7DD9A931FDECDC6522C0D36A6F0A0FEC955C5AC3C09175BBFF2B"
" E588DB593DC2E420201BEB3AC17536918417C497AC0F8657855380C1FCF11C5B"
" D20DB4BEE9BDF916648DE6D6E419FA446C513AAB81C30CB7B34D6007637BE675"
" 56CE6473E9F9EE9B9FADD275D001563336F2186F424DEC6199A0F758F6A00FF4"
" #)))\n",
"\xa7\x99\x61\xeb\x88\x83\xd2\xf4\x05\xc8"
"\x4f\xba\x06\xf8\x78\x09\xbc\x1e\x20\xe5" }
},
{ /* ECDSA test. */
GCRY_PK_ECDSA, FLAG_SIGN,
{
"(private-key\n"
" (ecdsa\n"
" (curve nistp192)\n"
" (q #048532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE"
" C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966#)\n"
" (d #00D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D#)))\n",
"(public-key\n"
" (ecdsa\n"
" (curve nistp192)\n"
" (q #048532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE"
" C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966#)))\n",
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }
},
{ /* ECDSA test with the public key algorithm given as "ecc". */
GCRY_PK_ECDSA, FLAG_SIGN,
{
"(private-key\n"
" (ecdsa\n"
" (curve nistp192)\n"
" (q #048532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE"
" C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966#)\n"
" (d #00D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D#)))\n",
"(public-key\n"
" (ecc\n"
" (curve nistp192)\n"
" (q #048532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE"
" C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966#)))\n",
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }
},
{ /* ECDSA test with the private key algorithm given as "ecc". */
GCRY_PK_ECDSA, FLAG_SIGN,
{
"(private-key\n"
" (ecc\n"
" (curve nistp192)\n"
" (q #048532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE"
" C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966#)\n"
" (d #00D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D#)))\n",
"(public-key\n"
" (ecdsa\n"
" (curve nistp192)\n"
" (q #048532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE"
" C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966#)))\n",
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }
},
{ /* ECDSA test with the key algorithms given as "ecc". */
GCRY_PK_ECDSA, FLAG_SIGN,
{
"(private-key\n"
" (ecc\n"
" (curve nistp192)\n"
" (q #048532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE"
" C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966#)\n"
" (d #00D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D#)))\n",
"(public-key\n"
" (ecc\n"
" (curve nistp192)\n"
" (q #048532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE"
" C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966#)))\n",
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }
},
{ /* ECDSA test 256 bit. */
GCRY_PK_ECDSA, FLAG_SIGN,
{
"(private-key\n"
" (ecc\n"
" (curve nistp256)\n"
" (q #04D4F6A6738D9B8D3A7075C1E4EE95015FC0C9B7E4272D2B"
" EB6644D3609FC781B71F9A8072F58CB66AE2F89BB1245187"
" 3ABF7D91F9E1FBF96BF2F70E73AAC9A283#)\n"
" (d #5A1EF0035118F19F3110FB81813D3547BCE1E5BCE77D1F74"
" 4715E1D5BBE70378#)))\n",
"(public-key\n"
" (ecc\n"
" (curve nistp256)\n"
" (q #04D4F6A6738D9B8D3A7075C1E4EE95015FC0C9B7E4272D2B"
" EB6644D3609FC781B71F9A8072F58CB66AE2F89BB1245187"
" 3ABF7D91F9E1FBF96BF2F70E73AAC9A283#)))\n"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }
}
};
int i;
if (verbose)
fprintf (stderr, "Starting public key checks.\n");
for (i = 0; i < sizeof (pubkeys) / sizeof (*pubkeys); i++)
if (pubkeys[i].id)
{
if (gcry_pk_test_algo (pubkeys[i].id) && in_fips_mode)
{
if (verbose)
fprintf (stderr, " algorithm %d not available in fips mode\n",
pubkeys[i].id);
continue;
}
check_one_pubkey (i, pubkeys[i]);
}
if (verbose)
fprintf (stderr, "Completed public key checks.\n");
if (verbose)
fprintf (stderr, "Starting additional public key checks.\n");
for (i = 0; i < sizeof (pubkeys) / sizeof (*pubkeys); i++)
if (pubkeys[i].id)
{
if (gcry_pk_test_algo (pubkeys[i].id) && in_fips_mode)
{
if (verbose)
fprintf (stderr, " algorithm %d not available in fips mode\n",
pubkeys[i].id);
continue;
}
check_one_pubkey_new (i);
}
if (verbose)
fprintf (stderr, "Completed additional public key checks.\n");
}
int
main (int argc, char **argv)
{
gpg_error_t err;
int last_argc = -1;
int debug = 0;
int use_fips = 0;
int selftest_only = 0;
if (argc)
{ argc--; argv++; }
while (argc && last_argc != argc )
{
last_argc = argc;
if (!strcmp (*argv, "--"))
{
argc--; argv++;
break;
}
else if (!strcmp (*argv, "--verbose"))
{
verbose++;
argc--; argv++;
}
else if (!strcmp (*argv, "--debug"))
{
verbose = debug = 1;
argc--; argv++;
}
else if (!strcmp (*argv, "--fips"))
{
use_fips = 1;
argc--; argv++;
}
else if (!strcmp (*argv, "--selftest"))
{
selftest_only = 1;
verbose += 2;
argc--; argv++;
}
else if (!strcmp (*argv, "--die"))
{
die_on_error = 1;
argc--; argv++;
}
}
gcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
if (use_fips)
gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
/* Check that we test exactly our version - including the patchlevel. */
if (strcmp (GCRYPT_VERSION, gcry_check_version (NULL)))
die ("version mismatch; pgm=%s, library=%s\n",
GCRYPT_VERSION,gcry_check_version (NULL));
if ( gcry_fips_mode_active () )
in_fips_mode = 1;
if (!in_fips_mode)
gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
if (verbose)
gcry_set_progress_handler (progress_handler, NULL);
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
if (debug)
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
/* No valuable keys are create, so we can speed up our RNG. */
gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
if (!selftest_only)
{
check_ciphers ();
check_cipher_modes ();
check_bulk_cipher_modes ();
check_digests ();
check_hmac ();
check_pubkey ();
}
if (in_fips_mode && !selftest_only)
{
/* If we are in fips mode do some more tests. */
gcry_md_hd_t md;
/* First trigger a self-test. */
gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
if (!gcry_control (GCRYCTL_OPERATIONAL_P, 0))
fail ("not in operational state after self-test\n");
/* Get us into the error state. */
err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
if (err)
fail ("failed to open SHA-1 hash context: %s\n", gpg_strerror (err));
else
{
err = gcry_md_enable (md, GCRY_MD_SHA256);
if (err)
fail ("failed to add SHA-256 hash context: %s\n",
gpg_strerror (err));
else
{
/* gcry_md_get_algo is only defined for a context with
just one digest algorithm. With our setup it should
put the oibrary intoerror state. */
fputs ("Note: Two lines with error messages follow "
"- this is expected\n", stderr);
gcry_md_get_algo (md);
gcry_md_close (md);
if (gcry_control (GCRYCTL_OPERATIONAL_P, 0))
fail ("expected error state but still in operational state\n");
else
{
/* Now run a self-test and to get back into
operational state. */
gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
if (!gcry_control (GCRYCTL_OPERATIONAL_P, 0))
fail ("did not reach operational after error "
"and self-test\n");
}
}
}
}
else
{
/* If in standard mode, run selftests. */
if (gcry_control (GCRYCTL_SELFTEST, 0))
fail ("running self-test failed\n");
}
if (verbose)
fprintf (stderr, "\nAll tests completed. Errors: %i\n", error_count);
if (in_fips_mode && !gcry_fips_mode_active ())
fprintf (stderr, "FIPS mode is not anymore active\n");
return error_count ? 1 : 0;
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, May 10, 8:31 AM (1 d, 7 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
eb/75/7cf89d7e7e70d19fb562c79e3758

Event Timeline