Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34384994
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
233 KB
Subscribers
None
View Options
diff --git a/cipher/ecc.c b/cipher/ecc.c
index 051308f0..17724e82 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -1,2356 +1,2415 @@
/* 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.
*/
#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"
#include "ecc-common.h"
static const char *ecc_names[] =
{
"ecc",
"ecdsa",
"ecdh",
"eddsa",
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_ecdsa (gcry_mpi_t input, ECC_secret_key *skey,
gcry_mpi_t r, gcry_mpi_t s,
int flags, int hashalgo);
static gpg_err_code_t verify_ecdsa (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);
static unsigned int ecc_get_nbits (gcry_sexp_t parms);
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); */
/* } */
/*
* Solve the right side of the Weierstrass equation.
*/
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. */
}
/* Standard version of the key generation. */
static gpg_err_code_t
nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
gcry_random_level_t random_level, unsigned int nbits)
{
mpi_point_struct Q;
point_init (&Q);
/* Generate a secret. */
sk->d = _gcry_dsa_gen_k (E->n, random_level);
/* Compute Q. */
_gcry_mpi_ec_mul_point (&Q, sk->d, &E->G, ctx);
/* Copy the stuff to the key structures. */
sk->E.model = E->model;
sk->E.dialect = E->dialect;
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);
}
/* 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 = _gcry_ecc_curve_copy (sk->E);
point_init (&pk.Q);
point_set (&pk.Q, &sk->Q);
gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
if (sign_ecdsa (test, sk, r, s, 0, 0) )
log_fatal ("ECDSA operation: sign failed\n");
if (verify_ecdsa (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);
_gcry_ecc_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;
gcry_mpi_t x1, x2;
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);
x1 = mpi_alloc (0);
x2 = 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.model, sk->E.dialect,
sk->E.p, sk->E.a, sk->E.b);
_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 (_gcry_mpi_ec_get_affine (x1, y_2, &Q, ctx))
{
if (DBG_CIPHER)
log_debug ("Bad check: Q can not be a Point at Infinity!\n");
goto leave;
}
/* Fast path for loaded secret keys - Q is already in affine coordinates */
if (!mpi_cmp_ui (sk->Q.z, 1))
{
if (mpi_cmp (x1, sk->Q.x) || mpi_cmp (y_2, sk->Q.y))
{
if (DBG_CIPHER)
log_debug
("Bad check: There is NO correspondence between 'd' and 'Q'!\n");
goto leave;
}
}
else
{
if (_gcry_mpi_ec_get_affine (x2, y2, &sk->Q, ctx))
{
if (DBG_CIPHER)
log_debug ("Bad check: Q can not be a Point at Infinity!\n");
goto leave;
}
if (mpi_cmp (x1, x2) || mpi_cmp (y_2, y2))
{
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 (x2);
mpi_free (x1);
mpi_free (y2);
mpi_free (y_2);
point_free (&Q);
return rc;
}
/* Compute an ECDSA signature.
* Return the signature struct (r,s) from the message hash. The caller
* must have allocated R and S.
*/
static gpg_err_code_t
sign_ecdsa (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s,
int flags, int hashalgo)
{
gpg_err_code_t err = 0;
int extraloops = 0;
gcry_mpi_t k, dr, sum, k_1, x;
mpi_point_struct I;
gcry_mpi_t hash;
const void *abuf;
unsigned int abits, qbits;
mpi_ec_t ctx;
if (DBG_CIPHER)
log_mpidump ("ecdsa sign hash ", input );
qbits = mpi_get_nbits (skey->E.n);
/* Convert the INPUT into an MPI if needed. */
if (mpi_is_opaque (input))
{
abuf = gcry_mpi_get_opaque (input, &abits);
err = gpg_err_code (gcry_mpi_scan (&hash, GCRYMPI_FMT_USG,
abuf, (abits+7)/8, NULL));
if (err)
return err;
if (abits > qbits)
gcry_mpi_rshift (hash, hash, abits - qbits);
}
else
hash = input;
k = NULL;
dr = mpi_alloc (0);
sum = mpi_alloc (0);
k_1 = mpi_alloc (0);
x = mpi_alloc (0);
point_init (&I);
ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect,
skey->E.p, skey->E.a, skey->E.b);
/* Two loops to avoid R or S are zero. This is more of a joke than
a real demand because the probability of them being zero is less
than any hardware failure. Some specs however require it. */
do
{
do
{
mpi_free (k);
k = NULL;
if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo)
{
/* Use Pornin's method for deterministic DSA. If this
flag is set, it is expected that HASH is an opaque
MPI with the to be signed hash. That hash is also
used as h1 from 3.2.a. */
if (!mpi_is_opaque (input))
{
err = GPG_ERR_CONFLICT;
goto leave;
}
abuf = gcry_mpi_get_opaque (input, &abits);
err = _gcry_dsa_gen_rfc6979_k (&k, skey->E.n, skey->d,
abuf, (abits+7)/8,
hashalgo, extraloops);
if (err)
goto leave;
extraloops++;
}
else
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 */
}
while (!mpi_cmp_ui (r, 0));
mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */
mpi_addm (sum, hash, 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 */
}
while (!mpi_cmp_ui (s, 0));
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);
if (hash != input)
mpi_free (hash);
return err;
}
/* Verify an ECDSA signature.
* Check if R and S verifies INPUT.
*/
static gpg_err_code_t
verify_ecdsa (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;
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);
point_init (&Q);
point_init (&Q1);
point_init (&Q2);
ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
pkey->E.p, pkey->E.a, pkey->E.b);
/* h = s^(-1) (mod n) */
mpi_invm (h, s, pkey->E.n);
/* h1 = hash * s^(-1) (mod n) */
mpi_mulm (h1, input, h, pkey->E.n);
/* Q1 = [ hash * s^(-1) ]G */
_gcry_mpi_ec_mul_point (&Q1, h1, &pkey->E.G, ctx);
/* h2 = r * s^(-1) (mod n) */
mpi_mulm (h2, r, h, pkey->E.n);
/* Q2 = [ r * s^(-1) ]Q */
_gcry_mpi_ec_mul_point (&Q2, h2, &pkey->Q, ctx);
/* Q = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */
_gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx);
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, NULL, &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 (" 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 (x);
mpi_free (h2);
mpi_free (h1);
mpi_free (h);
return err;
}
static void
reverse_buffer (unsigned char *buffer, unsigned int length)
{
unsigned int tmp, i;
for (i=0; i < length/2; i++)
{
tmp = buffer[i];
buffer[i] = buffer[length-1-i];
buffer[length-1-i] = tmp;
}
}
/* Encode MPI using the EdDSA scheme. MINLEN specifies the required
length of the buffer in bytes. On success 0 is returned an a
malloced buffer with the encoded point is stored at R_BUFFER; the
length of this buffer is stored at R_BUFLEN. */
static gpg_err_code_t
eddsa_encodempi (gcry_mpi_t mpi, unsigned int minlen,
unsigned char **r_buffer, unsigned int *r_buflen)
{
unsigned char *rawmpi;
unsigned int rawmpilen;
rawmpi = _gcry_mpi_get_buffer (mpi, minlen, &rawmpilen, NULL);
if (!rawmpi)
return gpg_err_code_from_syserror ();
*r_buffer = rawmpi;
*r_buflen = rawmpilen;
return 0;
}
/* Encode (X,Y) using the EdDSA scheme. MINLEN is the required length
in bytes for the result. On success 0 is returned and a malloced
buffer with the encoded point is stored at R_BUFFER; the length of
this buffer is stored at R_BUFLEN. */
static gpg_err_code_t
eddsa_encode_x_y (gcry_mpi_t x, gcry_mpi_t y, unsigned int minlen,
unsigned char **r_buffer, unsigned int *r_buflen)
{
unsigned char *rawmpi;
unsigned int rawmpilen;
rawmpi = _gcry_mpi_get_buffer (y, minlen, &rawmpilen, NULL);
if (!rawmpi)
return gpg_err_code_from_syserror ();
if (mpi_test_bit (x, 0) && rawmpilen)
rawmpi[rawmpilen - 1] |= 0x80; /* Set sign bit. */
*r_buffer = rawmpi;
*r_buflen = rawmpilen;
return 0;
}
/* Encode POINT using the EdDSA scheme. X and Y are either scratch
variables supplied by the caller or NULL. CTX is the usual
context. On success 0 is returned and a malloced buffer with the
encoded point is stored at R_BUFFER; the length of this buffer is
stored at R_BUFLEN. */
gpg_err_code_t
_gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ec,
gcry_mpi_t x_in, gcry_mpi_t y_in,
unsigned char **r_buffer, unsigned int *r_buflen)
{
gpg_err_code_t rc;
gcry_mpi_t x, y;
x = x_in? x_in : mpi_new (0);
y = y_in? y_in : mpi_new (0);
if (_gcry_mpi_ec_get_affine (x, y, point, ec))
{
log_error ("eddsa_encodepoint: Failed to get affine coordinates\n");
rc = GPG_ERR_INTERNAL;
}
else
rc = eddsa_encode_x_y (x, y, ec->nbits/8, r_buffer, r_buflen);
if (!x_in)
mpi_free (x);
if (!y_in)
mpi_free (y);
return rc;
}
/* Decode the EdDSA style encoded PK and set it into RESULT. CTX is
the usual curve context. If R_ENCPK is not NULL, the encoded PK is
stored at that address; this is a new copy to be released by the
caller. In contrast to the supplied PK, this is not an MPI and
thus guarnateed to be properly padded. R_ENCPKLEN received the
length of that encoded key. */
gpg_err_code_t
_gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result,
unsigned char **r_encpk, unsigned int *r_encpklen)
{
gpg_err_code_t rc;
unsigned char *rawmpi;
unsigned int rawmpilen;
gcry_mpi_t yy, t, x, p1, p2, p3;
int sign;
if (mpi_is_opaque (pk))
{
const unsigned char *buf;
buf = gcry_mpi_get_opaque (pk, &rawmpilen);
if (!buf)
return GPG_ERR_INV_OBJ;
rawmpilen = (rawmpilen + 7)/8;
/* First check whether the public key has been given in standard
uncompressed format. No need to recover x in this case.
Detection is easy: The size of the buffer will be odd and the
first byte be 0x04. */
if (rawmpilen > 1 && buf[0] == 0x04 && (rawmpilen%2))
{
gcry_mpi_t y;
rc = gcry_mpi_scan (&x, GCRYMPI_FMT_STD,
buf+1, (rawmpilen-1)/2, NULL);
if (rc)
return rc;
rc = gcry_mpi_scan (&y, GCRYMPI_FMT_STD,
buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2, NULL);
if (rc)
{
mpi_free (x);
return rc;
}
if (r_encpk)
{
rc = eddsa_encode_x_y (x, y, ctx->nbits/8, r_encpk, r_encpklen);
if (rc)
{
mpi_free (x);
mpi_free (y);
return rc;
}
}
mpi_snatch (result->x, x);
mpi_snatch (result->y, y);
mpi_set_ui (result->z, 1);
return 0;
}
/* EdDSA compressed point. */
rawmpi = gcry_malloc (rawmpilen? rawmpilen:1);
if (!rawmpi)
return gpg_err_code_from_syserror ();
memcpy (rawmpi, buf, rawmpilen);
reverse_buffer (rawmpi, rawmpilen);
}
else
{
/* Note: Without using an opaque MPI it is not reliable possible
to find out whether the public key has been given in
uncompressed format. Thus we expect EdDSA format here. */
rawmpi = _gcry_mpi_get_buffer (pk, ctx->nbits/8, &rawmpilen, NULL);
if (!rawmpi)
return gpg_err_code_from_syserror ();
}
if (rawmpilen)
{
sign = !!(rawmpi[0] & 0x80);
rawmpi[0] &= 0x7f;
}
else
sign = 0;
_gcry_mpi_set_buffer (result->y, rawmpi, rawmpilen, 0);
if (r_encpk)
{
/* Revert to little endian. */
if (sign && rawmpilen)
rawmpi[0] |= 0x80;
reverse_buffer (rawmpi, rawmpilen);
*r_encpk = rawmpi;
if (r_encpklen)
*r_encpklen = rawmpilen;
}
else
gcry_free (rawmpi);
/* Now recover X. */
/* t = (y^2-1) · ((b*y^2+1)^{p-2} mod p) */
x = mpi_new (0);
yy = mpi_new (0);
mpi_mul (yy, result->y, result->y);
t = mpi_copy (yy);
mpi_mul (t, t, ctx->b);
mpi_add_ui (t, t, 1);
p2 = mpi_copy (ctx->p);
mpi_sub_ui (p2, p2, 2);
mpi_powm (t, t, p2, ctx->p);
mpi_sub_ui (yy, yy, 1);
mpi_mul (t, yy, t);
/* x = t^{(p+3)/8} mod p */
p3 = mpi_copy (ctx->p);
mpi_add_ui (p3, p3, 3);
mpi_fdiv_q (p3, p3, mpi_const (MPI_C_EIGHT));
mpi_powm (x, t, p3, ctx->p);
/* (x^2 - t) % p != 0 ? x = (x*(2^{(p-1)/4} mod p)) % p */
mpi_mul (yy, x, x);
mpi_subm (yy, yy, t, ctx->p);
if (mpi_cmp_ui (yy, 0))
{
p1 = mpi_copy (ctx->p);
mpi_sub_ui (p1, p1, 1);
mpi_fdiv_q (p1, p1, mpi_const (MPI_C_FOUR));
mpi_powm (yy, mpi_const (MPI_C_TWO), p1, ctx->p);
mpi_mulm (x, x, yy, ctx->p);
}
else
p1 = NULL;
/* is_odd(x) ? x = p-x */
if (mpi_test_bit (x, 0))
mpi_sub (x, ctx->p, x);
/* lowbit(x) != highbit(input) ? x = p-x */
if (mpi_test_bit (x, 0) != sign)
mpi_sub (x, ctx->p, x);
mpi_set (result->x, x);
mpi_set_ui (result->z, 1);
gcry_mpi_release (x);
gcry_mpi_release (yy);
gcry_mpi_release (t);
gcry_mpi_release (p3);
gcry_mpi_release (p2);
gcry_mpi_release (p1);
return 0;
}
/* Ed25519 version of the key generation. */
static gpg_err_code_t
eddsa_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
gcry_random_level_t random_level)
{
gpg_err_code_t rc;
int b = 256/8; /* The only size we currently support. */
gcry_mpi_t a, x, y;
mpi_point_struct Q;
char *dbuf;
size_t dlen;
gcry_buffer_t hvec[1];
unsigned char *hash_d = NULL;
point_init (&Q);
memset (hvec, 0, sizeof hvec);
a = mpi_snew (0);
x = mpi_new (0);
y = mpi_new (0);
/* Generate a secret. */
hash_d = gcry_malloc_secure (2*b);
if (!hash_d)
{
rc = gpg_error_from_syserror ();
goto leave;
}
dlen = b;
dbuf = gcry_random_bytes_secure (dlen, random_level);
/* Compute the A value. */
hvec[0].data = dbuf;
hvec[0].len = dlen;
rc = _gcry_md_hash_buffers (GCRY_MD_SHA512, 0, hash_d, hvec, 1);
if (rc)
goto leave;
sk->d = _gcry_mpi_set_opaque (NULL, dbuf, dlen*8);
dbuf = NULL;
reverse_buffer (hash_d, 32); /* Only the first half of the hash. */
hash_d[0] = (hash_d[0] & 0x7f) | 0x40;
hash_d[31] &= 0xf8;
_gcry_mpi_set_buffer (a, hash_d, 32, 0);
gcry_free (hash_d); hash_d = NULL;
/* log_printmpi ("ecgen a", a); */
/* Compute Q. */
_gcry_mpi_ec_mul_point (&Q, a, &E->G, ctx);
if (DBG_CIPHER)
log_printpnt ("ecgen pk", &Q, ctx);
/* Copy the stuff to the key structures. */
sk->E.model = E->model;
sk->E.dialect = E->dialect;
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);
point_set (&sk->Q, &Q);
leave:
gcry_mpi_release (a);
gcry_mpi_release (x);
gcry_mpi_release (y);
gcry_free (hash_d);
return rc;
}
/* Compute an EdDSA signature. See:
* [ed25519] 23pp. (PDF) Daniel J. Bernstein, Niels Duif, Tanja
* Lange, Peter Schwabe, Bo-Yin Yang. High-speed high-security
* signatures. Journal of Cryptographic Engineering 2 (2012), 77-89.
* Document ID: a1a62a2f76d23f65d622484ddd09caf8.
* URL: http://cr.yp.to/papers.html#ed25519. Date: 2011.09.26.
*
* Despite that this function requires the specification of a hash
* algorithm, we only support what has been specified by the paper.
* This may change in the future. Note that we don't check the used
* curve; the user is responsible to use Ed25519.
*
* Return the signature struct (r,s) from the message hash. The caller
* must have allocated R_R and S.
*/
static gpg_err_code_t
sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
gcry_mpi_t r_r, gcry_mpi_t s, int hashalgo, gcry_mpi_t pk)
{
int rc;
mpi_ec_t ctx = NULL;
int b;
unsigned int tmp;
unsigned char *digest;
gcry_buffer_t hvec[3];
const void *mbuf;
size_t mlen;
unsigned char *rawmpi = NULL;
unsigned int rawmpilen;
unsigned char *encpk = NULL; /* Encoded public key. */
unsigned int encpklen;
mpi_point_struct I; /* Intermediate value. */
mpi_point_struct Q; /* Public key. */
gcry_mpi_t a, x, y, r;
memset (hvec, 0, sizeof hvec);
if (!mpi_is_opaque (input))
return GPG_ERR_INV_DATA;
if (hashalgo != GCRY_MD_SHA512)
return GPG_ERR_DIGEST_ALGO;
/* Initialize some helpers. */
point_init (&I);
point_init (&Q);
a = mpi_snew (0);
x = mpi_new (0);
y = mpi_new (0);
r = mpi_new (0);
ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect,
skey->E.p, skey->E.a, skey->E.b);
b = (ctx->nbits+7)/8;
if (b != 256/8)
return GPG_ERR_INTERNAL; /* We only support 256 bit. */
digest = gcry_calloc_secure (2, b);
if (!digest)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
/* Hash the secret key. We clear DIGEST so we can use it as input
to left pad the key with zeroes for hashing. */
rawmpi = _gcry_mpi_get_buffer (skey->d, 0, &rawmpilen, NULL);
if (!rawmpi)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
hvec[0].data = digest;
hvec[0].off = 0;
hvec[0].len = b > rawmpilen? b - rawmpilen : 0;
hvec[1].data = rawmpi;
hvec[1].off = 0;
hvec[1].len = rawmpilen;
rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2);
gcry_free (rawmpi); rawmpi = NULL;
if (rc)
goto leave;
/* Compute the A value (this modifies DIGEST). */
reverse_buffer (digest, 32); /* Only the first half of the hash. */
digest[0] = (digest[0] & 0x7f) | 0x40;
digest[31] &= 0xf8;
_gcry_mpi_set_buffer (a, digest, 32, 0);
/* Compute the public key if it has not been supplied as optional
parameter. */
if (pk)
{
rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen);
if (rc)
goto leave;
if (DBG_CIPHER)
log_printhex ("* e_pk", encpk, encpklen);
if (!_gcry_mpi_ec_curve_point (&Q, ctx))
{
rc = GPG_ERR_BROKEN_PUBKEY;
goto leave;
}
}
else
{
_gcry_mpi_ec_mul_point (&Q, a, &skey->E.G, ctx);
rc = _gcry_ecc_eddsa_encodepoint (&Q, ctx, x, y, &encpk, &encpklen);
if (rc)
goto leave;
if (DBG_CIPHER)
log_printhex (" e_pk", encpk, encpklen);
}
/* Compute R. */
mbuf = gcry_mpi_get_opaque (input, &tmp);
mlen = (tmp +7)/8;
if (DBG_CIPHER)
log_printhex (" m", mbuf, mlen);
hvec[0].data = digest;
hvec[0].off = 32;
hvec[0].len = 32;
hvec[1].data = (char*)mbuf;
hvec[1].len = mlen;
rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2);
if (rc)
goto leave;
reverse_buffer (digest, 64);
if (DBG_CIPHER)
log_printhex (" r", digest, 64);
_gcry_mpi_set_buffer (r, digest, 64, 0);
_gcry_mpi_ec_mul_point (&I, r, &skey->E.G, ctx);
if (DBG_CIPHER)
log_printpnt (" r", &I, ctx);
/* Convert R into affine coordinates and apply encoding. */
rc = _gcry_ecc_eddsa_encodepoint (&I, ctx, x, y, &rawmpi, &rawmpilen);
if (rc)
goto leave;
if (DBG_CIPHER)
log_printhex (" e_r", rawmpi, rawmpilen);
/* S = r + a * H(encodepoint(R) + encodepoint(pk) + m) mod n */
hvec[0].data = rawmpi; /* (this is R) */
hvec[0].off = 0;
hvec[0].len = rawmpilen;
hvec[1].data = encpk;
hvec[1].off = 0;
hvec[1].len = encpklen;
hvec[2].data = (char*)mbuf;
hvec[2].off = 0;
hvec[2].len = mlen;
rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3);
if (rc)
goto leave;
/* No more need for RAWMPI thus we now transfer it to R_R. */
gcry_mpi_set_opaque (r_r, rawmpi, rawmpilen*8);
rawmpi = NULL;
reverse_buffer (digest, 64);
if (DBG_CIPHER)
log_printhex (" H(R+)", digest, 64);
_gcry_mpi_set_buffer (s, digest, 64, 0);
mpi_mulm (s, s, a, skey->E.n);
mpi_addm (s, s, r, skey->E.n);
rc = eddsa_encodempi (s, b, &rawmpi, &rawmpilen);
if (rc)
goto leave;
if (DBG_CIPHER)
log_printhex (" e_s", rawmpi, rawmpilen);
gcry_mpi_set_opaque (s, rawmpi, rawmpilen*8);
rawmpi = NULL;
rc = 0;
leave:
gcry_mpi_release (a);
gcry_mpi_release (x);
gcry_mpi_release (y);
gcry_mpi_release (r);
gcry_free (digest);
_gcry_mpi_ec_free (ctx);
point_free (&I);
point_free (&Q);
gcry_free (encpk);
gcry_free (rawmpi);
return rc;
}
/* Verify an EdDSA signature. See sign_eddsa for the reference.
* Check if R_IN and S_IN verifies INPUT. PKEY has the curve
* parameters and PK is the EdDSA style encoded public key.
*/
static gpg_err_code_t
verify_eddsa (gcry_mpi_t input, ECC_public_key *pkey,
gcry_mpi_t r_in, gcry_mpi_t s_in, int hashalgo, gcry_mpi_t pk)
{
int rc;
mpi_ec_t ctx = NULL;
int b;
unsigned int tmp;
mpi_point_struct Q; /* Public key. */
unsigned char *encpk = NULL; /* Encoded public key. */
unsigned int encpklen;
const void *mbuf, *rbuf;
unsigned char *tbuf = NULL;
size_t mlen, rlen;
unsigned int tlen;
unsigned char digest[64];
gcry_buffer_t hvec[3];
gcry_mpi_t h, s;
mpi_point_struct Ia, Ib;
if (!mpi_is_opaque (input) || !mpi_is_opaque (r_in) || !mpi_is_opaque (s_in))
return GPG_ERR_INV_DATA;
if (hashalgo != GCRY_MD_SHA512)
return GPG_ERR_DIGEST_ALGO;
point_init (&Q);
point_init (&Ia);
point_init (&Ib);
h = mpi_new (0);
s = mpi_new (0);
ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
pkey->E.p, pkey->E.a, pkey->E.b);
b = ctx->nbits/8;
if (b != 256/8)
return GPG_ERR_INTERNAL; /* We only support 256 bit. */
/* Decode and check the public key. */
rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen);
if (rc)
goto leave;
if (!_gcry_mpi_ec_curve_point (&Q, ctx))
{
rc = GPG_ERR_BROKEN_PUBKEY;
goto leave;
}
if (DBG_CIPHER)
log_printhex (" e_pk", encpk, encpklen);
if (encpklen != b)
{
rc = GPG_ERR_INV_LENGTH;
goto leave;
}
/* Convert the other input parameters. */
mbuf = gcry_mpi_get_opaque (input, &tmp);
mlen = (tmp +7)/8;
if (DBG_CIPHER)
log_printhex (" m", mbuf, mlen);
rbuf = gcry_mpi_get_opaque (r_in, &tmp);
rlen = (tmp +7)/8;
if (DBG_CIPHER)
log_printhex (" r", rbuf, rlen);
if (rlen != b)
{
rc = GPG_ERR_INV_LENGTH;
goto leave;
}
/* h = H(encodepoint(R) + encodepoint(pk) + m) */
hvec[0].data = (char*)rbuf;
hvec[0].off = 0;
hvec[0].len = rlen;
hvec[1].data = encpk;
hvec[1].off = 0;
hvec[1].len = encpklen;
hvec[2].data = (char*)mbuf;
hvec[2].off = 0;
hvec[2].len = mlen;
rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3);
if (rc)
goto leave;
reverse_buffer (digest, 64);
if (DBG_CIPHER)
log_printhex (" H(R+)", digest, 64);
_gcry_mpi_set_buffer (h, digest, 64, 0);
/* According to the paper the best way for verification is:
encodepoint(sG - h·Q) = encodepoint(r)
because we don't need to decode R. */
{
void *sbuf;
unsigned int slen;
sbuf = _gcry_mpi_get_opaque_copy (s_in, &tmp);
slen = (tmp +7)/8;
reverse_buffer (sbuf, slen);
if (DBG_CIPHER)
log_printhex (" s", sbuf, slen);
_gcry_mpi_set_buffer (s, sbuf, slen, 0);
gcry_free (sbuf);
if (slen != b)
{
rc = GPG_ERR_INV_LENGTH;
goto leave;
}
}
_gcry_mpi_ec_mul_point (&Ia, s, &pkey->E.G, ctx);
_gcry_mpi_ec_mul_point (&Ib, h, &Q, ctx);
_gcry_mpi_neg (Ib.x, Ib.x);
_gcry_mpi_ec_add_points (&Ia, &Ia, &Ib, ctx);
rc = _gcry_ecc_eddsa_encodepoint (&Ia, ctx, s, h, &tbuf, &tlen);
if (rc)
goto leave;
if (tlen != rlen || memcmp (tbuf, rbuf, tlen))
{
if (DBG_CIPHER)
log_debug ("eddsa verify: Not verified\n");
rc = GPG_ERR_BAD_SIGNATURE;
goto leave;
}
if (DBG_CIPHER)
log_debug ("eddsa verify: Accepted\n");
rc = 0;
leave:
gcry_free (encpk);
gcry_free (tbuf);
_gcry_mpi_ec_free (ctx);
gcry_mpi_release (s);
gcry_mpi_release (h);
point_free (&Ia);
point_free (&Ib);
point_free (&Q);
return rc;
}
/*********************************************
************** interface ******************
*********************************************/
static gcry_err_code_t
ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
{
gpg_err_code_t rc;
unsigned int nbits;
elliptic_curve_t E;
ECC_secret_key sk;
gcry_mpi_t x = NULL;
gcry_mpi_t y = NULL;
char *curve_name = NULL;
gcry_sexp_t l1;
int transient_key = 0;
gcry_random_level_t random_level;
mpi_ec_t ctx = NULL;
gcry_sexp_t curve_info = NULL;
gcry_mpi_t base = NULL;
gcry_mpi_t public = NULL;
gcry_mpi_t secret = NULL;
memset (&E, 0, sizeof E);
memset (&sk, 0, sizeof sk);
rc = _gcry_pk_util_get_nbits (genparms, &nbits);
if (rc)
return rc;
/* 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. */
rc = _gcry_ecc_fill_in_curve (nbits, curve_name, &E, &nbits);
gcry_free (curve_name); curve_name = NULL;
if (rc)
goto leave;
if (DBG_CIPHER)
{
log_debug ("ecgen curve info: %s/%s\n",
_gcry_ecc_model2str (E.model),
_gcry_ecc_dialect2str (E.dialect));
if (E.name)
log_debug ("ecgen curve used: %s\n", E.name);
log_printmpi ("ecgen curve p", E.p);
log_printmpi ("ecgen curve a", E.a);
log_printmpi ("ecgen curve b", E.b);
log_printmpi ("ecgen curve n", E.n);
log_printpnt ("ecgen curve G", &E.G, NULL);
}
random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
ctx = _gcry_mpi_ec_p_internal_new (E.model, E.dialect, E.p, E.a, E.b);
x = mpi_new (0);
y = mpi_new (0);
switch (E.dialect)
{
case ECC_DIALECT_STANDARD:
rc = nist_generate_key (&sk, &E, ctx, random_level, nbits);
break;
case ECC_DIALECT_ED25519:
rc = eddsa_generate_key (&sk, &E, ctx, random_level);
break;
default:
rc = GPG_ERR_INTERNAL;
break;
}
if (rc)
goto leave;
/* Copy data to the result. */
if (_gcry_mpi_ec_get_affine (x, y, &sk.E.G, ctx))
log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "G");
base = _gcry_ecc_ec2os (x, y, sk.E.p);
if (sk.E.dialect == ECC_DIALECT_ED25519)
{
unsigned char *encpk;
unsigned int encpklen;
rc = _gcry_ecc_eddsa_encodepoint (&sk.Q, ctx, x, y, &encpk, &encpklen);
if (rc)
return rc;
public = mpi_new (0);
gcry_mpi_set_opaque (public, encpk, encpklen*8);
encpk = NULL;
}
else
{
if (_gcry_mpi_ec_get_affine (x, y, &sk.Q, ctx))
log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q");
public = _gcry_ecc_ec2os (x, y, sk.E.p);
}
secret = sk.d; sk.d = NULL;
if (E.name)
{
rc = gcry_sexp_build (&curve_info, NULL, "(curve %s)", E.name);
if (rc)
goto leave;
}
rc = gcry_sexp_build (r_skey, NULL,
"(key-data"
" (public-key"
" (ecc%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))"
" (private-key"
" (ecc%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)(d%m)))"
" )",
curve_info,
sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, public,
curve_info,
sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, public, secret);
if (rc)
goto leave;
if (DBG_CIPHER)
{
log_printmpi ("ecgen result p", sk.E.p);
log_printmpi ("ecgen result a", sk.E.a);
log_printmpi ("ecgen result b", sk.E.b);
log_printmpi ("ecgen result G", base);
log_printmpi ("ecgen result n", sk.E.n);
log_printmpi ("ecgen result Q", public);
log_printmpi ("ecgen result d", secret);
}
leave:
mpi_free (secret);
mpi_free (public);
mpi_free (base);
{
_gcry_ecc_curve_free (&sk.E);
point_free (&sk.Q);
mpi_free (sk.d);
}
_gcry_ecc_curve_free (&E);
mpi_free (x);
mpi_free (y);
_gcry_mpi_ec_free (ctx);
gcry_sexp_release (curve_info);
return rc;
}
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.model = MPI_EC_WEIERSTRASS;
sk.E.p = skey[0];
sk.E.a = skey[1];
sk.E.b = skey[2];
point_init (&sk.E.G);
err = _gcry_ecc_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 = _gcry_ecc_os2ec (&sk.Q, skey[5]);
if (err)
{
point_free (&sk.E.G);
point_free (&sk.Q);
return err;
}
{
const unsigned char *buf;
unsigned int n;
gcry_assert (mpi_is_opaque (skey[6]));
buf = gcry_mpi_get_opaque (skey[6], &n);
if (!buf)
err = GPG_ERR_INV_OBJ;
else
{
n = (n + 7)/8;
sk.d = NULL;
err = gcry_mpi_scan (&sk.d, GCRYMPI_FMT_USG, buf, n, NULL);
if (!err)
{
if (check_secret_key (&sk))
err = GPG_ERR_BAD_SECKEY;
gcry_mpi_release (sk.d);
sk.d = NULL;
}
}
}
point_free (&sk.E.G);
point_free (&sk.Q);
return err;
}
static gcry_err_code_t
ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
{
gcry_err_code_t rc;
struct pk_encoding_ctx ctx;
gcry_mpi_t data = NULL;
gcry_sexp_t l1 = NULL;
char *curvename = NULL;
gcry_mpi_t mpi_g = NULL;
gcry_mpi_t mpi_q = NULL;
ECC_secret_key sk;
gcry_mpi_t sig_r = NULL;
gcry_mpi_t sig_s = NULL;
memset (&sk, 0, sizeof sk);
_gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, 0);
/* Extract the data. */
rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
if (rc)
goto leave;
if (DBG_CIPHER)
log_mpidump ("ecc_sign data", data);
/*
* Extract the key.
*/
rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?/q?+d",
&sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
&mpi_q, &sk.d, NULL);
if (rc)
goto leave;
if (mpi_g)
{
point_init (&sk.E.G);
rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g);
if (rc)
goto leave;
}
/* Add missing parameters using the optional curve parameter. */
gcry_sexp_release (l1);
l1 = gcry_sexp_find_token (keyparms, "curve", 5);
if (l1)
{
curvename = gcry_sexp_nth_string (l1, 1);
if (curvename)
{
rc = _gcry_ecc_fill_in_curve (0, curvename, &sk.E, NULL);
if (rc)
return rc;
}
}
/* Guess required fields if a curve parameter has not been given.
FIXME: This is a crude hacks. We need to fix that. */
if (!curvename)
{
sk.E.model = ((ctx.flags & PUBKEY_FLAG_EDDSA)
? MPI_EC_TWISTEDEDWARDS
: MPI_EC_WEIERSTRASS);
sk.E.dialect = ((ctx.flags & PUBKEY_FLAG_EDDSA)
? ECC_DIALECT_ED25519
: ECC_DIALECT_STANDARD);
}
if (DBG_CIPHER)
{
log_debug ("ecc_sign info: %s/%s\n",
_gcry_ecc_model2str (sk.E.model),
_gcry_ecc_dialect2str (sk.E.dialect));
if (sk.E.name)
log_debug ("ecc_sign name: %s\n", sk.E.name);
log_printmpi ("ecc_sign p", sk.E.p);
log_printmpi ("ecc_sign a", sk.E.a);
log_printmpi ("ecc_sign b", sk.E.b);
log_printpnt ("ecc_sign g", &sk.E.G, NULL);
log_printmpi ("ecc_sign n", sk.E.n);
log_printmpi ("ecc_sign q", mpi_q);
if (!fips_mode ())
log_printmpi ("ecc_sign d", sk.d);
}
if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.d)
{
rc = GPG_ERR_NO_OBJ;
goto leave;
}
sig_r = gcry_mpi_new (0);
sig_s = gcry_mpi_new (0);
if ((ctx.flags & PUBKEY_FLAG_EDDSA))
{
/* EdDSA requires the public key. */
rc = sign_eddsa (data, &sk, sig_r, sig_s, ctx.hash_algo, mpi_q);
if (!rc)
rc = gcry_sexp_build (r_sig, NULL,
"(sig-val(eddsa(r%M)(s%M)))", sig_r, sig_s);
}
else
{
rc = sign_ecdsa (data, &sk, sig_r, sig_s, ctx.flags, ctx.hash_algo);
if (!rc)
rc = gcry_sexp_build (r_sig, NULL,
"(sig-val(ecdsa(r%M)(s%M)))", sig_r, sig_s);
}
leave:
gcry_mpi_release (sk.E.p);
gcry_mpi_release (sk.E.a);
gcry_mpi_release (sk.E.b);
gcry_mpi_release (mpi_g);
point_free (&sk.E.G);
gcry_mpi_release (sk.E.n);
gcry_mpi_release (mpi_q);
point_free (&sk.Q);
gcry_mpi_release (sk.d);
gcry_mpi_release (sig_r);
gcry_mpi_release (sig_s);
gcry_free (curvename);
gcry_mpi_release (data);
gcry_sexp_release (l1);
_gcry_pk_util_free_encoding_ctx (&ctx);
if (DBG_CIPHER)
log_debug ("ecc_sign => %s\n", gpg_strerror (rc));
return rc;
}
static gcry_err_code_t
ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
{
gcry_err_code_t rc;
struct pk_encoding_ctx ctx;
gcry_sexp_t l1 = NULL;
char *curvename = NULL;
gcry_mpi_t mpi_g = NULL;
gcry_mpi_t mpi_q = NULL;
gcry_mpi_t sig_r = NULL;
gcry_mpi_t sig_s = NULL;
gcry_mpi_t data = NULL;
ECC_public_key pk;
int sigflags;
memset (&pk, 0, sizeof pk);
_gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY,
ecc_get_nbits (s_keyparms));
/* Extract the data. */
rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
if (rc)
goto leave;
if (DBG_CIPHER)
log_mpidump ("ecc_verify data", data);
/*
* Extract the signature value.
*/
rc = _gcry_pk_util_preparse_sigval (s_sig, ecc_names, &l1, &sigflags);
if (rc)
goto leave;
rc = _gcry_pk_util_extract_mpis (l1,
(sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs",
&sig_r, &sig_s, NULL);
if (rc)
goto leave;
if (DBG_CIPHER)
{
log_mpidump ("ecc_verify s_r", sig_r);
log_mpidump ("ecc_verify s_s", sig_s);
}
if ((ctx.flags & PUBKEY_FLAG_EDDSA) ^ (sigflags & PUBKEY_FLAG_EDDSA))
{
rc = GPG_ERR_CONFLICT; /* Inconsistent use of flag/algoname. */
goto leave;
}
/*
* Extract the key.
*/
rc = _gcry_pk_util_extract_mpis (s_keyparms, "-p?a?b?g?n?/q?",
&pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
&mpi_q, NULL);
if (rc)
goto leave;
if (mpi_g)
{
point_init (&pk.E.G);
rc = _gcry_ecc_os2ec (&pk.E.G, mpi_g);
if (rc)
goto leave;
}
/* Add missing parameters using the optional curve parameter. */
gcry_sexp_release (l1);
l1 = gcry_sexp_find_token (s_keyparms, "curve", 5);
if (l1)
{
curvename = gcry_sexp_nth_string (l1, 1);
if (curvename)
{
rc = _gcry_ecc_fill_in_curve (0, curvename, &pk.E, NULL);
if (rc)
return rc;
}
}
/* Guess required fields if a curve parameter has not been given.
FIXME: This is a crude hacks. We need to fix that. */
if (!curvename)
{
pk.E.model = ((sigflags & PUBKEY_FLAG_EDDSA)
? MPI_EC_TWISTEDEDWARDS
: MPI_EC_WEIERSTRASS);
pk.E.dialect = ((sigflags & PUBKEY_FLAG_EDDSA)
? ECC_DIALECT_ED25519
: ECC_DIALECT_STANDARD);
}
if (DBG_CIPHER)
{
log_debug ("ecc_verify info: %s/%s\n",
_gcry_ecc_model2str (pk.E.model),
_gcry_ecc_dialect2str (pk.E.dialect));
if (pk.E.name)
log_debug ("ecc_verify name: %s\n", pk.E.name);
log_printmpi ("ecc_verify p", pk.E.p);
log_printmpi ("ecc_verify a", pk.E.a);
log_printmpi ("ecc_verify b", pk.E.b);
log_printpnt ("ecc_verify g", &pk.E.G, NULL);
log_printmpi ("ecc_verify n", pk.E.n);
log_printmpi ("ecc_verify q", mpi_q);
}
if (!pk.E.p || !pk.E.a || !pk.E.b || !pk.E.G.x || !pk.E.n || !mpi_q)
{
rc = GPG_ERR_NO_OBJ;
goto leave;
}
/*
* Verify the signature.
*/
if ((sigflags & PUBKEY_FLAG_EDDSA))
{
rc = verify_eddsa (data, &pk, sig_r, sig_s, ctx.hash_algo, mpi_q);
}
else
{
point_init (&pk.Q);
rc = _gcry_ecc_os2ec (&pk.Q, mpi_q);
if (rc)
goto leave;
if (mpi_is_opaque (data))
{
const void *abuf;
unsigned int abits, qbits;
gcry_mpi_t a;
qbits = mpi_get_nbits (pk.E.n);
abuf = gcry_mpi_get_opaque (data, &abits);
rc = gpg_err_code (gcry_mpi_scan (&a, GCRYMPI_FMT_USG,
abuf, (abits+7)/8, NULL));
if (!rc)
{
if (abits > qbits)
gcry_mpi_rshift (a, a, abits - qbits);
rc = verify_ecdsa (a, &pk, sig_r, sig_s);
gcry_mpi_release (a);
}
}
else
rc = verify_ecdsa (data, &pk, sig_r, sig_s);
}
leave:
gcry_mpi_release (pk.E.p);
gcry_mpi_release (pk.E.a);
gcry_mpi_release (pk.E.b);
gcry_mpi_release (mpi_g);
point_free (&pk.E.G);
gcry_mpi_release (pk.E.n);
gcry_mpi_release (mpi_q);
point_free (&pk.Q);
gcry_mpi_release (data);
gcry_mpi_release (sig_r);
gcry_mpi_release (sig_s);
gcry_free (curvename);
gcry_sexp_release (l1);
_gcry_pk_util_free_encoding_ctx (&ctx);
if (DBG_CIPHER)
log_debug ("ecc_verify => %s\n", rc?gpg_strerror (rc):"Good");
return rc;
}
/* 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: A new S-expression with the parameters:
* s : shared point (kdG)
* e : 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 (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
{
gcry_err_code_t rc;
struct pk_encoding_ctx ctx;
gcry_sexp_t l1 = NULL;
char *curvename = NULL;
gcry_mpi_t mpi_g = NULL;
gcry_mpi_t mpi_q = NULL;
gcry_mpi_t mpi_s = NULL;
gcry_mpi_t mpi_e = NULL;
gcry_mpi_t data = NULL;
ECC_public_key pk;
mpi_ec_t ec = NULL;
memset (&pk, 0, sizeof pk);
_gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT,
ecc_get_nbits (keyparms));
/*
* Extract the data.
*/
rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
if (rc)
goto leave;
if (DBG_CIPHER)
log_mpidump ("ecc_encrypt data", data);
if (mpi_is_opaque (data))
{
rc = GPG_ERR_INV_DATA;
goto leave;
}
/*
* Extract the key.
*/
rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+q",
&pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
&mpi_q, NULL);
if (rc)
goto leave;
if (mpi_g)
{
point_init (&pk.E.G);
rc = _gcry_ecc_os2ec (&pk.E.G, mpi_g);
if (rc)
goto leave;
}
/* Add missing parameters using the optional curve parameter. */
gcry_sexp_release (l1);
l1 = gcry_sexp_find_token (keyparms, "curve", 5);
if (l1)
{
curvename = gcry_sexp_nth_string (l1, 1);
if (curvename)
{
rc = _gcry_ecc_fill_in_curve (0, curvename, &pk.E, NULL);
if (rc)
return rc;
}
}
/* Guess required fields if a curve parameter has not been given. */
if (!curvename)
{
pk.E.model = MPI_EC_WEIERSTRASS;
pk.E.dialect = ECC_DIALECT_STANDARD;
}
if (DBG_CIPHER)
{
log_debug ("ecc_encrypt info: %s/%s\n",
_gcry_ecc_model2str (pk.E.model),
_gcry_ecc_dialect2str (pk.E.dialect));
if (pk.E.name)
log_debug ("ecc_encrypt name: %s\n", pk.E.name);
log_printmpi ("ecc_encrypt p", pk.E.p);
log_printmpi ("ecc_encrypt a", pk.E.a);
log_printmpi ("ecc_encrypt b", pk.E.b);
log_printpnt ("ecc_encrypt g", &pk.E.G, NULL);
log_printmpi ("ecc_encrypt n", pk.E.n);
log_printmpi ("ecc_encrypt q", mpi_q);
}
if (!pk.E.p || !pk.E.a || !pk.E.b || !pk.E.G.x || !pk.E.n || !mpi_q)
{
rc = GPG_ERR_NO_OBJ;
goto leave;
}
/* Convert the public key. */
if (mpi_q)
{
point_init (&pk.Q);
rc = _gcry_ecc_os2ec (&pk.Q, mpi_q);
if (rc)
goto leave;
}
/* Compute the encrypted value. */
ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect,
pk.E.p, pk.E.a, pk.E.b);
/* 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, data, &pk.Q, ec);
if (_gcry_mpi_ec_get_affine (x, y, &R, ec))
log_fatal ("ecdh: Failed to get affine coordinates for kdG\n");
mpi_s = _gcry_ecc_ec2os (x, y, pk.E.p);
/* R = kG */
_gcry_mpi_ec_mul_point (&R, data, &pk.E.G, ec);
if (_gcry_mpi_ec_get_affine (x, y, &R, ec))
log_fatal ("ecdh: Failed to get affine coordinates for kG\n");
mpi_e = _gcry_ecc_ec2os (x, y, pk.E.p);
mpi_free (x);
mpi_free (y);
point_free (&R);
}
rc = gcry_sexp_build (r_ciph, NULL, "(enc-val(ecdh(s%m)(e%m)))",
mpi_s, mpi_e);
leave:
gcry_mpi_release (pk.E.p);
gcry_mpi_release (pk.E.a);
gcry_mpi_release (pk.E.b);
gcry_mpi_release (mpi_g);
point_free (&pk.E.G);
gcry_mpi_release (pk.E.n);
gcry_mpi_release (mpi_q);
point_free (&pk.Q);
gcry_mpi_release (data);
gcry_mpi_release (mpi_s);
gcry_mpi_release (mpi_e);
gcry_free (curvename);
_gcry_mpi_ec_free (ec);
_gcry_pk_util_free_encoding_ctx (&ctx);
if (DBG_CIPHER)
log_debug ("ecc_encrypt => %s\n", gpg_strerror (rc));
return rc;
}
/* 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_sexp_t *r_plain, gcry_mpi_t *data,
- gcry_mpi_t *skey, int flags,
- enum pk_encoding encoding, int hash_algo,
- unsigned char *label, size_t labellen)
+ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
{
gpg_err_code_t rc;
+ struct pk_encoding_ctx ctx;
+ gcry_sexp_t l1 = NULL;
+ gcry_mpi_t data_e = NULL;
ECC_secret_key sk;
- mpi_point_struct R; /* Result that we return. */
+ gcry_mpi_t mpi_g = NULL;
+ char *curvename = NULL;
+ mpi_ec_t ec = NULL;
mpi_point_struct kG;
- mpi_ec_t ctx;
- gcry_mpi_t r;
-
- (void)algo;
- (void)flags;
- (void)encoding;
- (void)hash_algo;
- (void)label;
- (void)labellen;
-
- if (!data || !data[0]
- || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4]
- || !skey[5] || !skey[6] )
- return GPG_ERR_BAD_MPI;
+ mpi_point_struct R;
+ gcry_mpi_t r = NULL;
+ memset (&sk, 0, sizeof sk);
point_init (&kG);
- rc = _gcry_ecc_os2ec (&kG, data[0]);
+ point_init (&R);
+
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT,
+ ecc_get_nbits (keyparms));
+
+ /*
+ * Extract the data.
+ */
+ rc = _gcry_pk_util_preparse_encval (s_data, ecc_names, &l1, &ctx);
if (rc)
+ goto leave;
+ rc = _gcry_pk_util_extract_mpis (l1, "e", &data_e, NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ log_printmpi ("ecc_decrypt d_e", data_e);
+ if (mpi_is_opaque (data_e))
{
- point_free (&kG);
- return rc;
+ rc = GPG_ERR_INV_DATA;
+ goto leave;
}
- sk.E.model = MPI_EC_WEIERSTRASS;
- sk.E.p = skey[0];
- sk.E.a = skey[1];
- sk.E.b = skey[2];
- point_init (&sk.E.G);
- rc = _gcry_ecc_os2ec (&sk.E.G, skey[3]);
+ /*
+ * Extract the key.
+ */
+ rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+d",
+ &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
+ &sk.d, NULL);
if (rc)
+ goto leave;
+ if (mpi_g)
{
- point_free (&kG);
- point_free (&sk.E.G);
- return rc;
+ point_init (&sk.E.G);
+ rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g);
+ if (rc)
+ goto leave;
}
- sk.E.n = skey[4];
- point_init (&sk.Q);
- rc = _gcry_ecc_os2ec (&sk.Q, skey[5]);
+ /* Add missing parameters using the optional curve parameter. */
+ gcry_sexp_release (l1);
+ l1 = gcry_sexp_find_token (keyparms, "curve", 5);
+ if (l1)
+ {
+ curvename = gcry_sexp_nth_string (l1, 1);
+ if (curvename)
+ {
+ rc = _gcry_ecc_fill_in_curve (0, curvename, &sk.E, NULL);
+ if (rc)
+ return rc;
+ }
+ }
+ /* Guess required fields if a curve parameter has not been given. */
+ if (!curvename)
+ {
+ sk.E.model = MPI_EC_WEIERSTRASS;
+ sk.E.dialect = ECC_DIALECT_STANDARD;
+ }
+ if (DBG_CIPHER)
+ {
+ log_debug ("ecc_decrypt info: %s/%s\n",
+ _gcry_ecc_model2str (sk.E.model),
+ _gcry_ecc_dialect2str (sk.E.dialect));
+ if (sk.E.name)
+ log_debug ("ecc_decrypt name: %s\n", sk.E.name);
+ log_printmpi ("ecc_decrypt p", sk.E.p);
+ log_printmpi ("ecc_decrypt a", sk.E.a);
+ log_printmpi ("ecc_decrypt b", sk.E.b);
+ log_printpnt ("ecc_decrypt g", &sk.E.G, NULL);
+ log_printmpi ("ecc_decrypt n", sk.E.n);
+ if (!fips_mode ())
+ log_printmpi ("ecc_decrypt d", sk.d);
+ }
+ if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.d)
+ {
+ rc = GPG_ERR_NO_OBJ;
+ goto leave;
+ }
+
+
+ /*
+ * Compute the plaintext.
+ */
+ rc = _gcry_ecc_os2ec (&kG, data_e);
if (rc)
{
point_free (&kG);
- point_free (&sk.E.G);
- point_free (&sk.Q);
return rc;
}
- sk.d = skey[6];
- ctx = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect,
- sk.E.p, sk.E.a, sk.E.b);
+ ec = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect,
+ sk.E.p, sk.E.a, sk.E.b);
/* R = dkG */
- point_init (&R);
- _gcry_mpi_ec_mul_point (&R, sk.d, &kG, ctx);
-
- point_free (&kG);
+ _gcry_mpi_ec_mul_point (&R, sk.d, &kG, ec);
/* 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))
+ if (_gcry_mpi_ec_get_affine (x, y, &R, ec))
log_fatal ("ecdh: Failed to get affine coordinates\n");
r = _gcry_ecc_ec2os (x, y, sk.E.p);
if (!r)
rc = gpg_err_code_from_syserror ();
else
rc = 0;
mpi_free (x);
mpi_free (y);
}
+ if (DBG_CIPHER)
+ log_printmpi ("ecc_decrypt res", r);
+
+ if (!rc)
+ rc = gcry_sexp_build (r_plain, NULL, "(value %m)", r);
+ leave:
point_free (&R);
- _gcry_mpi_ec_free (ctx);
point_free (&kG);
+ gcry_mpi_release (r);
+ gcry_mpi_release (sk.E.p);
+ gcry_mpi_release (sk.E.a);
+ gcry_mpi_release (sk.E.b);
+ gcry_mpi_release (mpi_g);
point_free (&sk.E.G);
- point_free (&sk.Q);
-
- if (!rc)
- rc = gcry_sexp_build (r_plain, NULL, "(value %m)", r);
- mpi_free (r);
+ gcry_mpi_release (sk.E.n);
+ gcry_mpi_release (sk.d);
+ gcry_mpi_release (data_e);
+ gcry_free (curvename);
+ gcry_sexp_release (l1);
+ _gcry_mpi_ec_free (ec);
+ _gcry_pk_util_free_encoding_ctx (&ctx);
+ if (DBG_CIPHER)
+ log_debug ("ecc_decrypt => %s\n", gpg_strerror (rc));
return rc;
}
/* Return the number of bits for the key described by PARMS. On error
* 0 is returned. The format of PARMS starts with the algorithm name;
* for example:
*
* (ecc
* (p <mpi>)
* (a <mpi>)
* (b <mpi>)
* (g <mpi>)
* (n <mpi>)
* (q <mpi>))
*
* More parameters may be given currently P is needed. FIXME: We
* need allow for a "curve" parameter.
*/
static unsigned int
ecc_get_nbits (gcry_sexp_t parms)
{
gcry_sexp_t l1;
gcry_mpi_t p;
unsigned int nbits = 0;
char *curve;
l1 = gcry_sexp_find_token (parms, "p", 1);
if (!l1)
{ /* Parameter P not found - check whether we have "curve". */
l1 = gcry_sexp_find_token (parms, "curve", 5);
if (!l1)
return 0; /* Neither P nor CURVE found. */
curve = _gcry_sexp_nth_string (l1, 1);
gcry_sexp_release (l1);
if (!curve)
return 0; /* No curve name given (or out of core). */
if (_gcry_ecc_fill_in_curve (0, curve, NULL, &nbits))
nbits = 0;
gcry_free (curve);
}
else
{
p = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l1);
if (p)
{
nbits = mpi_get_nbits (p);
gcry_mpi_release (p);
}
}
return nbits;
}
/* 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 = _gcry_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], 0, &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.
*/
/* This is the worker 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_ecc_compute_public (NULL, 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;
}
if (ec->dialect == ECC_DIALECT_ED25519)
{
unsigned char *encpk;
unsigned int encpklen;
rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL,
&encpk, &encpklen);
if (rc)
goto leave;
mpi_Q = gcry_mpi_set_opaque (NULL, encpk, encpklen*8);
encpk = NULL;
}
else
{
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 = 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 = 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_ECC, 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)
{
(void)extended;
if (algo != GCRY_PK_ECC)
return GPG_ERR_PUBKEY_ALGO;
return selftests_ecdsa (report);
}
gcry_pk_spec_t _gcry_pubkey_spec_ecc =
{
GCRY_PK_ECC, { 0, 0 },
(GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR),
"ECC", ecc_names,
"pabgnq", "pabgnqd", "sw", "rs", "pabgnq",
ecc_generate,
ecc_check_secret_key,
ecc_encrypt_raw,
ecc_decrypt_raw,
ecc_sign,
ecc_verify,
ecc_get_nbits,
run_selftests,
compute_keygrip,
_gcry_ecc_get_param,
_gcry_ecc_get_curve,
_gcry_ecc_get_param_sexp
};
diff --git a/cipher/elgamal.c b/cipher/elgamal.c
index 37182874..7fedc7bf 100644
--- a/cipher/elgamal.c
+++ b/cipher/elgamal.c
@@ -1,1061 +1,1094 @@
/* Elgamal.c - Elgamal Public Key encryption
* Copyright (C) 1998, 2000, 2001, 2002, 2003,
* 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/>.
*
* 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"
#include "pubkey-internal.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 const char *elg_names[] =
{
"elg",
"openpgp-elg",
"openpgp-elg-sig",
NULL,
};
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 unsigned int elg_get_nbits (gcry_sexp_t parms);
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\n");
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\n", 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 (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
{
gpg_err_code_t rc;
unsigned int nbits;
ELG_secret_key sk;
gcry_mpi_t xvalue = NULL;
gcry_sexp_t l1;
gcry_mpi_t *factors = NULL;
gcry_sexp_t misc_info = NULL;
memset (&sk, 0, sizeof sk);
rc = _gcry_pk_util_get_nbits (genparms, &nbits);
if (rc)
return rc;
/* 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)
{
rc = generate_using_x (&sk, nbits, xvalue, &factors);
mpi_free (xvalue);
}
else
{
generate (&sk, nbits, &factors);
rc = 0;
}
if (rc)
goto leave;
if (factors && factors[0])
{
int nfac;
void **arg_list;
char *buffer, *p;
for (nfac = 0; factors[nfac]; nfac++)
;
arg_list = gcry_calloc (nfac+1, sizeof *arg_list);
if (!arg_list)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
buffer = gcry_malloc (30 + nfac*2 + 2 + 1);
if (!buffer)
{
rc = gpg_err_code_from_syserror ();
gcry_free (arg_list);
goto leave;
}
p = stpcpy (buffer, "(misc-key-info(pm1-factors");
for(nfac = 0; factors[nfac]; nfac++)
{
p = stpcpy (p, "%m");
arg_list[nfac] = factors + nfac;
}
p = stpcpy (p, "))");
rc = gcry_sexp_build_array (&misc_info, NULL, buffer, arg_list);
gcry_free (arg_list);
gcry_free (buffer);
if (rc)
goto leave;
}
rc = gcry_sexp_build (r_skey, NULL,
"(key-data"
" (public-key"
" (elg(p%m)(g%m)(y%m)))"
" (private-key"
" (elg(p%m)(g%m)(y%m)(x%m)))"
" %S)",
sk.p, sk.g, sk.y,
sk.p, sk.g, sk.y, sk.x,
misc_info);
leave:
mpi_free (sk.p);
mpi_free (sk.g);
mpi_free (sk.y);
mpi_free (sk.x);
gcry_sexp_release (misc_info);
if (factors)
{
gcry_mpi_t *mp;
for (mp = factors; *mp; mp++)
mpi_free (*mp);
gcry_free (factors);
}
return rc;
}
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 (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
{
gcry_err_code_t rc;
struct pk_encoding_ctx ctx;
gcry_mpi_t mpi_a = NULL;
gcry_mpi_t mpi_b = NULL;
gcry_mpi_t data = NULL;
ELG_public_key pk = { NULL, NULL, NULL };
_gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT,
elg_get_nbits (keyparms));
/* Extract the data. */
rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
if (rc)
goto leave;
if (DBG_CIPHER)
log_mpidump ("elg_encrypt data", data);
if (mpi_is_opaque (data))
{
rc = GPG_ERR_INV_DATA;
goto leave;
}
/* Extract the key. */
rc = _gcry_pk_util_extract_mpis (keyparms, "pgy", &pk.p, &pk.g, &pk.y, NULL);
if (rc)
return rc;
if (DBG_CIPHER)
{
log_mpidump ("elg_encrypt p", pk.p);
log_mpidump ("elg_encrypt g", pk.g);
log_mpidump ("elg_encrypt y", pk.y);
}
/* Do Elgamal computation and build result. */
mpi_a = gcry_mpi_new (0);
mpi_b = gcry_mpi_new (0);
do_encrypt (mpi_a, mpi_b, data, &pk);
rc = gcry_sexp_build (r_ciph, NULL, "(enc-val(elg(a%m)(b%m)))", mpi_a, mpi_b);
leave:
gcry_mpi_release (mpi_a);
gcry_mpi_release (mpi_b);
gcry_mpi_release (pk.p);
gcry_mpi_release (pk.g);
gcry_mpi_release (pk.y);
gcry_mpi_release (data);
_gcry_pk_util_free_encoding_ctx (&ctx);
if (DBG_CIPHER)
log_debug ("elg_encrypt => %s\n", gpg_strerror (rc));
return rc;
}
static gcry_err_code_t
-elg_decrypt (int algo, gcry_sexp_t *r_plain,
- gcry_mpi_t *data, gcry_mpi_t *skey, int flags,
- enum pk_encoding encoding, int hash_algo,
- unsigned char *label, size_t labellen)
+elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
{
- gcry_err_code_t rc;
- ELG_secret_key sk;
- gcry_mpi_t plain;
+ gpg_err_code_t rc;
+ struct pk_encoding_ctx ctx;
+ gcry_sexp_t l1 = NULL;
+ gcry_mpi_t data_a = NULL;
+ gcry_mpi_t data_b = NULL;
+ ELG_secret_key sk = {NULL, NULL, NULL, NULL};
+ gcry_mpi_t plain = NULL;
+ unsigned char *unpad = NULL;
+ size_t unpadlen = 0;
- (void)algo;
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT,
+ elg_get_nbits (keyparms));
- if ((! data[0]) || (! data[1])
- || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]))
- rc = GPG_ERR_BAD_MPI;
- else
+ /* Extract the data. */
+ rc = _gcry_pk_util_preparse_encval (s_data, elg_names, &l1, &ctx);
+ if (rc)
+ goto leave;
+ rc = _gcry_pk_util_extract_mpis (l1, "ab", &data_a, &data_b, NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
{
- unsigned char *unpad = NULL;
- size_t unpadlen = 0;
- unsigned int nbits;
+ log_printmpi ("elg_decrypt d_a", data_a);
+ log_printmpi ("elg_decrypt d_b", data_b);
+ }
+ if (mpi_is_opaque (data_a) || mpi_is_opaque (data_b))
+ {
+ rc = GPG_ERR_INV_DATA;
+ goto leave;
+ }
- sk.p = skey[0];
- sk.g = skey[1];
- sk.y = skey[2];
- sk.x = skey[3];
+ /* Extract the key. */
+ rc = _gcry_pk_util_extract_mpis (keyparms, "pgyx",
+ &sk.p, &sk.g, &sk.y, &sk.x,
+ NULL);
+ if (rc)
+ return rc;
+ if (DBG_CIPHER)
+ {
+ log_printmpi ("elg_decrypt p", sk.p);
+ log_printmpi ("elg_decrypt g", sk.g);
+ log_printmpi ("elg_decrypt y", sk.y);
+ if (!fips_mode ())
+ log_printmpi ("elg_decrypt x", sk.x);
+ }
- nbits = gcry_mpi_get_nbits (sk.p);
+ plain = gcry_mpi_snew (ctx.nbits);
+ decrypt (plain, data_a, data_b, &sk);
+ if (DBG_CIPHER)
+ log_printmpi ("elg_decrypt res", plain);
- plain = mpi_snew (nbits);
- decrypt (plain, data[0], data[1], &sk);
+ /* Reverse the encoding and build the s-expression. */
+ switch (ctx.encoding)
+ {
+ case PUBKEY_ENC_PKCS1:
+ rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain);
+ mpi_free (plain); plain = NULL;
+ if (!rc)
+ rc = gcry_sexp_build (r_plain, NULL, "(value %b)",
+ (int)unpadlen, unpad);
+ break;
+
+ case PUBKEY_ENC_OAEP:
+ rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen,
+ ctx.nbits, ctx.hash_algo, plain,
+ ctx.label, ctx.labellen);
+ mpi_free (plain); plain = NULL;
+ if (!rc)
+ rc = 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_sexp_build (r_plain, NULL,
+ (ctx.flags & PUBKEY_FLAG_LEGACYRESULT)
+ ? "%m" : "(value %m)",
+ plain);
+ break;
+ }
- /* Reverse the encoding and build the s-expression. */
- switch (encoding)
- {
- case PUBKEY_ENC_PKCS1:
- rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, nbits, plain);
- mpi_free (plain);
- plain = NULL;
- if (!rc)
- rc = gcry_sexp_build (r_plain, NULL, "(value %b)",
- (int)unpadlen, unpad);
- break;
-
- case PUBKEY_ENC_OAEP:
- rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen,
- nbits, hash_algo, plain, label, labellen);
- mpi_free (plain);
- plain = NULL;
- if (!rc)
- rc = 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_sexp_build (r_plain, NULL,
- (flags & PUBKEY_FLAG_LEGACYRESULT)
- ? "%m" : "(value %m)",
- plain);
- break;
- }
- gcry_free (unpad);
- mpi_free (plain);
- }
+ leave:
+ gcry_free (unpad);
+ gcry_mpi_release (plain);
+ gcry_mpi_release (sk.p);
+ gcry_mpi_release (sk.g);
+ gcry_mpi_release (sk.y);
+ gcry_mpi_release (sk.x);
+ gcry_mpi_release (data_a);
+ gcry_mpi_release (data_b);
+ gcry_sexp_release (l1);
+ _gcry_pk_util_free_encoding_ctx (&ctx);
+ if (DBG_CIPHER)
+ log_debug ("elg_decrypt => %s\n", gpg_strerror (rc));
return rc;
}
static gcry_err_code_t
elg_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
{
gcry_err_code_t rc;
struct pk_encoding_ctx ctx;
gcry_mpi_t data = NULL;
ELG_secret_key sk = {NULL, NULL, NULL, NULL};
gcry_mpi_t sig_r = NULL;
gcry_mpi_t sig_s = NULL;
_gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN,
elg_get_nbits (keyparms));
/* Extract the data. */
rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
if (rc)
goto leave;
if (DBG_CIPHER)
log_mpidump ("elg_sign data", data);
if (mpi_is_opaque (data))
{
rc = GPG_ERR_INV_DATA;
goto leave;
}
/* Extract the key. */
rc = _gcry_pk_util_extract_mpis (keyparms, "pgyx",
&sk.p, &sk.g, &sk.y, &sk.x, NULL);
if (rc)
return rc;
if (DBG_CIPHER)
{
log_mpidump ("elg_sign p", sk.p);
log_mpidump ("elg_sign g", sk.g);
log_mpidump ("elg_sign y", sk.y);
if (!fips_mode ())
log_mpidump ("elg_sign x", sk.x);
}
sig_r = gcry_mpi_new (0);
sig_s = gcry_mpi_new (0);
sign (sig_r, sig_s, data, &sk);
if (DBG_CIPHER)
{
log_mpidump ("elg_sign sig_r", sig_r);
log_mpidump ("elg_sign sig_s", sig_s);
}
rc = gcry_sexp_build (r_sig, NULL, "(sig-val(elg(r%M)(s%M)))", sig_r, sig_s);
leave:
gcry_mpi_release (sig_r);
gcry_mpi_release (sig_s);
gcry_mpi_release (sk.p);
gcry_mpi_release (sk.g);
gcry_mpi_release (sk.y);
gcry_mpi_release (sk.x);
gcry_mpi_release (data);
_gcry_pk_util_free_encoding_ctx (&ctx);
if (DBG_CIPHER)
log_debug ("elg_sign => %s\n", gpg_strerror (rc));
return rc;
}
static gcry_err_code_t
elg_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
{
gcry_err_code_t rc;
struct pk_encoding_ctx ctx;
gcry_sexp_t l1 = NULL;
gcry_mpi_t sig_r = NULL;
gcry_mpi_t sig_s = NULL;
gcry_mpi_t data = NULL;
ELG_public_key pk = { NULL, NULL, NULL };
_gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY,
elg_get_nbits (s_keyparms));
/* Extract the data. */
rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
if (rc)
goto leave;
if (DBG_CIPHER)
log_mpidump ("elg_verify data", data);
if (mpi_is_opaque (data))
{
rc = GPG_ERR_INV_DATA;
goto leave;
}
/* Extract the signature value. */
rc = _gcry_pk_util_preparse_sigval (s_sig, elg_names, &l1, NULL);
if (rc)
goto leave;
rc = _gcry_pk_util_extract_mpis (l1, "rs", &sig_r, &sig_s, NULL);
if (rc)
goto leave;
if (DBG_CIPHER)
{
log_mpidump ("elg_verify s_r", sig_r);
log_mpidump ("elg_verify s_s", sig_s);
}
/* Extract the key. */
rc = _gcry_pk_util_extract_mpis (s_keyparms, "pgy",
&pk.p, &pk.g, &pk.y, NULL);
if (rc)
return rc;
if (DBG_CIPHER)
{
log_mpidump ("elg_verify p", pk.p);
log_mpidump ("elg_verify g", pk.g);
log_mpidump ("elg_verify y", pk.y);
}
/* Verify the signature. */
if (!verify (sig_r, sig_s, data, &pk))
rc = GPG_ERR_BAD_SIGNATURE;
leave:
gcry_mpi_release (pk.p);
gcry_mpi_release (pk.g);
gcry_mpi_release (pk.y);
gcry_mpi_release (data);
gcry_mpi_release (sig_r);
gcry_mpi_release (sig_s);
gcry_sexp_release (l1);
_gcry_pk_util_free_encoding_ctx (&ctx);
if (DBG_CIPHER)
log_debug ("elg_verify => %s\n", rc?gpg_strerror (rc):"Good");
return rc;
}
/* Return the number of bits for the key described by PARMS. On error
* 0 is returned. The format of PARMS starts with the algorithm name;
* for example:
*
* (dsa
* (p <mpi>)
* (g <mpi>)
* (y <mpi>))
*
* More parameters may be given but we only need P here.
*/
static unsigned int
elg_get_nbits (gcry_sexp_t parms)
{
gcry_sexp_t l1;
gcry_mpi_t p;
unsigned int nbits;
l1 = gcry_sexp_find_token (parms, "p", 1);
if (!l1)
return 0; /* Parameter P not found. */
p= gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l1);
nbits = p? mpi_get_nbits (p) : 0;
gcry_mpi_release (p);
return nbits;
}
gcry_pk_spec_t _gcry_pubkey_spec_elg =
{
GCRY_PK_ELG, { 0, 0 },
(GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR),
"ELG", elg_names,
"pgy", "pgyx", "ab", "rs", "pgy",
elg_generate,
elg_check_secret_key,
elg_encrypt,
elg_decrypt,
elg_sign,
elg_verify,
elg_get_nbits,
};
diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h
index 3bed609a..7e3667e9 100644
--- a/cipher/pubkey-internal.h
+++ b/cipher/pubkey-internal.h
@@ -1,93 +1,97 @@
/* pubkey-internal.h - Internal defs for pubkey.c
* 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/>.
*/
#ifndef GCRY_PUBKEY_INTERNAL_H
#define GCRY_PUBKEY_INTERNAL_H
/*-- pubkey-util.c --*/
gpg_err_code_t _gcry_pk_util_get_nbits (gcry_sexp_t list,
unsigned int *r_nbits);
gpg_err_code_t _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list,
unsigned long *r_e);
gpg_err_code_t _gcry_pk_util_extract_mpis (gcry_sexp_t sexp,
const char *list, ...)
GCC_ATTR_SENTINEL(0);
gpg_err_code_t _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig,
const char **algo_names,
gcry_sexp_t *r_parms,
int *r_eccflags);
+gpg_err_code_t _gcry_pk_util_preparse_encval (gcry_sexp_t sexp,
+ const char **algo_names,
+ gcry_sexp_t *r_parms,
+ struct pk_encoding_ctx *ctx);
void _gcry_pk_util_init_encoding_ctx (struct pk_encoding_ctx *ctx,
enum pk_operation op,
unsigned int nbits);
void _gcry_pk_util_free_encoding_ctx (struct pk_encoding_ctx *ctx);
gcry_err_code_t _gcry_pk_util_data_to_mpi (gcry_sexp_t input,
gcry_mpi_t *ret_mpi,
struct pk_encoding_ctx *ctx);
/*-- rsa-common.c --*/
gpg_err_code_t
_gcry_rsa_pkcs1_encode_for_enc (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);
gpg_err_code_t
_gcry_rsa_pkcs1_decode_for_enc (unsigned char **r_result, size_t *r_resultlen,
unsigned int nbits, gcry_mpi_t value);
gpg_err_code_t
_gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits,
const unsigned char *value, size_t valuelen,
int algo);
gpg_err_code_t
_gcry_rsa_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);
gpg_err_code_t
_gcry_rsa_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);
gpg_err_code_t
_gcry_rsa_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);
gpg_err_code_t
_gcry_rsa_pss_verify (gcry_mpi_t value, gcry_mpi_t encoded,
unsigned int nbits, int algo, size_t saltlen);
/*-- dsa-common.c --*/
gcry_mpi_t _gcry_dsa_gen_k (gcry_mpi_t q, int security_level);
gpg_err_code_t _gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k,
gcry_mpi_t dsa_q, gcry_mpi_t dsa_x,
const unsigned char *h1,
unsigned int h1len,
int halgo,
unsigned int extraloops);
/*-- ecc.c --*/
gpg_err_code_t _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode,
mpi_ec_t ec);
#endif /*GCRY_PUBKEY_INTERNAL_H*/
diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c
index debe6ca6..9a94fe27 100644
--- a/cipher/pubkey-util.c
+++ b/cipher/pubkey-util.c
@@ -1,894 +1,1079 @@
/* pubkey-util.c - Supporting functions for all pubkey modules.
* 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 "g10lib.h"
#include "mpi.h"
#include "cipher.h"
#include "pubkey-internal.h"
/* 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 _gcry_rsa_pss_verify (hash, tmp, ctx->nbits - 1,
ctx->hash_algo, ctx->saltlen);
}
+static 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;
+}
+
/* Get the "nbits" parameter from an s-expression of the format:
*
* (algo
* (parameter_name_1 ....)
* ....
* (parameter_name_n ....))
*
* Example:
*
* (rsa
* (nbits 4:2048))
*
* On success the value for nbits is stored at R_NBITS. If no nbits
* parameter is found, the function returns success and stores 0 at
* R_NBITS. For parsing errors the function returns an error code and
* stores 0 at R_NBITS.
*/
gpg_err_code_t
_gcry_pk_util_get_nbits (gcry_sexp_t list, unsigned int *r_nbits)
{
char buf[50];
const char *s;
size_t n;
*r_nbits = 0;
list = gcry_sexp_find_token (list, "nbits", 0);
if (!list)
return 0; /* No NBITS found. */
s = gcry_sexp_nth_data (list, 1, &n);
if (!s || n >= DIM (buf) - 1 )
{
/* NBITS given without a cdr. */
gcry_sexp_release (list);
return GPG_ERR_INV_OBJ;
}
memcpy (buf, s, n);
buf[n] = 0;
*r_nbits = (unsigned int)strtoul (buf, NULL, 0);
gcry_sexp_release (list);
return 0;
}
/* Get the optional "rsa-use-e" parameter from an s-expression of the
* format:
*
* (algo
* (parameter_name_1 ....)
* ....
* (parameter_name_n ....))
*
* Example:
*
* (rsa
* (nbits 4:2048)
* (rsa-use-e 2:41))
*
* On success the value for nbits is stored at R_E. If no rsa-use-e
* parameter is found, the function returns success and stores 65537 at
* R_E. For parsing errors the function returns an error code and
* stores 0 at R_E.
*/
gpg_err_code_t
_gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, unsigned long *r_e)
{
char buf[50];
const char *s;
size_t n;
*r_e = 0;
list = gcry_sexp_find_token (list, "rsa-use-e", 0);
if (!list)
{
*r_e = 65537; /* Not given, use the value generated by old versions. */
return 0;
}
s = gcry_sexp_nth_data (list, 1, &n);
if (!s || n >= DIM (buf) - 1 )
{
/* No value or value too large. */
gcry_sexp_release (list);
return GPG_ERR_INV_OBJ;
}
memcpy (buf, s, n);
buf[n] = 0;
*r_e = strtoul (buf, NULL, 0);
gcry_sexp_release (list);
return 0;
}
/* Extract MPIs from an s-expression using a list of one letter
* parameters. The names of these parameters are given by the string
* LIST. Some special characters may be given to control the
* conversion:
*
* + :: Switch to unsigned integer format (default).
* - :: Switch to standard signed format.
* / :: Switch to opaque format.
* ? :: The previous parameter is optional.
*
* For each parameter name a pointer to an MPI variable is expected
* and finally a NULL is expected. Example:
*
* _gcry_pk_util_extract_mpis (key, "n/x+ed", &mpi_n, &mpi_x, &mpi_e, NULL)
*
* This stores the parameter "N" from KEY as an unsigned MPI into
* MPI_N, the parameter "X" as an opaque MPI into MPI_X, and the
* parameter "E" again as an unsigned MPI into MPI_E.
*
* The function returns NULL on success. On error an error code is
* returned and and the passed MPIs have no defined value.
*/
gpg_err_code_t
_gcry_pk_util_extract_mpis (gcry_sexp_t sexp, const char *list, ...)
{
va_list arg_ptr;
const char *s;
gcry_mpi_t *array[10];
int idx;
gcry_sexp_t l1;
enum gcry_mpi_format mpifmt = GCRYMPI_FMT_USG;
/* First copy all the args into an array. This is required so that
we are able to release already allocated MPIs if later an error
was found. */
va_start (arg_ptr, list) ;
for (s=list, idx=0; *s && idx < DIM (array); s++)
{
if (*s == '+' || *s == '-' || *s == '/' || *s == '?')
;
else
{
array[idx] = va_arg (arg_ptr, gcry_mpi_t *);
if (!array[idx])
{
va_end (arg_ptr);
return GPG_ERR_INTERNAL; /* NULL pointer given. */
}
idx++;
}
}
if (*s)
{
va_end (arg_ptr);
return GPG_ERR_INTERNAL; /* Too many list elements. */
}
if (va_arg (arg_ptr, gcry_mpi_t *))
{
va_end (arg_ptr);
return GPG_ERR_INTERNAL; /* Not enough list elemends. */
}
va_end (arg_ptr);
/* Now extract all parameters. */
for (s=list, idx=0; *s; s++)
{
if (*s == '+')
mpifmt = GCRYMPI_FMT_USG;
else if (*s == '-')
mpifmt = GCRYMPI_FMT_STD;
else if (*s == '/')
mpifmt = GCRYMPI_FMT_HEX; /* Used to indicate opaque. */
else if (*s == '?')
; /* Only used via lookahead. */
else
{
l1 = gcry_sexp_find_token (sexp, s, 1);
if (!l1 && s[1] == '?')
*array[idx] = NULL; /* Optional element not found. */
else if (!l1)
{
while (idx--)
gcry_mpi_release (*array[idx]);
return GPG_ERR_NO_OBJ; /* List element not found. */
}
else
{
if (mpifmt == GCRYMPI_FMT_HEX)
*array[idx] = _gcry_sexp_nth_opaque_mpi (l1, 1);
else
*array[idx] = gcry_sexp_nth_mpi (l1, 1, mpifmt);
gcry_sexp_release (l1);
if (!*array[idx])
{
while (idx--)
gcry_mpi_release (*array[idx]);
return GPG_ERR_INV_OBJ; /* Conversion failed. */
}
}
idx++;
}
}
return 0;
}
-/* Parse a "sig_val s-expression and store the inner parameter list at
+/* Parse a "sig-val" s-expression and store the inner parameter list at
R_PARMS. ALGO_NAMES is used to verify that the algorithm in
"sig-val" is valid. Returns 0 on success and stores a new list at
R_PARMS which must be freed by the caller. On error R_PARMS is set
to NULL and an error code returned. If R_ECCFLAGS is not NULL flag
values are set into it; as of now they are only used with ecc
algorithms. */
gpg_err_code_t
_gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names,
gcry_sexp_t *r_parms, int *r_eccflags)
{
gpg_err_code_t rc;
gcry_sexp_t l1 = NULL;
gcry_sexp_t l2 = NULL;
char *name = NULL;
int i;
*r_parms = NULL;
if (r_eccflags)
*r_eccflags = 0;
/* Extract the signature value. */
l1 = gcry_sexp_find_token (s_sig, "sig-val", 0);
if (!l1)
{
rc = GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */
goto leave;
}
l2 = gcry_sexp_nth (l1, 1);
if (!l2)
{
rc = GPG_ERR_NO_OBJ; /* No cadr for the sig object. */
goto leave;
}
name = _gcry_sexp_nth_string (l2, 0);
if (!name)
{
rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
goto leave;
}
else if (!strcmp (name, "flags"))
{
/* Skip a "flags" parameter and look again for the algorithm
name. This is not used but here just for the sake of
consistent S-expressions we need to handle it. */
gcry_sexp_release (l2);
l2 = gcry_sexp_nth (l1, 2);
if (!l2)
{
rc = GPG_ERR_INV_OBJ;
goto leave;
}
gcry_free (name);
name = _gcry_sexp_nth_string (l2, 0);
if (!name)
{
rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
goto leave;
}
}
for (i=0; algo_names[i]; i++)
if (!stricmp (name, algo_names[i]))
break;
if (!algo_names[i])
{
rc = GPG_ERR_CONFLICT; /* "sig-val" uses an unexpected algo. */
goto leave;
}
if (r_eccflags)
{
if (!strcmp (name, "eddsa"))
*r_eccflags = PUBKEY_FLAG_EDDSA;
}
*r_parms = l2;
l2 = NULL;
rc = 0;
leave:
gcry_free (name);
gcry_sexp_release (l2);
gcry_sexp_release (l1);
return rc;
}
+
+/* Parse a "enc-val" s-expression and store the inner parameter list
+ at R_PARMS. ALGO_NAMES is used to verify that the algorithm in
+ "enc-val" is valid. Returns 0 on success and stores a new list at
+ R_PARMS which must be freed by the caller. On error R_PARMS is set
+ to NULL and an error code returned. If R_ECCFLAGS is not NULL flag
+ values are set into it; as of now they are only used with ecc
+ algorithms.
+
+ (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. CTX will be updated with
+ encoding information. */
+gpg_err_code_t
+_gcry_pk_util_preparse_encval (gcry_sexp_t sexp, const char **algo_names,
+ gcry_sexp_t *r_parms,
+ struct pk_encoding_ctx *ctx)
+{
+ gcry_err_code_t rc = 0;
+ gcry_sexp_t l1 = NULL;
+ gcry_sexp_t l2 = NULL;
+ char *name = NULL;
+ size_t n;
+ int parsed_flags = 0;
+ int i;
+
+ *r_parms = NULL;
+
+ /* Check that the first element is valid. */
+ l1 = gcry_sexp_find_token (sexp, "enc-val" , 0);
+ if (!l1)
+ {
+ rc = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */
+ goto leave;
+ }
+
+ l2 = gcry_sexp_nth (l1, 1);
+ if (!l2)
+ {
+ rc = GPG_ERR_NO_OBJ; /* No cadr for the data object. */
+ goto leave;
+ }
+
+ /* Extract identifier of sublist. */
+ name = _gcry_sexp_nth_string (l2, 0);
+ if (!name)
+ {
+ rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
+ goto leave;
+ }
+
+ if (!strcmp (name, "flags"))
+ {
+ /* There is a flags element - process it. */
+ const char *s;
+
+ 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)
+ {
+ rc = GPG_ERR_CONFLICT;
+ goto leave;
+ }
+ else if (n == 11 && !memcmp (s, "no-blinding", 11))
+ parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
+ else
+ {
+ rc = GPG_ERR_INV_FLAG;
+ goto leave;
+ }
+ }
+
+ /* Get the OAEP parameters HASH-ALGO and LABEL, if any. */
+ if (ctx->encoding == PUBKEY_ENC_OAEP)
+ {
+ /* Get HASH-ALGO. */
+ gcry_sexp_release (l2);
+ l2 = gcry_sexp_find_token (l1, "hash-algo", 0);
+ if (l2)
+ {
+ s = gcry_sexp_nth_data (l2, 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;
+ }
+ if (rc)
+ goto leave;
+ }
+
+ /* Get LABEL. */
+ gcry_sexp_release (l2);
+ l2 = gcry_sexp_find_token (l1, "label", 0);
+ if (l2)
+ {
+ s = gcry_sexp_nth_data (l2, 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;
+ }
+ }
+ if (rc)
+ goto leave;
+ }
+ }
+
+ /* Get the next which has the actual data - skip HASH-ALGO and LABEL. */
+ for (i = 2; (gcry_sexp_release (l2), l2 = gcry_sexp_nth (l1, i)); 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;
+ }
+ if (!l2)
+ {
+ rc = GPG_ERR_NO_OBJ; /* No cadr for the data object. */
+ goto leave;
+ }
+
+ /* Extract sublist identifier. */
+ gcry_free (name);
+ name = _gcry_sexp_nth_string (l2, 0);
+ if (!name)
+ {
+ rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
+ goto leave;
+ }
+ }
+ else /* No flags - flag as legacy structure. */
+ parsed_flags |= PUBKEY_FLAG_LEGACYRESULT;
+
+ for (i=0; algo_names[i]; i++)
+ if (!stricmp (name, algo_names[i]))
+ break;
+ if (!algo_names[i])
+ {
+ rc = GPG_ERR_CONFLICT; /* "enc-val" uses an unexpected algo. */
+ goto leave;
+ }
+
+ *r_parms = l2;
+ l2 = NULL;
+ ctx->flags |= parsed_flags;
+ rc = 0;
+
+ leave:
+ gcry_free (name);
+ gcry_sexp_release (l2);
+ gcry_sexp_release (l1);
+ return rc;
+}
+
+
/* Initialize an encoding context. */
void
_gcry_pk_util_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;
}
/* Free a context initialzied by _gcry_pk_util_init_encoding_ctx. */
void
_gcry_pk_util_free_encoding_ctx (struct pk_encoding_ctx *ctx)
{
gcry_free (ctx->label);
}
-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 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, direct, pkcs1, oaep, pss, no-blinding, rfc6979, eddsa])]
[(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 is specific to OAEP and EDDSA.
LABEL is specific to OAEP.
SALT-LENGTH is for PSS.
RANDOM-OVERRIDE is used to replace random nonces for regression
testing. */
gcry_err_code_t
_gcry_pk_util_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 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 == 5 && !memcmp (s, "eddsa", 5))
{
ctx->encoding = PUBKEY_ENC_RAW;
parsed_flags |= PUBKEY_FLAG_EDDSA;
}
else if ( n == 3 && !memcmp (s, "raw", 3)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
{
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;
parsed_flags |= PUBKEY_FLAG_FIXEDLEN;
}
else if ( n == 4 && !memcmp (s, "oaep", 4)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
{
ctx->encoding = PUBKEY_ENC_OAEP;
parsed_flags |= PUBKEY_FLAG_FIXEDLEN;
}
else if ( n == 3 && !memcmp (s, "pss", 3)
&& ctx->encoding == PUBKEY_ENC_UNKNOWN)
{
ctx->encoding = PUBKEY_ENC_PSS;
parsed_flags |= PUBKEY_FLAG_FIXEDLEN;
}
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
&& (parsed_flags & PUBKEY_FLAG_EDDSA))
{
/* Prepare for EdDSA. */
gcry_sexp_t list;
void *value;
size_t valuelen;
if (!lvalue)
{
rc = GPG_ERR_INV_OBJ;
goto leave;
}
/* 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);
}
else
rc = GPG_ERR_INV_OBJ;
if (rc)
goto leave;
/* Get VALUE. */
value = gcry_sexp_nth_buffer (lvalue, 1, &valuelen);
if (!value)
{
/* We assume that a zero length message is meant by
"(value)". This is commonly used by test vectors. Note
that S-expression do not allow zero length items. */
valuelen = 0;
value = gcry_malloc (1);
if (!value)
rc = gpg_err_code_from_syserror ();
}
else if ((valuelen * 8) < valuelen)
{
gcry_free (value);
rc = GPG_ERR_TOO_LARGE;
}
if (rc)
goto leave;
/* Note that mpi_set_opaque takes ownership of VALUE. */
*ret_mpi = gcry_mpi_set_opaque (NULL, value, valuelen*8);
}
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 = _gcry_rsa_pkcs1_encode_for_enc (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 = _gcry_rsa_pkcs1_encode_for_sig (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 = _gcry_rsa_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 = _gcry_rsa_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;
}
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 8a46e4e5..d7a474d8 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -1,1652 +1,1397 @@
/* 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"
/* This is the list of the public-key algorithms included in
Libgcrypt. */
static gcry_pk_spec_t *pubkey_list[] =
{
#if USE_ECC
&_gcry_pubkey_spec_ecc,
#endif
#if USE_RSA
&_gcry_pubkey_spec_rsa,
#endif
#if USE_DSA
&_gcry_pubkey_spec_dsa,
#endif
#if USE_ELGAMAL
&_gcry_pubkey_spec_elg,
#endif
NULL
};
static int
map_algo (int algo)
{
switch (algo)
{
case GCRY_PK_ECDSA:
case GCRY_PK_ECDH:
return GCRY_PK_ECC;
case GCRY_PK_ELG_E:
return GCRY_PK_ELG;
default:
return algo;
}
}
/* Return the spec structure for the public key algorithm ALGO. For
an unknown algorithm NULL is returned. */
static gcry_pk_spec_t *
spec_from_algo (int algo)
{
int idx;
gcry_pk_spec_t *spec;
algo = map_algo (algo);
for (idx = 0; (spec = pubkey_list[idx]); idx++)
if (algo == spec->algo)
return spec;
return NULL;
}
/* Return the spec structure for the public key algorithm with NAME.
For an unknown name NULL is returned. */
static gcry_pk_spec_t *
spec_from_name (const char *name)
{
gcry_pk_spec_t *spec;
int idx;
const char **aliases;
for (idx=0; (spec = pubkey_list[idx]); idx++)
{
if (!stricmp (name, spec->name))
return spec;
for (aliases = spec->aliases; *aliases; aliases++)
if (!stricmp (name, *aliases))
return spec;
}
return NULL;
}
/* Given the s-expression SEXP with the first element be either
* "private-key" or "public-key" return the spec structure for it. We
* look through the list to find a list beginning with "private-key"
* or "public-key" - the first one found is used. If WANT_PRIVATE is
* set the function will only succeed if a private key has been given.
* On success the spec is stored at R_SPEC. On error NULL is stored
* at R_SPEC and an error code returned. If R_PARMS is not NULL and
* the fucntion returns success, the parameter list below
* "private-key" or "public-key" is stored there and the caller must
* call gcry_sexp_release on it.
*/
static gcry_err_code_t
spec_from_sexp (gcry_sexp_t sexp, int want_private,
gcry_pk_spec_t **r_spec, gcry_sexp_t *r_parms)
{
gcry_sexp_t list, l2;
char *name;
gcry_pk_spec_t *spec;
*r_spec = NULL;
if (r_parms)
*r_parms = NULL;
/* Check that the first element is valid. If we are looking for a
public key but a private key was supplied, we allow the use of
the private key anyway. The rationale for this is that the
private key is a superset of the public key. */
list = gcry_sexp_find_token (sexp,
want_private? "private-key":"public-key", 0);
if (!list && !want_private)
list = gcry_sexp_find_token (sexp, "private-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. */
}
spec = spec_from_name (name);
gcry_free (name);
if (!spec)
{
gcry_sexp_release (list);
return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
}
*r_spec = spec;
if (r_parms)
*r_parms = list;
else
gcry_sexp_release (list);
return 0;
}
/* Disable the use of the algorithm ALGO. This is not thread safe and
should thus be called early. */
static void
disable_pubkey_algo (int algo)
{
gcry_pk_spec_t *spec = spec_from_algo (algo);
if (spec)
spec->flags.disabled = 1;
}
/* Free the MPIs stored in the NULL terminated ARRAY of MPIs and set
the slots to NULL. */
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_pk_spec_t *spec;
if (!string)
return 0;
spec = spec_from_name (string);
if (!spec)
return 0;
if (spec->flags.disabled)
return 0;
return spec->algo;
}
/* 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 algo)
{
gcry_pk_spec_t *spec;
spec = spec_from_algo (algo);
if (spec)
return spec->name;
return "?";
}
/****************
* A USE of 0 means: don't care.
*/
static gcry_err_code_t
check_pubkey_algo (int algo, unsigned use)
{
gcry_err_code_t err = 0;
gcry_pk_spec_t *spec;
spec = spec_from_algo (algo);
if (spec)
{
if (((use & GCRY_PK_USAGE_SIGN)
&& (! (spec->use & GCRY_PK_USAGE_SIGN)))
|| ((use & GCRY_PK_USAGE_ENCR)
&& (! (spec->use & GCRY_PK_USAGE_ENCR))))
err = GPG_ERR_WRONG_PUBKEY_ALGO;
}
else
err = GPG_ERR_PUBKEY_ALGO;
return err;
}
/****************
* Return the number of public key material numbers
*/
static int
pubkey_get_npkey (int algo)
{
gcry_pk_spec_t *spec = spec_from_algo (algo);
return spec? strlen (spec->elements_pkey) : 0;
}
/****************
* Return the number of secret key material numbers
*/
static int
pubkey_get_nskey (int algo)
{
gcry_pk_spec_t *spec = spec_from_algo (algo);
return spec? strlen (spec->elements_skey) : 0;
}
/****************
* Return the number of signature material numbers
*/
static int
pubkey_get_nsig (int algo)
{
gcry_pk_spec_t *spec = spec_from_algo (algo);
return spec? strlen (spec->elements_sig) : 0;
}
/****************
* Return the number of encryption material numbers
*/
static int
pubkey_get_nenc (int algo)
{
gcry_pk_spec_t *spec = spec_from_algo (algo);
return spec? strlen (spec->elements_enc) : 0;
}
static gcry_err_code_t
pubkey_check_secret_key (int algo, gcry_mpi_t *skey)
{
gcry_err_code_t rc;
gcry_pk_spec_t *spec = spec_from_algo (algo);
if (spec && spec->check_secret_key)
rc = spec->check_secret_key (algo, skey);
else if (spec)
rc = GPG_ERR_NOT_IMPLEMENTED;
else
rc = GPG_ERR_PUBKEY_ALGO;
return rc;
}
/* Internal function. */
static gcry_err_code_t
sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names,
gcry_mpi_t *elements, const char *algo_name, int opaque)
{
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 if (opaque)
{
elements[idx] = _gcry_sexp_nth_opaque_mpi (list, 1);
gcry_sexp_release (list);
if (!elements[idx])
err = GPG_ERR_INV_OBJ;
}
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, i = 0; *name; name++, i++)
if (!elements[i])
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])
mpi_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, gcry_pk_spec_t *spec,
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
{
switch (idx)
{
case 5: /* The public and */
case 6: /* the secret key must to be passed opaque. */
elements[idx] = _gcry_sexp_nth_opaque_mpi (list, 1);
break;
default:
elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_STD);
break;
}
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 (spec->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 = spec->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])
mpi_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_pk_spec_t **r_spec, 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_pk_spec_t *spec;
int is_ecc;
/* Check that the first element is valid. If we are looking for a
public key but a private key was supplied, we allow the use of
the private key anyway. The rationale for this is that the
private key is a superset of the public key. */
list = gcry_sexp_find_token (sexp,
want_private? "private-key":"public-key", 0);
if (!list && !want_private)
list = gcry_sexp_find_token (sexp, "private-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;
if (is_ecc == 2 && (use & GCRY_PK_USAGE_SIGN))
spec = spec_from_name ("ecdsa");
else if (is_ecc == 2 && (use & GCRY_PK_USAGE_ENCR))
spec = spec_from_name ("ecdh");
else
spec = spec_from_name (name);
gcry_free (name);
if (!spec)
{
gcry_sexp_release (list);
return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
}
if (override_elems)
elems = override_elems;
else if (want_private)
elems = spec->elements_skey;
else
elems = spec->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, spec,
want_private);
else
err = sexp_elements_extract (list, elems, array, spec->name, 0);
}
gcry_sexp_release (list);
if (err)
{
gcry_free (array);
}
else
{
*retarray = array;
*r_spec = spec;
if (r_is_ecc)
*r_is_ecc = is_ecc;
}
return err;
}
/* FIXME: This is a duplicate. */
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_pk_spec_t **r_spec,
- int *flags, struct pk_encoding_ctx *ctx)
-{
- gcry_err_code_t err = 0;
- gcry_sexp_t list = NULL;
- gcry_sexp_t l2 = NULL;
- gcry_pk_spec_t *spec = NULL;
- char *name = NULL;
- size_t n;
- int parsed_flags = 0;
- const char *elems;
- gcry_mpi_t *array = NULL;
-
- /* 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;
-
- 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;
- }
- else
- parsed_flags |= PUBKEY_FLAG_LEGACYRESULT;
-
- spec = spec_from_name (name);
- if (!spec)
- {
- err = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
- goto leave;
- }
-
- elems = spec->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, 0);
-
- leave:
- gcry_sexp_release (list);
- gcry_sexp_release (l2);
- gcry_free (name);
-
- if (err)
- {
- gcry_free (array);
- gcry_free (ctx->label);
- ctx->label = NULL;
- }
- else
- {
- *retarray = array;
- *r_spec = spec;
- *flags = parsed_flags;
- }
-
- return err;
-}
-
-
/*
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 _gcry_pk_util_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_err_code_t rc;
gcry_pk_spec_t *spec;
gcry_sexp_t keyparms;
*r_ciph = NULL;
rc = spec_from_sexp (s_pkey, 0, &spec, &keyparms);
if (rc)
goto leave;
if (spec->encrypt)
rc = spec->encrypt (r_ciph, s_data, keyparms);
else
rc = GPG_ERR_NOT_IMPLEMENTED;
leave:
gcry_sexp_release (keyparms);
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_err_code_t rc;
- gcry_mpi_t *skey = NULL;
- gcry_mpi_t *data = NULL;
- int i;
- int flags;
- struct pk_encoding_ctx ctx;
- gcry_pk_spec_t *spec = NULL;
- gcry_pk_spec_t *spec_enc = NULL;
+ gcry_pk_spec_t *spec;
+ gcry_sexp_t keyparms;
*r_plain = NULL;
- ctx.label = NULL;
-
- rc = sexp_to_key (s_skey, 1, GCRY_PK_USAGE_ENCR, NULL,
- &skey, &spec, NULL);
- if (rc)
- goto leave;
- _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, gcry_pk_get_nbits (s_skey));
- rc = sexp_to_enc (s_data, &data, &spec_enc, &flags, &ctx);
+ rc = spec_from_sexp (s_skey, 1, &spec, &keyparms);
if (rc)
goto leave;
- if (spec->algo != spec_enc->algo)
- {
- rc = GPG_ERR_CONFLICT; /* Key algo does not match data algo. */
- goto leave;
- }
-
- if (DBG_CIPHER && !fips_mode ())
- {
- log_debug ("gcry_pk_decrypt: algo=%d\n", spec->algo);
- for(i = 0; i < pubkey_get_nskey (spec->algo); i++)
- log_mpidump (" skey", skey[i]);
- for(i = 0; i < pubkey_get_nenc (spec->algo); i++)
- log_mpidump (" data", data[i]);
- }
-
if (spec->decrypt)
- rc = spec->decrypt (spec->algo, r_plain, data, skey, flags,
- ctx.encoding, ctx.hash_algo,
- ctx.label, ctx.labellen);
+ rc = spec->decrypt (r_plain, s_data, keyparms);
else
rc = GPG_ERR_NOT_IMPLEMENTED;
- if (rc)
- goto leave;
-
- /* if (DBG_CIPHER && !fips_mode ()) */
- /* log_mpidump (" plain", plain); */
-
leave:
- if (skey)
- {
- release_mpi_array (skey);
- gcry_free (skey);
- }
-
- if (data)
- {
- release_mpi_array (data);
- gcry_free (data);
- }
-
- gcry_free (ctx.label);
-
+ gcry_sexp_release (keyparms);
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 _gcry-pk_util_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_err_code_t rc;
gcry_pk_spec_t *spec;
gcry_sexp_t keyparms;
*r_sig = NULL;
rc = spec_from_sexp (s_skey, 1, &spec, &keyparms);
if (rc)
goto leave;
if (spec->sign)
rc = spec->sign (r_sig, s_hash, keyparms);
else
rc = GPG_ERR_NOT_IMPLEMENTED;
leave:
gcry_sexp_release (keyparms);
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_err_code_t rc;
gcry_pk_spec_t *spec;
gcry_sexp_t keyparms;
rc = spec_from_sexp (s_pkey, 0, &spec, &keyparms);
if (rc)
goto leave;
if (spec->verify)
rc = spec->verify (s_sig, s_hash, keyparms);
else
rc = GPG_ERR_NOT_IMPLEMENTED;
leave:
gcry_sexp_release (keyparms);
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_pk_spec_t *spec = NULL;
gcry_mpi_t *key = NULL;
gcry_err_code_t rc;
/* Note we currently support only secret key checking. */
rc = sexp_to_key (s_key, 1, 0, NULL, &key, &spec, NULL);
if (!rc)
{
rc = pubkey_check_secret_key (spec->algo, 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 *spec = NULL;
gcry_sexp_t list = NULL;
gcry_sexp_t l2 = NULL;
char *name = NULL;
gcry_err_code_t rc;
*r_key = NULL;
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;
}
spec = spec_from_name (name);
gcry_free (name);
name = NULL;
if (!spec)
{
rc = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
goto leave;
}
if (spec->generate)
rc = spec->generate (list, r_key);
else
rc = GPG_ERR_NOT_IMPLEMENTED;
leave:
gcry_sexp_release (list);
gcry_free (name);
gcry_sexp_release (l2);
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_pk_spec_t *spec;
gcry_sexp_t parms;
unsigned int nbits;
/* Parsing KEY might be considered too much overhead. For example
for RSA we would only need to look at P and stop parsing right
away. However, with ECC things are more complicate in that only
a curve name might be specified. Thus we need to tear the sexp
apart. */
if (spec_from_sexp (key, 0, &spec, &parms))
return 0; /* Error - 0 is a suitable indication for that. */
nbits = spec->get_nbits (parms);
gcry_sexp_release (parms);
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;
gcry_sexp_t l2 = NULL;
gcry_pk_spec_t *spec = NULL;
const char *s;
char *name = NULL;
int idx;
const char *elems;
gcry_md_hd_t md = NULL;
int okay = 0;
/* 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. */
spec = spec_from_name (name);
if (!spec)
goto fail; /* Unknown algorithm. */
elems = spec->elements_grip;
if (!elems)
goto fail; /* No grip parameter. */
if (gcry_md_open (&md, GCRY_MD_SHA1, 0))
goto fail;
if (spec->comp_keygrip)
{
/* Module specific method to compute a keygrip. */
if (spec->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;
char *name = NULL;
const char *result = NULL;
int want_private = 1;
gcry_pk_spec_t *spec = NULL;
if (r_nbits)
*r_nbits = 0;
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, &spec, NULL))
goto leave;
}
else
{
spec = spec_from_name ("ecc");
if (!spec)
goto leave;
}
if (!spec || !spec->get_curve)
goto leave;
result = spec->get_curve (pkey, iterator, r_nbits);
leave:
if (pkey)
{
release_mpi_array (pkey);
gcry_free (pkey);
}
gcry_free (name);
gcry_sexp_release (list);
return result;
}
gcry_sexp_t
gcry_pk_get_param (int algo, const char *name)
{
gcry_sexp_t result = NULL;
gcry_pk_spec_t *spec = NULL;
algo = map_algo (algo);
if (algo != GCRY_PK_ECC)
return NULL;
spec = spec_from_name ("ecc");
if (spec)
{
if (spec && spec->get_curve_param)
result = spec->get_curve_param (name);
}
return result;
}
gcry_error_t
gcry_pk_ctl (int cmd, void *buffer, size_t buflen)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
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_pk_spec_t *spec;
spec = spec_from_algo (algorithm);
*nbytes = spec? spec->use : 0;
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)
{
return 0;
}
/* 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_err_code_t ec;
gcry_pk_spec_t *spec;
algo = map_algo (algo);
spec = spec_from_algo (algo);
if (spec && !spec->flags.disabled && spec->selftest)
ec = spec->selftest (algo, extended, report);
else
{
ec = GPG_ERR_PUBKEY_ALGO;
/* Fixme: We need to change the report fucntion to allow passing
of an encryption mode (e.g. pkcs1, ecdsa, or ecdh). */
if (report)
report ("pubkey", algo, "module",
spec && !spec->flags.disabled?
"no selftest available" :
spec? "algorithm disabled" :
"algorithm not found");
}
return gpg_error (ec);
}
diff --git a/cipher/rsa.c b/cipher/rsa.c
index 51480df3..428185bf 100644
--- a/cipher/rsa.c
+++ b/cipher/rsa.c
@@ -1,1548 +1,1590 @@
/* 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"
#include "pubkey-internal.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;
static const char *rsa_names[] =
{
"rsa",
"openpgp-rsa",
"oid.1.2.840.113549.1.1.1",
NULL,
};
/* 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);
static unsigned int rsa_get_nbits (gcry_sexp_t parms);
/* 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);
log_printmpi (" 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);
log_printmpi (" 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 )
{
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_has_sign ( 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 );
}
}
/*********************************************
************** interface ******************
*********************************************/
static gcry_err_code_t
rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
{
gpg_err_code_t ec;
unsigned int nbits;
unsigned long evalue;
RSA_secret_key sk;
gcry_sexp_t deriveparms;
int transient_key = 0;
int use_x931 = 0;
gcry_sexp_t l1;
gcry_sexp_t swap_info = NULL;
memset (&sk, 0, sizeof sk);
ec = _gcry_pk_util_get_nbits (genparms, &nbits);
if (ec)
return ec;
ec = _gcry_pk_util_get_rsa_use_e (genparms, &evalue);
if (ec)
return ec;
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 && swapped)
ec = gcry_sexp_new (&swap_info, "(misc-key-info(p-q-swapped))", 0, 1);
}
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)
{
ec = gcry_sexp_build (r_skey, NULL,
"(key-data"
" (public-key"
" (rsa(n%m)(e%m)))"
" (private-key"
" (rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))"
" %S)",
sk.n, sk.e,
sk.n, sk.e, sk.d, sk.p, sk.q, sk.u,
swap_info);
}
mpi_free (sk.n);
mpi_free (sk.e);
mpi_free (sk.p);
mpi_free (sk.q);
mpi_free (sk.d);
mpi_free (sk.u);
gcry_sexp_release (swap_info);
return ec;
}
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 (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
{
gcry_err_code_t rc;
struct pk_encoding_ctx ctx;
gcry_mpi_t data = NULL;
RSA_public_key pk = {NULL, NULL};
gcry_mpi_t ciph = NULL;
_gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT,
rsa_get_nbits (keyparms));
/* Extract the data. */
rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
if (rc)
goto leave;
if (DBG_CIPHER)
log_mpidump ("rsa_encrypt data", data);
if (mpi_is_opaque (data))
{
rc = GPG_ERR_INV_DATA;
goto leave;
}
/* Extract the key. */
rc = _gcry_pk_util_extract_mpis (keyparms, "ne", &pk.n, &pk.e, NULL);
if (rc)
return rc;
if (DBG_CIPHER)
{
- log_mpidump ("rsa_encrypt n", pk.n);
- log_mpidump ("rsa_encrypt e", pk.e);
+ log_mpidump ("rsa_encrypt n", pk.n);
+ log_mpidump ("rsa_encrypt e", pk.e);
}
/* Do RSA computation and build result. */
ciph = gcry_mpi_new (0);
public (ciph, data, &pk);
+ if (DBG_CIPHER)
+ log_mpidump ("rsa_encrypt res", ciph);
if ((ctx.flags & PUBKEY_FLAG_FIXEDLEN))
{
/* We need to make sure to return the correct length to avoid
problems with missing leading zeroes. */
unsigned char *em;
size_t emlen = (mpi_get_nbits (pk.n)+7)/8;
rc = _gcry_mpi_to_octet_string (&em, NULL, ciph, emlen);
if (!rc)
{
rc = gcry_sexp_build (r_ciph, NULL,
"(enc-val(rsa(a%b)))", (int)emlen, em);
gcry_free (em);
}
}
else
rc = gcry_sexp_build (r_ciph, NULL, "(enc-val(rsa(a%m)))", ciph);
leave:
gcry_mpi_release (ciph);
gcry_mpi_release (pk.n);
gcry_mpi_release (pk.e);
gcry_mpi_release (data);
_gcry_pk_util_free_encoding_ctx (&ctx);
if (DBG_CIPHER)
- log_debug ("rsa_encrypt => %s\n", gpg_strerror (rc));
+ log_debug ("rsa_encrypt => %s\n", gpg_strerror (rc));
return rc;
}
static gcry_err_code_t
-rsa_decrypt (int algo, gcry_sexp_t *r_plain, gcry_mpi_t *data,
- gcry_mpi_t *skey, int flags,
- enum pk_encoding encoding, int hash_algo,
- unsigned char *label, size_t labellen)
+rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
{
gpg_err_code_t rc;
- RSA_secret_key sk;
- gcry_mpi_t plain; /* Decrypted data. */
+ struct pk_encoding_ctx ctx;
+ gcry_sexp_t l1 = NULL;
+ gcry_mpi_t data = NULL;
+ RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL};
+ gcry_mpi_t plain = NULL;
+ gcry_mpi_t r = NULL; /* Random number needed for blinding. */
+ gcry_mpi_t ri = NULL; /* Modular multiplicative inverse of r. */
+ gcry_mpi_t bldata = NULL;/* Blinded data to decrypt. */
unsigned char *unpad = NULL;
size_t unpadlen = 0;
- unsigned int nbits;
- (void)algo;
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT,
+ rsa_get_nbits (keyparms));
- /* 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. */
+ /* Extract the data. */
+ rc = _gcry_pk_util_preparse_encval (s_data, rsa_names, &l1, &ctx);
+ if (rc)
+ goto leave;
+ rc = _gcry_pk_util_extract_mpis (l1, "a", &data, NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ log_printmpi ("rsa_decrypt data", data);
+ if (mpi_is_opaque (data))
+ {
+ rc = GPG_ERR_INV_DATA;
+ goto leave;
+ }
- nbits = gcry_mpi_get_nbits (sk.n);
+ /* Extract the key. */
+ rc = _gcry_pk_util_extract_mpis (keyparms, "nedp?q?u?",
+ &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u,
+ NULL);
+ if (rc)
+ return rc;
+ if (DBG_CIPHER)
+ {
+ log_printmpi ("rsa_decrypt n", sk.n);
+ log_printmpi ("rsa_decrypt e", sk.e);
+ if (!fips_mode ())
+ {
+ log_printmpi ("rsa_decrypt d", sk.d);
+ log_printmpi ("rsa_decrypt p", sk.p);
+ log_printmpi ("rsa_decrypt q", sk.q);
+ log_printmpi ("rsa_decrypt u", sk.u);
+ }
+ }
- plain = gcry_mpi_snew (nbits);
+ plain = gcry_mpi_snew (ctx.nbits);
/* 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))
+ if (!(ctx.flags & PUBKEY_FLAG_NO_BLINDING))
{
- gcry_mpi_t r; /* Random number needed for blinding. */
- gcry_mpi_t ri; /* Modular multiplicative inverse of r. */
- gcry_mpi_t ciph; /* Blinded data to decrypt. */
-
/* 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 (nbits);
- ri = gcry_mpi_snew (nbits);
- ciph = gcry_mpi_snew (nbits);
+ r = gcry_mpi_snew (ctx.nbits);
+ ri = gcry_mpi_snew (ctx.nbits);
+ bldata = gcry_mpi_snew (ctx.nbits);
- gcry_mpi_randomize (r, nbits, GCRY_WEAK_RANDOM);
+ gcry_mpi_randomize (r, ctx.nbits, 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;
+ {
+ rc = GPG_ERR_INTERNAL;
+ goto leave;
+ }
/* Do blinding. 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 (ciph, r, sk.e, sk.n);
- gcry_mpi_mulm (ciph, ciph, data[0], sk.n);
+ gcry_mpi_powm (bldata, r, sk.e, sk.n);
+ gcry_mpi_mulm (bldata, bldata, data, sk.n);
/* Perform decryption. */
- secret (plain, ciph, &sk);
+ secret (plain, bldata, &sk);
+ gcry_mpi_release (bldata); bldata = NULL;
/* Undo blinding. 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 (plain, plain, ri, sk.n);
- gcry_mpi_release (ciph);
- gcry_mpi_release (r);
- gcry_mpi_release (ri);
+ gcry_mpi_release (r); r = NULL;
+ gcry_mpi_release (ri); ri = NULL;
}
else
- secret (plain, data[0], &sk);
+ secret (plain, data, &sk);
+
+ if (DBG_CIPHER)
+ log_printmpi ("rsa_decrypt res", plain);
/* Reverse the encoding and build the s-expression. */
- switch (encoding)
+ switch (ctx.encoding)
{
case PUBKEY_ENC_PKCS1:
- rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, nbits, plain);
+ rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain);
mpi_free (plain);
plain = NULL;
if (!rc)
rc = gcry_sexp_build (r_plain, NULL,
"(value %b)", (int)unpadlen, unpad);
break;
case PUBKEY_ENC_OAEP:
rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen,
- nbits, hash_algo, plain, label, labellen);
+ ctx.nbits, ctx.hash_algo,
+ plain, ctx.label, ctx.labellen);
mpi_free (plain);
plain = NULL;
if (!rc)
rc = 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_sexp_build (r_plain, NULL,
- (flags & PUBKEY_FLAG_LEGACYRESULT)
+ (ctx.flags & PUBKEY_FLAG_LEGACYRESULT)
? "%m":"(value %m)", plain);
break;
}
+ leave:
gcry_free (unpad);
- mpi_free (plain);
-
+ gcry_mpi_release (plain);
+ gcry_mpi_release (sk.n);
+ gcry_mpi_release (sk.e);
+ gcry_mpi_release (sk.d);
+ gcry_mpi_release (sk.p);
+ gcry_mpi_release (sk.q);
+ gcry_mpi_release (sk.u);
+ gcry_mpi_release (data);
+ gcry_mpi_release (r);
+ gcry_mpi_release (ri);
+ gcry_mpi_release (bldata);
+ gcry_sexp_release (l1);
+ _gcry_pk_util_free_encoding_ctx (&ctx);
+ if (DBG_CIPHER)
+ log_debug ("rsa_decrypt => %s\n", gpg_strerror (rc));
return rc;
}
static gcry_err_code_t
rsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
{
gpg_err_code_t rc;
struct pk_encoding_ctx ctx;
gcry_mpi_t data = NULL;
RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL};
gcry_mpi_t sig = NULL;
_gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN,
rsa_get_nbits (keyparms));
/* Extract the data. */
rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
if (rc)
goto leave;
if (DBG_CIPHER)
- log_mpidump ("rsa_sign data", data);
+ log_printmpi ("rsa_sign data", data);
if (mpi_is_opaque (data))
{
rc = GPG_ERR_INV_DATA;
goto leave;
}
/* Extract the key. */
rc = _gcry_pk_util_extract_mpis (keyparms, "nedp?q?u?",
&sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u,
NULL);
if (rc)
return rc;
if (DBG_CIPHER)
{
- log_mpidump ("rsa_sign n", sk.n);
- log_mpidump ("rsa_sign e", sk.e);
+ log_printmpi ("rsa_sign n", sk.n);
+ log_printmpi ("rsa_sign e", sk.e);
if (!fips_mode ())
{
- log_mpidump ("rsa_sign d", sk.d);
- log_mpidump ("rsa_sign p", sk.p);
- log_mpidump ("rsa_sign q", sk.q);
- log_mpidump ("rsa_sign u", sk.u);
+ log_printmpi ("rsa_sign d", sk.d);
+ log_printmpi ("rsa_sign p", sk.p);
+ log_printmpi ("rsa_sign q", sk.q);
+ log_printmpi ("rsa_sign u", sk.u);
}
}
/* Do RSA computation and build the result. */
sig = gcry_mpi_new (0);
secret (sig, data, &sk);
if (DBG_CIPHER)
- log_mpidump ("rsa_sign sig", sig);
+ log_printmpi ("rsa_sign res", sig);
if ((ctx.flags & PUBKEY_FLAG_FIXEDLEN))
{
/* We need to make sure to return the correct length to avoid
problems with missing leading zeroes. */
unsigned char *em;
size_t emlen = (mpi_get_nbits (sk.n)+7)/8;
rc = _gcry_mpi_to_octet_string (&em, NULL, sig, emlen);
if (!rc)
{
rc = gcry_sexp_build (r_sig, NULL,
"(sig-val(rsa(s%b)))", (int)emlen, em);
gcry_free (em);
}
}
else
rc = gcry_sexp_build (r_sig, NULL, "(sig-val(rsa(s%M)))", sig);
leave:
gcry_mpi_release (sig);
gcry_mpi_release (sk.n);
gcry_mpi_release (sk.e);
gcry_mpi_release (sk.d);
gcry_mpi_release (sk.p);
gcry_mpi_release (sk.q);
gcry_mpi_release (sk.u);
gcry_mpi_release (data);
_gcry_pk_util_free_encoding_ctx (&ctx);
if (DBG_CIPHER)
log_debug ("rsa_sign => %s\n", gpg_strerror (rc));
return rc;
}
static gcry_err_code_t
rsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
{
gcry_err_code_t rc;
struct pk_encoding_ctx ctx;
gcry_sexp_t l1 = NULL;
gcry_mpi_t sig = NULL;
gcry_mpi_t data = NULL;
RSA_public_key pk = { NULL, NULL };
gcry_mpi_t result = NULL;
_gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY,
rsa_get_nbits (keyparms));
/* Extract the data. */
rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
if (rc)
goto leave;
if (DBG_CIPHER)
- log_mpidump ("rsa_verify data", data);
+ log_printmpi ("rsa_verify data", data);
if (mpi_is_opaque (data))
{
rc = GPG_ERR_INV_DATA;
goto leave;
}
/* Extract the signature value. */
rc = _gcry_pk_util_preparse_sigval (s_sig, rsa_names, &l1, NULL);
if (rc)
goto leave;
rc = _gcry_pk_util_extract_mpis (l1, "s", &sig, NULL);
if (rc)
goto leave;
if (DBG_CIPHER)
- log_mpidump ("rsa_verify sig", sig);
+ log_printmpi ("rsa_verify sig", sig);
/* Extract the key. */
rc = _gcry_pk_util_extract_mpis (keyparms, "ne", &pk.n, &pk.e, NULL);
if (rc)
return rc;
if (DBG_CIPHER)
{
- log_mpidump ("rsa_verify n", pk.n);
- log_mpidump ("rsa_verify e", pk.e);
+ log_printmpi ("rsa_verify n", pk.n);
+ log_printmpi ("rsa_verify e", pk.e);
}
/* Do RSA computation and compare. */
result = gcry_mpi_new (0);
public (result, sig, &pk);
if (DBG_CIPHER)
- log_mpidump ("rsa_verify cmp", result);
+ log_printmpi ("rsa_verify cmp", result);
if (ctx.verify_cmp)
rc = ctx.verify_cmp (&ctx, result);
else
rc = mpi_cmp (result, data) ? GPG_ERR_BAD_SIGNATURE : 0;
leave:
gcry_mpi_release (result);
gcry_mpi_release (pk.n);
gcry_mpi_release (pk.e);
gcry_mpi_release (data);
gcry_mpi_release (sig);
gcry_sexp_release (l1);
_gcry_pk_util_free_encoding_ctx (&ctx);
if (DBG_CIPHER)
log_debug ("rsa_verify => %s\n", rc?gpg_strerror (rc):"Good");
return rc;
}
/* Return the number of bits for the key described by PARMS. On error
* 0 is returned. The format of PARMS starts with the algorithm name;
* for example:
*
* (rsa
* (n <mpi>)
* (e <mpi>))
*
* More parameters may be given but we only need N here.
*/
static unsigned int
rsa_get_nbits (gcry_sexp_t parms)
{
gcry_sexp_t l1;
gcry_mpi_t n;
unsigned int nbits;
l1 = gcry_sexp_find_token (parms, "n", 1);
if (!l1)
return 0; /* Parameter N not found. */
n = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l1);
nbits = n? mpi_get_nbits (n) : 0;
gcry_mpi_release (n);
return nbits;
}
/* 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); */
+ /* _gcry_log_printmpi ("plaintext", plaintext); */
+ /* _gcry_log_printmpi ("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;
}
gcry_pk_spec_t _gcry_pubkey_spec_rsa =
{
GCRY_PK_RSA, { 0, 1 },
(GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR),
"RSA", rsa_names,
"ne", "nedpqu", "a", "s", "n",
rsa_generate,
rsa_check_secret_key,
rsa_encrypt,
rsa_decrypt,
rsa_sign,
rsa_verify,
rsa_get_nbits,
run_selftests,
compute_keygrip
};
diff --git a/src/cipher-proto.h b/src/cipher-proto.h
index c570e5ff..0dc83bd1 100644
--- a/src/cipher-proto.h
+++ b/src/cipher-proto.h
@@ -1,277 +1,271 @@
/* cipher-proto.h - Internal declarations
* Copyright (C) 2008, 2011 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 file has been factored out from cipher.h so that it can be
used standalone in visibility.c . */
#ifndef G10_CIPHER_PROTO_H
#define G10_CIPHER_PROTO_H
enum pk_encoding;
/* Definition of a function used to report selftest failures.
DOMAIN is a string describing the function block:
"cipher", "digest", "pubkey or "random",
ALGO is the algorithm under test,
WHAT is a string describing what has been tested,
DESC is a string describing the error. */
typedef void (*selftest_report_func_t)(const char *domain,
int algo,
const char *what,
const char *errdesc);
/* Definition of the selftest functions. */
typedef gpg_err_code_t (*selftest_func_t)
(int algo, int extended, selftest_report_func_t report);
/*
*
* Public key related definitions.
*
*/
/* Type for the pk_generate function. */
typedef gcry_err_code_t (*gcry_pk_generate_t) (gcry_sexp_t genparms,
gcry_sexp_t *r_skey);
/* Type for the pk_check_secret_key function. */
typedef gcry_err_code_t (*gcry_pk_check_secret_key_t) (int algo,
gcry_mpi_t *skey);
/* Type for the pk_encrypt function. */
typedef gcry_err_code_t (*gcry_pk_encrypt_t) (gcry_sexp_t *r_ciph,
gcry_sexp_t s_data,
gcry_sexp_t keyparms);
/* Type for the pk_decrypt function. */
-typedef gcry_err_code_t (*gcry_pk_decrypt_t) (int algo,
- gcry_sexp_t *r_result,
- gcry_mpi_t *data,
- gcry_mpi_t *skey,
- int flags,
- enum pk_encoding encoding,
- int hash_algo,
- unsigned char *label,
- size_t labellen);
+typedef gcry_err_code_t (*gcry_pk_decrypt_t) (gcry_sexp_t *r_plain,
+ gcry_sexp_t s_data,
+ gcry_sexp_t keyparms);
/* Type for the pk_sign function. */
typedef gcry_err_code_t (*gcry_pk_sign_t) (gcry_sexp_t *r_sig,
gcry_sexp_t s_data,
gcry_sexp_t keyparms);
/* Type for the pk_verify function. */
typedef gcry_err_code_t (*gcry_pk_verify_t) (gcry_sexp_t s_sig,
gcry_sexp_t s_data,
gcry_sexp_t keyparms);
/* Type for the pk_get_nbits function. */
typedef unsigned (*gcry_pk_get_nbits_t) (gcry_sexp_t keyparms);
/* The type used to compute the keygrip. */
typedef gpg_err_code_t (*pk_comp_keygrip_t) (gcry_md_hd_t md,
gcry_sexp_t keyparm);
/* The type used to query ECC curve parameters. */
typedef gcry_err_code_t (*pk_get_param_t) (const char *name,
gcry_mpi_t *pkey);
/* The type used to query an ECC curve name. */
typedef const char *(*pk_get_curve_t)(gcry_mpi_t *pkey, int iterator,
unsigned int *r_nbits);
/* The type used to query ECC curve parameters by name. */
typedef gcry_sexp_t (*pk_get_curve_param_t)(const char *name);
/* Module specification structure for public key algoritms. */
typedef struct gcry_pk_spec
{
int algo;
struct {
unsigned int disabled:1;
unsigned int fips:1;
} flags;
int use;
const char *name;
const char **aliases;
const char *elements_pkey;
const char *elements_skey;
const char *elements_enc;
const char *elements_sig;
const char *elements_grip;
gcry_pk_generate_t generate;
gcry_pk_check_secret_key_t check_secret_key;
gcry_pk_encrypt_t encrypt;
gcry_pk_decrypt_t decrypt;
gcry_pk_sign_t sign;
gcry_pk_verify_t verify;
gcry_pk_get_nbits_t get_nbits;
selftest_func_t selftest;
pk_comp_keygrip_t comp_keygrip;
pk_get_param_t get_param;
pk_get_curve_t get_curve;
pk_get_curve_param_t get_curve_param;
} gcry_pk_spec_t;
/*
*
* Symmetric cipher related definitions.
*
*/
/* Type for the cipher_setkey function. */
typedef gcry_err_code_t (*gcry_cipher_setkey_t) (void *c,
const unsigned char *key,
unsigned keylen);
/* Type for the cipher_encrypt function. */
typedef unsigned int (*gcry_cipher_encrypt_t) (void *c,
unsigned char *outbuf,
const unsigned char *inbuf);
/* Type for the cipher_decrypt function. */
typedef unsigned int (*gcry_cipher_decrypt_t) (void *c,
unsigned char *outbuf,
const unsigned char *inbuf);
/* Type for the cipher_stencrypt function. */
typedef void (*gcry_cipher_stencrypt_t) (void *c,
unsigned char *outbuf,
const unsigned char *inbuf,
unsigned int n);
/* Type for the cipher_stdecrypt function. */
typedef void (*gcry_cipher_stdecrypt_t) (void *c,
unsigned char *outbuf,
const unsigned char *inbuf,
unsigned int n);
/* The type used to convey additional information to a cipher. */
typedef gpg_err_code_t (*cipher_set_extra_info_t)
(void *c, int what, const void *buffer, size_t buflen);
/* The type used to set an IV directly in the algorithm module. */
typedef void (*cipher_setiv_func_t)(void *c,
const byte *iv, unsigned int ivlen);
/* A structure to map OIDs to encryption modes. */
typedef struct gcry_cipher_oid_spec
{
const char *oid;
int mode;
} gcry_cipher_oid_spec_t;
/* Module specification structure for ciphers. */
typedef struct gcry_cipher_spec
{
int algo;
struct {
unsigned int disabled:1;
unsigned int fips:1;
} flags;
const char *name;
const char **aliases;
gcry_cipher_oid_spec_t *oids;
size_t blocksize;
size_t keylen;
size_t contextsize;
gcry_cipher_setkey_t setkey;
gcry_cipher_encrypt_t encrypt;
gcry_cipher_decrypt_t decrypt;
gcry_cipher_stencrypt_t stencrypt;
gcry_cipher_stdecrypt_t stdecrypt;
selftest_func_t selftest;
cipher_set_extra_info_t set_extra_info;
cipher_setiv_func_t setiv;
} gcry_cipher_spec_t;
/*
*
* Message digest related definitions.
*
*/
/* Type for the md_init function. */
typedef void (*gcry_md_init_t) (void *c);
/* Type for the md_write function. */
typedef void (*gcry_md_write_t) (void *c, const void *buf, size_t nbytes);
/* Type for the md_final function. */
typedef void (*gcry_md_final_t) (void *c);
/* Type for the md_read function. */
typedef unsigned char *(*gcry_md_read_t) (void *c);
typedef struct gcry_md_oid_spec
{
const char *oidstring;
} gcry_md_oid_spec_t;
/* Module specification structure for message digests. */
typedef struct gcry_md_spec
{
int algo;
struct {
unsigned int disabled:1;
unsigned int fips:1;
} flags;
const char *name;
unsigned char *asnoid;
int asnlen;
gcry_md_oid_spec_t *oids;
int mdlen;
gcry_md_init_t init;
gcry_md_write_t write;
gcry_md_final_t final;
gcry_md_read_t read;
size_t contextsize; /* allocate this amount of context */
selftest_func_t selftest;
} gcry_md_spec_t;
/* The selftest functions. */
gcry_error_t _gcry_cipher_selftest (int algo, int extended,
selftest_report_func_t report);
gcry_error_t _gcry_md_selftest (int algo, int extended,
selftest_report_func_t report);
gcry_error_t _gcry_pk_selftest (int algo, int extended,
selftest_report_func_t report);
gcry_error_t _gcry_hmac_selftest (int algo, int extended,
selftest_report_func_t report);
gcry_error_t _gcry_random_selftest (selftest_report_func_t report);
/*-- pubkey.c --*/
gcry_err_code_t _gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp,
int reserved, gcry_ctx_t ctx);
#endif /*G10_CIPHER_PROTO_H*/
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 4, 5:37 AM (1 d, 15 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
a0/7b/e4455f31b22731711375d4799019
Attached To
rC libgcrypt
Event Timeline
Log In to Comment