The following works:
   gpg2 --gen-key (ECC)
   gpg2 --list-keys
   gpg2 --list-packets ~/.gnupg/pubring.gpg
   gpg2 --list-packets <private key from http://sites.google.com/site/brainhub/pgpecckeys>

ECDH doesn't work yet as the code must be re-written to adjust for gpg-agent refactoring.
This commit is contained in:
Andrey Jivsov 2011-01-05 17:33:17 -08:00
parent 7bbc07fde0
commit e0972d3d96
34 changed files with 1497 additions and 176 deletions

View File

@ -27,6 +27,7 @@
#include "agent.h"
#include "i18n.h"
#include "cvt-openpgp.h"
#include "../include/cipher.h" /* for PUBKEY_ALGO_ECDSA, PUBKEY_ALGO_ECDH */
/* Helper to pass data via the callback to do_unprotect. */
@ -49,7 +50,12 @@ struct try_do_unprotect_arg_s
gcry_sexp_t *r_key;
};
/* TODO: it is also in misc, which is not linked with the agent */
static int
map_pk_openpgp_to_gcry (int algo)
{
return (algo==PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : (algo==PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo));
}
/* Compute the keygrip from the public key and store it at GRIP. */
static gpg_error_t
@ -80,6 +86,12 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
"(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
break;
case GCRY_PK_ECDSA:
case GCRY_PK_ECDH:
err = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecc(c%m)(q%m)))", pkey[0], pkey[1]);
break;
default:
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
break;
@ -94,7 +106,9 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
/* Convert a secret key given as algorithm id and an array of key
parameters into our s-expression based format. */
parameters into our s-expression based format.
pubkey_algo is a libgcrypt ID
*/
static gpg_error_t
convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
{
@ -103,6 +117,8 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
*r_key = NULL;
pubkey_algo = map_pk_openpgp_to_gcry( pubkey_algo );
switch (pubkey_algo)
{
case GCRY_PK_DSA:
@ -128,6 +144,18 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
skey[5]);
break;
case GCRY_PK_ECDSA:
err = gcry_sexp_build (&s_skey, NULL,
"(private-key(ecdsa(c%m)(q%m)(d%m)))",
skey[0], skey[1], skey[2]);
break;
case GCRY_PK_ECDH:
err = gcry_sexp_build (&s_skey, NULL,
"(private-key(ecdh(c%m)(q%m)(p%m)(d%m)))",
skey[0], skey[1], skey[2], skey[3]);
break;
default:
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
break;
@ -202,6 +230,10 @@ do_unprotect (const char *passphrase,
*r_key = NULL;
/* Unfortunately, the OpenPGP PK algorithm numbers need to be re-mapped for Libgcrypt
*/
pubkey_algo = map_pk_openpgp_to_gcry( pubkey_algo );
/* Count the actual number of MPIs is in the array and set the
remainder to NULL for easier processing later on. */
for (skeylen = 0; skey[skeylen]; skeylen++)
@ -219,9 +251,6 @@ do_unprotect (const char *passphrase,
if (gcry_pk_test_algo (pubkey_algo))
{
/* The algorithm numbers are Libgcrypt numbers but fortunately
the OpenPGP algorithm numbers map one-to-one to the Libgcrypt
numbers. */
log_info (_("public key algorithm %d (%s) is not supported\n"),
pubkey_algo, gcry_pk_algo_name (pubkey_algo));
return gpg_error (GPG_ERR_PUBKEY_ALGO);
@ -632,7 +661,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
string = gcry_sexp_nth_string (list, 1);
if (!string)
goto bad_seckey;
pubkey_algo = gcry_pk_map_name (string);
pubkey_algo = gcry_pk_map_name (string); /* ligcrypt IDs */
xfree (string);
if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
@ -999,6 +1028,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
}
algo = gcry_pk_map_name (name);
log_debug ( "convert to openpgp begin for algo=%s\n", name );
xfree (name);
switch (algo)
@ -1007,7 +1037,8 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
case GCRY_PK_ELG: algoname = "elg"; npkey = 3; elems = "pgyx"; break;
case GCRY_PK_ELG_E: algoname = "elg"; npkey = 3; elems = "pgyx"; break;
case GCRY_PK_DSA: algoname = "dsa"; npkey = 4; elems = "pqgyx"; break;
case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 6; elems = "pabgnqd"; break;
case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 2; elems = "cqd"; break;
case GCRY_PK_ECDH: algoname = "ecdh"; npkey = 3; elems = "cqpd"; break;
default: algoname = ""; npkey = 0; elems = NULL; break;
}
assert (!elems || strlen (elems) < DIM (array) );
@ -1027,6 +1058,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
err = apply_protection (array, npkey, nskey, passphrase,
GCRY_CIPHER_AES, protect_iv, sizeof protect_iv,
3, GCRY_MD_SHA1, salt, s2k_count);
///log_debug ( "convert to openpgp: after applying protection, err = %d\n", err );
/* Turn it into the transfer key S-expression. Note that we always
return a protected key. */
if (!err)
@ -1037,7 +1069,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
int format_args_buf_int[1];
void *format_args[10+2];
size_t n;
gcry_sexp_t tmpkey, tmpsexp;
gcry_sexp_t tmpkey, tmpsexp = NULL;
snprintf (countbuf, sizeof countbuf, "%lu", s2k_count);
@ -1056,6 +1088,8 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
put_membuf_str (&mbuf, ")\n");
put_membuf (&mbuf, "", 1);
///log_debug ( "convert to openpgp: calling gcry_sexp_build\n" );
tmpkey = NULL;
{
char *format = get_membuf (&mbuf, NULL);
@ -1065,6 +1099,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
err = gcry_sexp_build_array (&tmpkey, NULL, format, format_args);
xfree (format);
}
///log_debug ( "convert to openpgp: calling gcry_sexp_build before err=%d\n", err );
if (!err)
err = gcry_sexp_build (&tmpsexp, NULL,
"(openpgp-private-key\n"
@ -1077,6 +1112,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
(int)sizeof protect_iv, protect_iv,
(int)sizeof salt, salt,
countbuf);
///log_debug ( "convert to openpgp: after gcry_sexp_build, err = %d\n", err );
gcry_sexp_release (tmpkey);
if (!err)
err = make_canon_sexp_pad (tmpsexp, 0, r_transferkey, r_transferkeylen);
@ -1085,6 +1121,8 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
for (i=0; i < DIM (array); i++)
gcry_mpi_release (array[i]);
log_debug ( "convert to openpgp end with err=%d\n", err );
return err;
}

View File

@ -726,6 +726,16 @@ key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
algoname = "dsa";
elems = "pqgy";
}
else if (n==5 && !memcmp (name, "ecdsa", 5))
{
algoname = "ecdsa";
elems = "cq";
}
else if (n==4 && !memcmp (name, "ecdh", 4))
{
algoname = "ecdh";
elems = "cqp";
}
else if (n==3 && !memcmp (name, "elg", 3))
{
algoname = "elg";

View File

@ -52,6 +52,8 @@ static struct {
{ "rsa", "nedpqu", 2, 5 },
{ "dsa", "pqgyx", 4, 4 },
{ "elg", "pgyx", 3, 3 },
{ "ecdsa","cqd", 2, 2 },
{ "ecdh", "cqpd", 3, 3 },
{ NULL }
};
@ -426,6 +428,9 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char *p;
gcry_md_hd_t md;
if (opt.debug & DBG_CRYPTO_VALUE)
log_info ("Protecting key=%s, passphrase=%s\n", plainkey, passphrase);
/* Create an S-expression with the protected-at timestamp. */
memcpy (timestamp_exp, "(12:protected-at15:", 19);
gnupg_get_isotime (timestamp_exp+19);
@ -454,37 +459,51 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
for (infidx=0; protect_info[infidx].algo
&& !smatch (&s, n, protect_info[infidx].algo); infidx++)
;
if (!protect_info[infidx].algo)
if (!protect_info[infidx].algo) {
log_info ("Unsupported alg %d for protection\n", protect_info[infidx].algo);
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
}
prot_begin = prot_end = NULL;
for (i=0; (c=protect_info[infidx].parmlist[i]); i++)
{
if (i == protect_info[infidx].prot_from)
prot_begin = s;
if (*s != '(')
if (*s != '(') {
log_info ("Unbalanced bracket in S-expression #1\n");
return gpg_error (GPG_ERR_INV_SEXP);
}
depth++;
s++;
n = snext (&s);
if (!n)
if (!n) {
log_info ("Cannot get the length of S-expression field\n");
return gpg_error (GPG_ERR_INV_SEXP);
if (n != 1 || c != *s)
}
if (n != 1 || c != *s) {
log_info ("Invalid length in S-expression field\n");
return gpg_error (GPG_ERR_INV_SEXP);
s += n;
}
s += n;
n = snext (&s);
if (!n)
if (!n) {
log_info ("Invalid fieled in S-expression field\n");
return gpg_error (GPG_ERR_INV_SEXP);
}
s +=n; /* skip value */
if (*s != ')')
if (*s != ')') {
log_info ("Unbalanced bracket in S-expression #2\n");
return gpg_error (GPG_ERR_INV_SEXP);
}
depth--;
if (i == protect_info[infidx].prot_to)
prot_end = s;
s++;
}
if (*s != ')' || !prot_begin || !prot_end )
if (*s != ')' || !prot_begin || !prot_end ) {
log_info ("Unbalanced bracket in S-expression #3\n");
return gpg_error (GPG_ERR_INV_SEXP);
}
depth--;
hash_end = s;
s++;

View File

@ -23,6 +23,7 @@
#include <ctype.h>
#include "util.h"
#include "gcrypt.h"
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
@ -245,5 +246,31 @@ hex2str_alloc (const char *hexstring, size_t *r_count)
return result;
}
/* returns hex representation of the MPI;
* caller must free with xfree
* Returns NULL on error, never throws
*/
char *mpi2hex( gcry_mpi_t m ) {
size_t nbytes;
size_t nbytes2;
int rc;
byte *p;
nbytes = (mpi_get_nbits ( m )+7)/8;
if( nbytes == 0 )
return NULL;
p = xtrymalloc( nbytes*3+1 );
if( p==NULL )
return NULL;
rc = gcry_mpi_print (GCRYMPI_FMT_USG, p+2*nbytes+1, nbytes, &nbytes2, m);
if( rc ) {
xfree( p );
return NULL;
}
bin2hex( p+2*nbytes+1, nbytes2, p );
p[nbytes2*2] = '\0';
//printf("%s:%d>>>> Created the string %s from %d bytes %02x %02x ..., MPI was %d bytes\n", __FILE__, __LINE__, p, nbytes2, p[2*nbytes+1], p[2*nbytes+2], nbytes);
return p;
}

View File

@ -192,6 +192,7 @@ gpg_error_t get_pk_algo_from_canon_sexp (const unsigned char *keydata,
int hex2bin (const char *string, void *buffer, size_t length);
int hexcolon2bin (const char *string, void *buffer, size_t length);
char *bin2hex (const void *buffer, size_t length, char *stringbuf);
char *mpi2hex (gcry_mpi_t m);
char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf);
const char *hex2str (const char *hexstring,
char *buffer, size_t bufsize, size_t *buflen);

View File

@ -24,7 +24,7 @@ min_automake_version="1.10"
# Remember to change the version number immediately *after* a release.
# Set my_issvn to "yes" for non-released code. Remember to run an
# "svn up" and "autogen.sh" right before creating a distribution.
m4_define([my_version], [2.1.0])
m4_define([my_version], [2.2.0])
m4_define([my_issvn], [yes])
m4_define([svn_revision], m4_esyscmd([printf "%d" $(svn info 2>/dev/null \
@ -43,7 +43,7 @@ development_version=no
NEED_GPG_ERROR_VERSION=1.8
NEED_LIBGCRYPT_API=1
NEED_LIBGCRYPT_VERSION=1.4.0
NEED_LIBGCRYPT_VERSION=1.6.0
NEED_LIBASSUAN_API=2
NEED_LIBASSUAN_VERSION=2.0.0
@ -1466,7 +1466,7 @@ AC_ARG_ENABLE(optimization,
AC_HELP_STRING([--disable-optimization],
[disable compiler optimization]),
[if test $enableval = no ; then
CFLAGS=`echo $CFLAGS | sed s/-O[[1-9]]\ /-O0\ /g`
CFLAGS=`echo $CFLAGS | sed s%-O[[1-9]]%-O0\ %g`
fi])
#

View File

@ -61,7 +61,7 @@ endif
dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL) $(LIBICONV)
if !USE_LDAPWRAPPER
dirmngr_LDADD += $(LDAPLIBS)
dirmngr_LDADD += $(LDAPLIBS) -llber
endif
dirmngr_LDFLAGS = $(extra_bin_ldflags)

View File

@ -72,7 +72,8 @@ common_source = \
plaintext.c \
sig-check.c \
keylist.c \
pkglue.c pkglue.h
pkglue.c pkglue.h \
ecdh.c
gpg2_SOURCES = gpg.c \
server.c \
@ -109,7 +110,8 @@ gpg2_SOURCES = gpg.c \
gpgv2_SOURCES = gpgv.c \
$(common_source) \
verify.c
verify.c \
verify-stubs.c
#gpgd_SOURCES = gpgd.c \
# ks-proto.h \

View File

@ -1079,7 +1079,7 @@ armor_filter( void *opaque, int control,
iobuf_writestr(a,afx->eol);
if( !opt.no_version )
{
iobuf_writestr(a, "Version: GnuPG v" VERSION " ("
iobuf_writestr(a, "Version: GnuPG v" VERSION "-ecc ("
PRINTABLE_OS_NAME ")" );
iobuf_writestr(a,afx->eol);
}

View File

@ -178,6 +178,16 @@ mpi_write (iobuf_t out, gcry_mpi_t a)
return rc;
}
/*
* Write the name OID, encoded as an mpi, to OUT. The format of the content of the MPI is
* one byte LEN, following by LEN bytes that are DER representation of an ASN.1 OID.
* This is true for each of the 3 following functions.
*/
#define iobuf_name_oid_write iobuf_write_size_body_mpi
/* Write the value of KEK fields for ECDH. */
#define ecdh_kek_params_write iobuf_write_size_body_mpi
/* Write the value of encrypted filed for ECDH. */
#define ecdh_esk_write iobuf_write_size_body_mpi
/****************
@ -290,10 +300,24 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
}
assert (npkey < nskey);
/* Writing the public parameters is easy. */
for (i=0; i < npkey; i++ )
if ((err = mpi_write (a, pk->pkey[i])))
goto leave;
if( pk->pubkey_algo != PUBKEY_ALGO_ECDSA && pk->pubkey_algo != PUBKEY_ALGO_ECDH ) {
/* Writing the public parameters is easy, */
for (i=0; i < npkey; i++ )
if ((err = mpi_write (a, pk->pkey[i])))
goto leave;
}
else {
/* ... except we do an adjustment for ECC OID and possibly KEK params for ECDH */
if( (err=iobuf_name_oid_write(a, pk->pkey[0])) || /* DER of OID with preceeding length byte */
(err = mpi_write (a, pk->pkey[1])) ) /* point Q, the public key */
{
goto leave;
}
if( pk->pubkey_algo == PUBKEY_ALGO_ECDH && (err=ecdh_kek_params_write(a,pk->pkey[2]))) { /* one more public field for ECDH */
goto leave;
}
/* followed by possibly protected private scalar */
}
if (pk->seckey_info)
{
@ -458,8 +482,18 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
n = pubkey_get_nenc( enc->pubkey_algo );
if ( !n )
write_fake_data( a, enc->data[0] );
for (i=0; i < n && !rc ; i++ )
rc = mpi_write(a, enc->data[i] );
if( enc->pubkey_algo != PUBKEY_ALGO_ECDH ) {
for (i=0; i < n && !rc ; i++ )
rc = mpi_write(a, enc->data[i] );
}
else {
/* the second field persists as a LEN+field structure, even though it is
* stored for uniformity as an MPI internally */
assert( n==2 );
rc = mpi_write(a, enc->data[0] );
if( !rc ) rc = ecdh_esk_write(a, enc->data[1] );
}
if (!rc)
{

View File

@ -1744,6 +1744,7 @@ inq_ciphertext_cb (void *opaque, const char *line)
gpg_error_t
agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
gcry_sexp_t s_ciphertext,
const byte sk_fp[MAX_FINGERPRINT_LEN],
unsigned char **r_buf, size_t *r_buflen)
{
gpg_error_t err;
@ -1751,6 +1752,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
membuf_t data;
size_t n, len;
char *p, *buf, *endp;
/*TODO: use sk_fp */
if (!keygrip || strlen(keygrip) != 40 || !s_ciphertext || !r_buf || !r_buflen)
return gpg_error (GPG_ERR_INV_VALUE);

View File

@ -168,6 +168,7 @@ gpg_error_t agent_pksign (ctrl_t ctrl, const char *cache_nonce,
/* Decrypt a ciphertext. */
gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
gcry_sexp_t s_ciphertext,
const byte sk_fp[MAX_FINGERPRINT_LEN],
unsigned char **r_buf, size_t *r_buflen);
/* Retrieve a key encryption key. */

477
g10/ecdh.c Normal file
View File

@ -0,0 +1,477 @@
/* ecdh.c - ECDH public key operations used in public key glue code
* Copyright (C) 2000, 2003 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU 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 <assert.h>
#include "gpg.h"
#include "util.h"
#include "pkglue.h"
#include "main.h"
#include "options.h"
gcry_mpi_t
pk_ecdh_default_params_to_mpi( int qbits ) {
gpg_error_t err;
gcry_mpi_t result;
/* Defaults are the strongest possible choices. Performance is not an issue here, only interoperability. */
byte kek_params[4] = {
3 /*size of following field*/,
1 /*fixed version for KDF+AESWRAP*/,
DIGEST_ALGO_SHA512 /* KEK MD */,
CIPHER_ALGO_AES256 /*KEK AESWRAP alg*/
};
int i;
static const struct {
int qbits;
int openpgp_hash_id;
int openpgp_cipher_id;
} kek_params_table[] = {
{ 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES },
{ 384, DIGEST_ALGO_SHA384, CIPHER_ALGO_AES256 },
{ 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 } // 528 is 521 rounded to the 8 bit boundary
};
for( i=0; i<sizeof(kek_params_table)/sizeof(kek_params_table[0]); i++ ) {
if( kek_params_table[i].qbits >= qbits ) {
kek_params[2] = kek_params_table[i].openpgp_hash_id;
kek_params[3] = kek_params_table[i].openpgp_cipher_id;
break;
}
}
if( DBG_CIPHER )
log_printhex ("ecdh kek params are", kek_params, sizeof(kek_params) );
err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, kek_params, sizeof(kek_params), NULL);
if (err)
log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err));
return result;
}
/* returns allocated (binary) KEK parameters; the size is returned in sizeout.
* The caller must free returned value with xfree.
* Returns NULL on error
*/
byte *
pk_ecdh_default_params( int qbits, size_t *sizeout ) {
gpg_error_t err;
gcry_mpi_t result;
/* Defaults are the strongest possible choices. Performance is not an issue here, only interoperability. */
byte kek_params[4] = {
3 /*size of following field*/,
1 /*fixed version for KDF+AESWRAP*/,
DIGEST_ALGO_SHA512 /* KEK MD */,
CIPHER_ALGO_AES256 /*KEK AESWRAP alg*/
};
int i;
static const struct {
int qbits;
int openpgp_hash_id;
int openpgp_cipher_id;
} kek_params_table[] = {
{ 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES },
{ 384, DIGEST_ALGO_SHA384, CIPHER_ALGO_AES256 },
{ 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 } // 528 is 521 rounded to the 8 bit boundary
};
byte *p;
*sizeout = 0;
for( i=0; i<sizeof(kek_params_table)/sizeof(kek_params_table[0]); i++ ) {
if( kek_params_table[i].qbits >= qbits ) {
kek_params[2] = kek_params_table[i].openpgp_hash_id;
kek_params[3] = kek_params_table[i].openpgp_cipher_id;
break;
}
}
if( DBG_CIPHER )
log_printhex ("ecdh kek params are", kek_params, sizeof(kek_params) );
p = xtrymalloc( sizeof(kek_params) );
if( p == NULL )
return NULL;
memcpy( p, kek_params, sizeof(kek_params) );
*sizeout = sizeof(kek_params);
return p;
}
/* Encrypts/decrypts 'data' with a key derived from shared_mpi ECC point using FIPS SP 800-56A compliant method, which is
* key derivation + key wrapping. The direction is determined by the first parameter (is_encrypt=1 --> this is encryption).
* The result is returned in out as a size+value MPI.
* TODO: memory leaks (x_secret).
*/
static int
pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t * pkey, gcry_mpi_t *out)
{
byte *secret_x;
int secret_x_size;
byte kdf_params[256];
int kdf_params_size=0;
int nbits;
int kdf_hash_algo;
int kdf_encr_algo;
int rc;
*out = NULL;
nbits = pubkey_nbits( PUBKEY_ALGO_ECDH, pkey );
{
size_t nbytes;
/* extract x component of the shared point: this is the actual shared secret */
nbytes = (mpi_get_nbits (pkey[1] /* public point */)+7)/8;
secret_x = xmalloc_secure( nbytes );
rc = gcry_mpi_print (GCRYMPI_FMT_USG, secret_x, nbytes, &nbytes, shared_mpi);
if( rc ) {
xfree( secret_x );
log_error ("ec ephemeral export of shared point failed: %s\n", gpg_strerror (rc) );
return rc;
}
secret_x_size = (nbits+7)/8;
assert( nbytes > secret_x_size );
memmove( secret_x, secret_x+1, secret_x_size );
memset( secret_x+secret_x_size, 0, nbytes-secret_x_size );
if( DBG_CIPHER )
log_printhex ("ecdh shared secret X is:", secret_x, secret_x_size );
}
/*** We have now the shared secret bytes in secret_x ***/
/* At this point we are done with PK encryption and the rest of the function uses symmetric
* key encryption techniques to protect the input 'data'. The following two sections will
* simply replace current secret_x with a value derived from it. This will become a KEK.
*/
{
IOBUF obuf = iobuf_temp();
rc = iobuf_write_size_body_mpi ( obuf, pkey[2] ); /* KEK params */
kdf_params_size = iobuf_temp_to_buffer( obuf, kdf_params, sizeof(kdf_params) );
if( DBG_CIPHER )
log_printhex ("ecdh KDF public key params are:", kdf_params, kdf_params_size );
if( kdf_params_size != 4 || kdf_params[0] != 3 || kdf_params[1] != 1 ) /* expect 4 bytes 03 01 hash_alg symm_alg */
return GPG_ERR_BAD_PUBKEY;
kdf_hash_algo = kdf_params[2];
kdf_encr_algo = kdf_params[3];
if( DBG_CIPHER )
log_debug ("ecdh KDF algorithms %s+%s with aeswrap\n", gcry_md_algo_name (kdf_hash_algo), openpgp_cipher_algo_name (kdf_encr_algo) );
if( kdf_hash_algo != GCRY_MD_SHA256 && kdf_hash_algo != GCRY_MD_SHA384 && kdf_hash_algo != GCRY_MD_SHA512 )
return GPG_ERR_BAD_PUBKEY;
if( kdf_encr_algo != GCRY_CIPHER_AES128 && kdf_encr_algo != GCRY_CIPHER_AES192 && kdf_encr_algo != GCRY_CIPHER_AES256 )
return GPG_ERR_BAD_PUBKEY;
}
/* build kdf_params */
{
IOBUF obuf;
obuf = iobuf_temp();
/* variable-length field 1, curve name OID */
rc = iobuf_write_size_body_mpi ( obuf, pkey[0] );
/* fixed-length field 2 */
iobuf_put (obuf, PUBKEY_ALGO_ECDH);
/* variable-length field 3, KDF params */
rc = (rc ? rc : iobuf_write_size_body_mpi ( obuf, pkey[2] ));
/* fixed-length field 4 */
iobuf_write (obuf, "Anonymous Sender ", 20);
/* fixed-length field 5, recipient fp */
iobuf_write (obuf, pk_fp, 20);
kdf_params_size = iobuf_temp_to_buffer( obuf, kdf_params, sizeof(kdf_params) );
iobuf_close( obuf );
if( rc ) {
return rc;
}
if( DBG_CIPHER )
log_printhex ("ecdh KDF message params are:", kdf_params, kdf_params_size );
}
/* Derive a KEK (key wrapping key) using kdf_params and secret_x. */
{
gcry_md_hd_t h;
int old_size;
rc = gcry_md_open (&h, kdf_hash_algo, 0);
if(rc)
log_bug ("gcry_md_open failed for algo %d: %s",
kdf_hash_algo, gpg_strerror (gcry_error(rc)));
gcry_md_write(h, "\x00\x00\x00\x01", 4); /* counter = 1 */
gcry_md_write(h, secret_x, secret_x_size); /* x of the point X */
gcry_md_write(h, kdf_params, kdf_params_size); /* KDF parameters */
gcry_md_final (h);
assert( gcry_md_get_algo_dlen (kdf_hash_algo) >= 32 );
memcpy (secret_x, gcry_md_read (h, kdf_hash_algo), gcry_md_get_algo_dlen (kdf_hash_algo));
gcry_md_close (h);
old_size = secret_x_size;
assert( old_size >= gcry_cipher_get_algo_keylen( kdf_encr_algo ) );
secret_x_size = gcry_cipher_get_algo_keylen( kdf_encr_algo );
assert( secret_x_size <= gcry_md_get_algo_dlen (kdf_hash_algo) );
memset( secret_x+secret_x_size, old_size-secret_x_size, 0 ); /* we could have allocated more, so clean the tail before returning */
if( DBG_CIPHER )
log_printhex ("ecdh KEK is:", secret_x, secret_x_size );
}
/* And, finally, aeswrap with key secret_x */
{
gcry_cipher_hd_t hd;
size_t nbytes;
byte *data_buf;
int data_buf_size;
gcry_mpi_t result;
rc = gcry_cipher_open (&hd, kdf_encr_algo, GCRY_CIPHER_MODE_AESWRAP, 0);
if (rc)
{
log_error( "ecdh failed to initialize AESWRAP: %s\n", gpg_strerror (rc));
return rc;
}
rc = gcry_cipher_setkey (hd, secret_x, secret_x_size);
xfree( secret_x );
if (rc)
{
gcry_cipher_close (hd);
log_error("ecdh failed in gcry_cipher_setkey: %s\n", gpg_strerror (rc));
return rc;
}
data_buf_size = (gcry_mpi_get_nbits(data)+7)/8;
assert( (data_buf_size & 7) == (is_encrypt ? 0 : 1) );
data_buf = xmalloc_secure( 1 + 2*data_buf_size + 8 );
if( !data_buf ) {
gcry_cipher_close (hd);
return GPG_ERR_ENOMEM;
}
if( is_encrypt ) {
byte *in = data_buf+1+data_buf_size+8;
/* write data MPI into the end of data_buf. data_buf is size aeswrap data */
rc = gcry_mpi_print (GCRYMPI_FMT_USG, in, data_buf_size, &nbytes, data/*in*/);
if( rc ) {
log_error("ecdh failed to export DEK: %s\n", gpg_strerror (rc));
gcry_cipher_close (hd);
xfree( data_buf );
return rc;
}
if( DBG_CIPHER )
log_printhex ("ecdh encrypting :", in, data_buf_size );
rc = gcry_cipher_encrypt (hd, data_buf+1, data_buf_size+8, in, data_buf_size);
memset( in, 0, data_buf_size);
gcry_cipher_close (hd);
if(rc)
{
log_error("ecdh failed in gcry_cipher_encrypt: %s\n", gpg_strerror (rc));
xfree( data_buf );
return rc;
}
data_buf[0] = data_buf_size+8;
if( DBG_CIPHER )
log_printhex ("ecdh encrypted to:", data_buf+1, data_buf[0] );
rc = gcry_mpi_scan ( &result, GCRYMPI_FMT_USG, data_buf, 1+data_buf[0], NULL); /* (byte)size + aeswrap of DEK */
xfree( data_buf );
if(rc)
{
log_error("ecdh failed to create an MPI: %s\n", gpg_strerror (rc));
return rc;
}
*out = result;
}
else {
byte *in;
rc = gcry_mpi_print (GCRYMPI_FMT_USG, data_buf, data_buf_size, &nbytes, data/*in*/);
if( nbytes != data_buf_size || data_buf[0] != data_buf_size-1 ) {
log_error("ecdh inconsistent size\n");
xfree( data_buf );
return GPG_ERR_BAD_MPI;
}
in = data_buf+data_buf_size;
data_buf_size = data_buf[0];
if( DBG_CIPHER )
log_printhex ("ecdh decrypting :", data_buf+1, data_buf_size );
rc = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1, data_buf_size );
gcry_cipher_close (hd);
if(rc)
{
log_error("ecdh failed in gcry_cipher_decrypt: %s\n", gpg_strerror (rc));
xfree( data_buf );
return rc;
}
data_buf_size-=8;
if( DBG_CIPHER )
log_printhex ("ecdh decrypted to :", in, data_buf_size );
/* padding is removed later */
//if( in[data_buf_size-1] > 8 ) {
// log_error("ecdh failed at decryption: invalid padding. %02x > 8\n", in[data_buf_size-1] );
// return GPG_ERR_BAD_KEY;
//}
rc = gcry_mpi_scan ( &result, GCRYMPI_FMT_USG, in, data_buf_size, NULL);
xfree( data_buf );
if(rc)
{
log_error("ecdh failed to create a plain text MPI: %s\n", gpg_strerror (rc));
return rc;
}
*out = result;
}
}
return rc;
}
/* Perform ECDH encryption, which involves ECDH key generation.
*/
int
pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t * pkey)
{
gcry_sexp_t s_ciph, s_data, s_pkey;
PKT_public_key *pk_eph;
int nbits;
int rc;
nbits = pubkey_nbits( PUBKEY_ALGO_ECDH, pkey );
/*** Generate an ephemeral key ***/
rc = pk_ecc_keypair_gen( &pk_eph, PUBKEY_ALGO_ECDH, KEYGEN_FLAG_TRANSIENT_KEY | KEYGEN_FLAG_NO_PROTECTION /*this is ephemeral*/, "", nbits );
if( rc )
return rc;
if( DBG_CIPHER ) {
unsigned char *buffer;
if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, pk_eph->pkey[1]))
BUG ();
log_debug("ephemeral key MPI #0: %s\n", buffer);
gcry_free( buffer );
}
free_public_key (pk_eph);
/*** Done with ephemeral key generation.
* Now use ephemeral secret to get the shared secret. ***/
rc = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecdh(c%m)(q%m)(p%m)))", pkey[0], pkey[1], pkey[2]);
if (rc)
BUG ();
/* put the data into a simple list */
if (gcry_sexp_build (&s_data, NULL, "%m", pk_eph->pkey[3])) /* ephemeral scalar goes as data */
BUG ();
/* pass it to libgcrypt */
rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
gcry_sexp_release (s_data);
gcry_sexp_release (s_pkey);
if (rc)
return rc;
/* finally, perform encryption */
{
gcry_mpi_t shared = mpi_from_sexp (s_ciph, "a"); /* ... and get the shared point */
gcry_sexp_release (s_ciph);
resarr[0] = pk_eph->pkey[1]; /* ephemeral public key */
if( DBG_CIPHER ) {
unsigned char *buffer;
if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, resarr[0]))
BUG ();
log_debug("ephemeral key MPI: %s\n", buffer);
gcry_free( buffer );
}
rc = pk_ecdh_encrypt_with_shared_point ( 1 /*=encrypton*/, shared, pk_fp, data, pkey, resarr+1 );
mpi_release( shared );
}
return rc;
}
/* Perform ECDH decryption.
*/
int
pk_ecdh_decrypt (gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t *data, gcry_mpi_t * skey) {
gcry_sexp_t s_skey, s_data, s_ciph;
int rc;
if (!data[0] || !data[1])
return gpg_error (GPG_ERR_BAD_MPI);
rc = gcry_sexp_build (&s_skey, NULL,
"(public-key(ecdh(c%m)(q%m)(p%m)))",
skey[0]/*curve*/, data[0]/*ephemeral key*/, skey[2]/*KDF params*/);
if (rc)
BUG ();
/* put the data into a simple list */
if (gcry_sexp_build (&s_data, NULL, "%m", skey[3])) /* static private key (scalar) goes as data */
BUG ();
rc = gcry_pk_encrypt (&s_ciph, s_data, s_skey); /* encrypting ephemeral key with our private scalar yields the shared point */
gcry_sexp_release (s_skey);
gcry_sexp_release (s_data);
if (rc)
return rc;
{
gcry_mpi_t shared = mpi_from_sexp (s_ciph, "a"); /* get the shared point */
gcry_sexp_release (s_ciph);
rc = pk_ecdh_encrypt_with_shared_point ( 0 /*=decryption*/, shared, sk_fp, data[1]/*encr data as an MPI*/, skey, result );
mpi_release( shared );
}
return rc;
}

View File

@ -876,7 +876,9 @@ write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
for ( ; pk_list; pk_list = pk_list->next )
{
gcry_mpi_t frame;
byte fp[MAX_FINGERPRINT_LEN];
size_t fpn;
pk = pk_list->pk;
print_pubkey_algo_note ( pk->pubkey_algo );
@ -892,6 +894,9 @@ write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
compliance_failure();
}
fingerprint_from_pk( pk, fp, &fpn );
assert( fpn == 20 );
/* Okay, what's going on: We have the session key somewhere in
* the structure DEK and want to encode this session key in an
* integer value of n bits. pubkey_nbits gives us the number of
@ -904,9 +909,9 @@ write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
* for Elgamal). We don't need frame anymore because we have
* everything now in enc->data which is the passed to
* build_packet(). */
frame = encode_session_key (dek,
frame = encode_session_key (pk->pubkey_algo, dek,
pubkey_nbits (pk->pubkey_algo, pk->pkey));
rc = pk_encrypt (pk->pubkey_algo, enc->data, frame, pk->pkey);
rc = pk_encrypt (pk->pubkey_algo, enc->data, frame, fp, pk->pkey);
gcry_mpi_release (frame);
if (rc)
log_error ("pubkey_encrypt failed: %s\n", gpg_strerror (rc) );

View File

@ -1161,6 +1161,18 @@ build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent)
/* iobuf_put (out,')'); iobuf_put (out,'\n'); */
/* (*indent)--; */
/* } */
/*
else if (sk->pubkey_algo == PUBKEY_ALGO_ECDSA && !sk->is_protected)
{
write_sexp_line (out, indent, "(ecdsa\n");
(*indent)++;
write_sexp_keyparm (out, indent, "c", sk->skey[0]); iobuf_put (out,'\n');
write_sexp_keyparm (out, indent, "q", sk->skey[6]); iobuf_put (out,'\n');
write_sexp_keyparm (out, indent, "d", sk->skey[7]);
iobuf_put (out,')'); iobuf_put (out,'\n');
(*indent)--;
}
*/
/* else if (is_ELGAMAL (sk->pubkey_algo) && !sk->is_protected) */
/* { */
/* write_sexp_line (out, indent, "(elg\n"); */

View File

@ -138,7 +138,10 @@ cache_public_key (PKT_public_key * pk)
return;
if (is_ELGAMAL (pk->pubkey_algo)
|| pk->pubkey_algo == PUBKEY_ALGO_DSA || is_RSA (pk->pubkey_algo))
|| pk->pubkey_algo == PUBKEY_ALGO_DSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH
|| is_RSA (pk->pubkey_algo))
{
keyid_from_pk (pk, keyid);
}

View File

@ -813,7 +813,7 @@ my_strusage( int level )
const char *p;
switch( level ) {
case 11: p = "gpg (GnuPG)";
case 11: p = "gpg (GnuPG) ecc";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
@ -857,7 +857,7 @@ my_strusage( int level )
case 34:
if (!pubkeys)
pubkeys = build_list (_("Pubkey: "), 0,
gcry_pk_algo_name,
openpgp_pk_algo_name,
openpgp_pk_test_algo );
p = pubkeys;
break;

View File

@ -42,6 +42,8 @@
#include "i18n.h"
#include "keyserver-internal.h"
#include "call-agent.h"
#include "pkglue.h"
#include "gcrypt.h"
/* The default algorithms. If you change them remember to change them
also in gpg.c:gpgconf_list. You should also check that the value
@ -49,10 +51,6 @@
#define DEFAULT_STD_ALGO GCRY_PK_RSA
#define DEFAULT_STD_KEYSIZE 2048
#define KEYGEN_FLAG_NO_PROTECTION 1
#define KEYGEN_FLAG_TRANSIENT_KEY 2
#define MAX_PREFS 30
enum para_name {
@ -1130,17 +1128,15 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
}
/* Common code for the key generation fucntion gen_xxx. */
static int
common_gen (const char *keyparms, int algo, const char *algoelem,
kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
int keygen_flags, char **cache_nonce_addr)
common_key_gen (const char *keyparms, int algo, const char *algoelem,
int keygen_flags, char **cache_nonce_addr, PKT_public_key **pk_out)
{
int err;
PACKET *pkt;
PKT_public_key *pk;
gcry_sexp_t s_key;
*pk_out = NULL;
err = agent_genkey (NULL, cache_nonce_addr, keyparms,
!!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), &s_key);
@ -1158,10 +1154,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
return err;
}
pk->timestamp = timestamp;
pk->version = 4;
if (expireval)
pk->expiredate = pk->timestamp + expireval;
pk->pubkey_algo = algo;
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
@ -1174,21 +1167,45 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
}
gcry_sexp_release (s_key);
pkt = xtrycalloc (1, sizeof *pkt);
if (!pkt)
{
err = gpg_error_from_syserror ();
free_public_key (pk);
return err;
}
pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
pkt->pkt.public_key = pk;
add_kbnode (pub_root, new_kbnode (pkt));
*pk_out = pk;
return 0;
}
/* Common code for the key generation fucntion gen_xxx. */
static int
common_gen (const char *keyparms, int algo, const char *algoelem,
kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
int keygen_flags, char **cache_nonce_addr)
{
PKT_public_key *pk;
int err;
err = common_key_gen( keyparms, algo, algoelem, keygen_flags, cache_nonce_addr, &pk );
if( !err ) {
PACKET *pkt;
pk->timestamp = timestamp;
if (expireval)
pk->expiredate = pk->timestamp + expireval;
pkt = xtrycalloc (1, sizeof *pkt);
if (!pkt)
{
err = gpg_error_from_syserror ();
free_public_key (pk);
return err;
}
pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
pkt->pkt.public_key = pk;
add_kbnode (pub_root, new_kbnode (pkt));
}
return err;
}
/*
* Generate an Elgamal key.
@ -1326,6 +1343,186 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
return err;
}
/* Returns allocated ECC key generation S-explression
call gcry_sexp_release ( out ) to free it.
*/
static int
delme__pk_ecc_build_sexp( int qbits, int algo, int is_long_term, gcry_sexp_t *out ) {
gcry_mpi_t kek_params;
char *kek_params_s;
int rc;
if( is_long_term && algo == PUBKEY_ALGO_ECDH )
kek_params = pk_ecdh_default_params_to_mpi( qbits );
else
kek_params = NULL;
if( kek_params ) {
kek_params_s = mpi2hex( kek_params );
mpi_release( kek_params );
}
rc = gcry_sexp_build (out, NULL,
algo == PUBKEY_ALGO_ECDSA ?
"(genkey(ecdsa(nbits %d)(qbits %d)))" :
"(genkey(ecdh(nbits %d)(qbits %d)(transient-key %d)(kek-params %s)))",
(int)qbits, (int)qbits, (int)(is_long_term==0), kek_params_s);
xfree( kek_params_s );
if (rc) {
log_debug("ec gen gcry_sexp_build failed: %s\n", gpg_strerror (rc));
return rc;
}
return 0;
}
static char *
pk_ecc_build_key_params( int qbits, int algo, int transient ) {
byte *kek_params = NULL;
size_t kek_params_size;
char nbitsstr[35];
char qbitsstr[35];
char *keyparms;
int n;
/* KEK parameters are only needed for long term key generation */
if( !transient && algo == PUBKEY_ALGO_ECDH )
kek_params = pk_ecdh_default_params( qbits, &kek_params_size );
else
kek_params = NULL;
snprintf (nbitsstr, sizeof nbitsstr, "%u", qbits);
snprintf (qbitsstr, sizeof qbitsstr, "%u", qbits);
if( algo == PUBKEY_ALGO_ECDSA || kek_params == NULL )
keyparms = xtryasprintf (
"(genkey(%s(nbits %zu:%s)(qbits %zu:%s)(transient-key 1:%d)))",
algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh",
strlen (nbitsstr), nbitsstr,
strlen (qbitsstr), qbitsstr,
transient );
else {
assert( kek_params != NULL );
keyparms = xtryasprintf (
"(genkey(ecdh(nbits %zu:%s)(qbits %zu:%s)(transient-key 1:%d)(kek-params %u:",
strlen (nbitsstr), nbitsstr,
strlen (qbitsstr), qbitsstr,
transient,
(unsigned)kek_params_size );
if( keyparms != NULL ) {
n = strlen(keyparms);
keyparms = xtryrealloc( keyparms, n + kek_params_size + 4 );
}
if( keyparms == NULL ) {
xfree( kek_params );
return NULL;
}
memcpy( keyparms+n, kek_params, kek_params_size );
xfree( kek_params );
memcpy( keyparms+n+kek_params_size, ")))", 4 );
}
return keyparms;
}
/* This common function is used in this file and also to generate ephemeral keys for ECDH.
* Caller must call free_public_key and free_secret_key */
int
pk_ecc_keypair_gen( PKT_public_key **pk_out, int algo, int keygen_flags, char **cache_nonce_addr, unsigned nbits) {
int err;
unsigned int qbits;
char *keyparms;
// PUBKEY_ALGO_ECDH, PUBKEY_ALGO_ECDSA
static const char * const ec_pub_params[2] = { "cqp", "cq" };
//static const char * const ec_priv_params[2] = { "cqpd", "cqd" };
assert( algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH );
assert( PUBKEY_ALGO_ECDSA == PUBKEY_ALGO_ECDH + 1 );
*pk_out = NULL;
if( pubkey_get_npkey (PUBKEY_ALGO_ECDSA) != 2 || pubkey_get_nskey (PUBKEY_ALGO_ECDSA) != 3 ||
pubkey_get_npkey (PUBKEY_ALGO_ECDH) != 3 || pubkey_get_nskey (PUBKEY_ALGO_ECDH) != 4 )
{
log_info(_("incompatible version of gcrypt library (expect named curve logic for ECC)\n") );
return GPG_ERR_EPROGMISMATCH;
}
if ( nbits != 256 && nbits != 384 && nbits != 521 )
{
log_info(_("keysize invalid; using 256 bits instead of passed in %d\n"), nbits );
}
/*
Figure out a q size based on the key size. See gen_dsa for more details.
Due to 8-bit rounding we may get 528 here instead of 521
*/
nbits = qbits = (nbits < 521 ? nbits : 521 );
keyparms = pk_ecc_build_key_params(qbits, algo, !!((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION)) );
if (!keyparms) {
err = gpg_error_from_syserror ();
log_error ("ec pk_ecc_build_key_params failed: %s\n", gpg_strerror (err) );
}
else
{
err = common_key_gen (keyparms, algo, ec_pub_params[algo-PUBKEY_ALGO_ECDH],
keygen_flags, cache_nonce_addr, pk_out);
xfree (keyparms);
}
#if 0
/* always allocase seckey_info for EC keys. TODO: is this needed? */
if( *pk_out ) {
struct seckey_info *ski;
(*pk_out)->seckey_info = ski = xtrycalloc (1, sizeof *ski);
if (!(*pk_out)->seckey_info) {
free_public_key(*pk_out);
*pk_out = NULL;
return gpg_error_from_syserror ();
}
ski->is_protected = 0;
ski->algo = 0;
}
#endif
return err;
}
/****************
* Generate an ECC OpenPGP key
*/
static gpg_error_t
gen_ecc (int algo, unsigned int nbits, KBNODE pub_root,
u32 timestamp, u32 expireval, int is_subkey,
int keygen_flags, char **cache_nonce_addr)
{
int rc;
PACKET *pkt;
PKT_public_key *pk;
rc = pk_ecc_keypair_gen( &pk, algo, keygen_flags, cache_nonce_addr, nbits );
if( rc )
return rc;
/* the rest is very similar to common_gen */
pk->timestamp = timestamp;
if (expireval)
pk->expiredate = pk->timestamp + expireval;
//assert( pk->seckey_info != NULL );
/// TODO: the new agent-based model doesn't return private portion here (the pkey array is allocated, but private MPIs are NULL, so this will cause a crash... )
///pk->seckey_info->csum = checksum_mpi ( pk->pkey[algo==PUBKEY_ALGO_ECDSA ? 2 : 3] ); /* corresponds to 'd' in 'cqd' or 'cqpd' */
pkt = xmalloc_clear(sizeof *pkt);
pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
pkt->pkt.public_key = pk;
add_kbnode(pub_root, new_kbnode( pkt ));
return 0;
}
/*
* Generate an RSA key.
@ -1557,6 +1754,8 @@ ask_algo (int addmode, int *r_subkey_algo, unsigned int *r_usage)
tty_printf (_(" (%d) RSA (set your own capabilities)\n"), 8 );
}
tty_printf (_(" (%d) ECDSA and ECDH\n"), 9 );
for(;;)
{
*r_usage = 0;
@ -1613,6 +1812,12 @@ ask_algo (int addmode, int *r_subkey_algo, unsigned int *r_usage)
*r_usage = ask_key_flags (algo, addmode);
break;
}
else if (algo == 9)
{
algo = PUBKEY_ALGO_ECDSA;
*r_subkey_algo = PUBKEY_ALGO_ECDH;
break;
}
else
tty_printf (_("Invalid selection.\n"));
}
@ -1657,13 +1862,20 @@ ask_keysize (int algo, unsigned int primary_keysize)
max=3072;
break;
case PUBKEY_ALGO_ECDSA:
case PUBKEY_ALGO_ECDH:
min=256;
def=256;
max=521;
break;
case PUBKEY_ALGO_RSA:
min=1024;
break;
}
tty_printf(_("%s keys may be between %u and %u bits long.\n"),
gcry_pk_algo_name (algo), min, max);
openpgp_pk_algo_name (algo), min, max);
for(;;)
{
@ -1682,7 +1894,7 @@ ask_keysize (int algo, unsigned int primary_keysize)
if(nbits<min || nbits>max)
tty_printf(_("%s keysizes must be in the range %u-%u\n"),
gcry_pk_algo_name (algo), min, max);
openpgp_pk_algo_name (algo), min, max);
else
break;
}
@ -1692,10 +1904,18 @@ ask_keysize (int algo, unsigned int primary_keysize)
leave:
if( algo == PUBKEY_ALGO_DSA && (nbits % 64) )
{
nbits = ((nbits + 63) / 64) * 64;
if (!autocomp)
tty_printf(_("rounded up to %u bits\n"), nbits );
if( !(algo == PUBKEY_ALGO_ECDSA && nbits==521) ) {
nbits = ((nbits + 63) / 64) * 64;
if (!autocomp)
tty_printf(_("rounded up to %u bits\n"), nbits );
}
}
else if( algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA ) {
if( nbits != 256 && nbits != 384 && nbits != 521 ) {
nbits = min;
tty_printf(_("unsupported ECDH value, corrected to the minimum %u bits\n"), nbits );
}
}
else if( (nbits % 32) )
{
nbits = ((nbits + 31) / 32) * 32;
@ -2185,6 +2405,9 @@ do_create (int algo, unsigned int nbits, KBNODE pub_root,
else if (algo == PUBKEY_ALGO_DSA)
err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey,
keygen_flags, cache_nonce_addr);
else if( algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH )
err = gen_ecc (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
keygen_flags, cache_nonce_addr);
else if (algo == PUBKEY_ALGO_RSA)
err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
keygen_flags, cache_nonce_addr);

View File

@ -57,6 +57,8 @@ pubkey_letter( int algo )
case PUBKEY_ALGO_ELGAMAL_E: return 'g';
case PUBKEY_ALGO_ELGAMAL: return 'G' ;
case PUBKEY_ALGO_DSA: return 'D' ;
case PUBKEY_ALGO_ECDSA: return 'E' ; // ECC DSA (sign only)
case PUBKEY_ALGO_ECDH: return 'e' ; // ECC DH (encrypt only)
default: return '?';
}
}
@ -74,6 +76,8 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
unsigned int nbits;
size_t nbytes;
int npkey = pubkey_get_npkey (pk->pubkey_algo);
/* name OID, MPI of public point, [for ECDH only: KEK params] */
enum gcry_mpi_format ecc_pub_format[3] = {GCRYMPI_FMT_USG, GCRYMPI_FMT_PGP, GCRYMPI_FMT_USG};
/* Two extra bytes for the expiration date in v3 */
if(pk->version<4)
@ -90,11 +94,13 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
{
for(i=0; i < npkey; i++ )
{
if (gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, pk->pkey[i]))
const enum gcry_mpi_format fmt =
((pk->pubkey_algo==PUBKEY_ALGO_ECDSA || pk->pubkey_algo==PUBKEY_ALGO_ECDH) ? ecc_pub_format[i] : GCRYMPI_FMT_PGP);
if (gcry_mpi_print (fmt, NULL, 0, &nbytes, pk->pkey[i]))
BUG ();
pp[i] = xmalloc (nbytes);
if (gcry_mpi_print (GCRYMPI_FMT_PGP, pp[i], nbytes,
&nbytes, pk->pkey[i]))
if (gcry_mpi_print (fmt, pp[i], nbytes, &nbytes, pk->pkey[i]))
BUG ();
nn[i] = nbytes;
n += nn[i];
@ -712,6 +718,20 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
pk->pkey[0], pk->pkey[1]);
break;
case PUBKEY_ALGO_ECDSA:
case PUBKEY_ALGO_ECDH:
err = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecc(c%m)(q%m)))",
pk->pkey[0], pk->pkey[1]);
break;
/*
case PUBKEY_ALGO_ECDH:
err = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecdh(c%m)(q%m)(p%m)))",
pk->pkey[0], pk->pkey[1], pk->pkey[2]);
break;
*/
default:
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
break;

View File

@ -93,11 +93,12 @@ int map_cipher_openpgp_to_gcry (int algo);
int openpgp_cipher_blocklen (int algo);
int openpgp_cipher_test_algo( int algo );
const char *openpgp_cipher_algo_name (int algo);
int map_pk_openpgp_to_gcry (int algo);
int openpgp_pk_test_algo( int algo );
int openpgp_pk_test_algo2 ( int algo, unsigned int use );
int openpgp_pk_algo_usage ( int algo );
const char *openpgp_pk_algo_name (int algo);
int openpgp_md_test_algo( int algo );
const char *openpgp_pk_algo_name (int algo);
const char *openpgp_md_algo_name (int algo);
#ifdef USE_IDEA
@ -157,6 +158,10 @@ int pubkey_get_nsig( int algo );
int pubkey_get_nenc( int algo );
unsigned int pubkey_nbits( int algo, gcry_mpi_t *pkey );
int mpi_print (estream_t stream, gcry_mpi_t a, int mode);
int iobuf_write_size_body_mpi (iobuf_t out, gcry_mpi_t a);
int iobuf_read_size_body(iobuf_t inp, byte *body, int body_max_size, int pktlen, gcry_mpi_t *out);
int ecdsa_qbits_from_Q( int qbits );
/*-- status.c --*/
void set_status_fd ( int fd );
@ -251,6 +256,10 @@ gpg_error_t generate_card_subkeypair (kbnode_t pub_keyblock,
int save_unprotected_key_to_card (PKT_public_key *sk, int keyno);
#endif
#define KEYGEN_FLAG_NO_PROTECTION 1
#define KEYGEN_FLAG_TRANSIENT_KEY 2
int pk_ecc_keypair_gen( PKT_public_key **pk_out, int algo, int keygen_flags, char **cache_nonce_addr, unsigned nbits);
/*-- openfile.c --*/
int overwrite_filep( const char *fname );
char *make_outfile_name( const char *iname );
@ -261,7 +270,7 @@ void try_make_homedir( const char *fname );
/*-- seskey.c --*/
void make_session_key( DEK *dek );
gcry_mpi_t encode_session_key( DEK *dek, unsigned nbits );
gcry_mpi_t encode_session_key( int openpgp_pk_algo, DEK *dek, unsigned nbits );
gcry_mpi_t encode_md_value (PKT_public_key *pk,
gcry_md_hd_t md, int hash_algo );

View File

@ -384,6 +384,8 @@ proc_pubkey_enc( CTX c, PACKET *pkt )
}
else if( is_ELGAMAL(enc->pubkey_algo)
|| enc->pubkey_algo == PUBKEY_ALGO_DSA
|| enc->pubkey_algo == PUBKEY_ALGO_ECDSA
|| enc->pubkey_algo == PUBKEY_ALGO_ECDH
|| is_RSA(enc->pubkey_algo)
|| enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL) {
/* Note that we also allow type 20 Elgamal keys for decryption.
@ -450,7 +452,7 @@ print_pkenc_list( struct kidlist_item *list, int failed )
if ( !failed && list->reason )
continue;
algstr = gcry_pk_algo_name ( list->pubkey_algo );
algstr = openpgp_pk_algo_name ( list->pubkey_algo );
pk = xmalloc_clear( sizeof *pk );
if( !algstr )
@ -1616,7 +1618,7 @@ check_sig_and_print( CTX c, KBNODE node )
/* (Indendation below not yet changed to GNU style.) */
astr = gcry_pk_algo_name ( sig->pubkey_algo );
astr = openpgp_pk_algo_name ( sig->pubkey_algo );
if(keystrlen()>8)
{
log_info(_("Signature made %s\n"),asctimestamp(sig->timestamp));

View File

@ -64,6 +64,7 @@
#include "call-agent.h"
#include "i18n.h"
#include <assert.h>
static int
string_count_chr (const char *string, int c)
@ -294,7 +295,7 @@ print_pubkey_algo_note( int algo )
{
warn=1;
log_info (_("WARNING: using experimental public key algorithm %s\n"),
gcry_pk_algo_name (algo));
openpgp_cipher_algo_name (algo));
}
}
else if (algo == 20)
@ -365,6 +366,12 @@ map_cipher_gcry_to_openpgp (int algo)
}
}
int
map_pk_openpgp_to_gcry (int algo)
{
return (algo==PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : (algo==PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo));
}
/* Return the block length of an OpenPGP cipher algorithm. */
int
@ -409,7 +416,13 @@ openpgp_cipher_test_algo( int algo )
const char *
openpgp_cipher_algo_name (int algo)
{
return gnupg_cipher_algo_name (map_cipher_openpgp_to_gcry (algo));
return gcry_cipher_algo_name (map_cipher_openpgp_to_gcry (algo));
}
const char *
openpgp_pk_algo_name (int algo)
{
return gcry_pk_algo_name ( algo == PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : ( algo == PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo ) );
}
int
@ -424,7 +437,13 @@ openpgp_pk_test_algo( int algo )
if (algo < 0 || algo > 110)
return gpg_error (GPG_ERR_PUBKEY_ALGO);
return gcry_pk_test_algo (algo);
if( algo == PUBKEY_ALGO_ECDSA )
algo = GCRY_PK_ECDSA;
else if( algo == PUBKEY_ALGO_ECDH )
algo = GCRY_PK_ECDH;
return gcry_pk_test_algo ( algo );
}
int
@ -442,7 +461,12 @@ openpgp_pk_test_algo2( int algo, unsigned int use )
if (algo < 0 || algo > 110)
return gpg_error (GPG_ERR_PUBKEY_ALGO);
return gcry_pk_algo_info (algo, GCRYCTL_TEST_ALGO, NULL, &use_buf);
if( algo == PUBKEY_ALGO_ECDSA )
algo = GCRY_PK_ECDSA;
else if( algo == PUBKEY_ALGO_ECDH )
algo = GCRY_PK_ECDH;
return gcry_pk_algo_info ( algo, GCRYCTL_TEST_ALGO, NULL, &use_buf);
}
int
@ -457,6 +481,7 @@ openpgp_pk_algo_usage ( int algo )
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH);
break;
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_ECDH:
use = PUBKEY_USAGE_ENC;
break;
case PUBKEY_ALGO_RSA_S:
@ -472,6 +497,8 @@ openpgp_pk_algo_usage ( int algo )
case PUBKEY_ALGO_DSA:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
break;
case PUBKEY_ALGO_ECDSA:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
default:
break;
}
@ -480,7 +507,7 @@ openpgp_pk_algo_usage ( int algo )
/* Map the OpenPGP pubkey algorithm whose ID is contained in ALGO to a
string representation of the algorithm name. For unknown algorithm
IDs this function returns "?". */
IDs this function returns "?".
const char *
openpgp_pk_algo_name (int algo)
{
@ -498,6 +525,7 @@ openpgp_pk_algo_name (int algo)
default: return "?";
}
}
*/
int
@ -1348,6 +1376,10 @@ pubkey_get_npkey( int algo )
if (algo == GCRY_PK_ELG_E)
algo = GCRY_PK_ELG;
else if (algo == PUBKEY_ALGO_ECDSA)
algo = GCRY_PK_ECDSA;
else if (algo == PUBKEY_ALGO_ECDH)
algo = GCRY_PK_ECDH;
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &n))
n = 0;
return n;
@ -1361,6 +1393,10 @@ pubkey_get_nskey( int algo )
if (algo == GCRY_PK_ELG_E)
algo = GCRY_PK_ELG;
else if (algo == PUBKEY_ALGO_ECDSA)
algo = GCRY_PK_ECDSA;
else if (algo == PUBKEY_ALGO_ECDH)
algo = GCRY_PK_ECDH;
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &n ))
n = 0;
return n;
@ -1374,6 +1410,10 @@ pubkey_get_nsig( int algo )
if (algo == GCRY_PK_ELG_E)
algo = GCRY_PK_ELG;
else if (algo == PUBKEY_ALGO_ECDSA)
algo = GCRY_PK_ECDSA;
else if (algo == PUBKEY_ALGO_ECDH)
algo = GCRY_PK_ECDH;
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSIGN, NULL, &n))
n = 0;
return n;
@ -1387,6 +1427,10 @@ pubkey_get_nenc( int algo )
if (algo == GCRY_PK_ELG_E)
algo = GCRY_PK_ELG;
else if (algo == PUBKEY_ALGO_ECDSA)
algo = GCRY_PK_ECDSA;
else if (algo == PUBKEY_ALGO_ECDH)
algo = GCRY_PK_ECDH;
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NENCR, NULL, &n ))
n = 0;
return n;
@ -1400,6 +1444,8 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
int rc, nbits;
gcry_sexp_t sexp;
assert( algo != GCRY_PK_ECDSA && algo != GCRY_PK_ECDH );
if( algo == GCRY_PK_DSA ) {
rc = gcry_sexp_build ( &sexp, NULL,
"(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
@ -1415,6 +1461,11 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
"(public-key(rsa(n%m)(e%m)))",
key[0], key[1] );
}
else if( algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH ) {
rc = gcry_sexp_build ( &sexp, NULL,
"(public-key(ecc(c%m)(q%m)))",
key[0], key[1] /* not affecting the size calculation, so use 'ecc' == 'ecdsa' */ );
}
else
return 0;
@ -1455,3 +1506,89 @@ mpi_print (estream_t fp, gcry_mpi_t a, int mode)
return n;
}
/*
* Write a special size+body mpi a, to OUT. The format of the content of the MPI is
* one byte LEN, following by LEN bytes
*/
int
iobuf_write_size_body_mpi (iobuf_t out, gcry_mpi_t a)
{
byte buffer[256]; /* Fixed buffer for a public parameter, max possible */
size_t nbytes = (mpi_get_nbits (a)+7)/8;
int rc;
if( nbytes > sizeof(buffer) ) {
log_error("mpi with size+body is too large (%u bytes)\n", nbytes);
return gpg_error (GPG_ERR_TOO_LARGE);
}
rc = gcry_mpi_print (GCRYMPI_FMT_USG, buffer, sizeof(buffer), &nbytes, a);
if( rc ) {
log_error("Failed to exported size+body mpi\n");
return rc;
}
if( nbytes < 2 || buffer[0] != nbytes-1 ) {
if( nbytes > 2 )
log_error("Internal size mismatch in mpi size+body: %02x != %02x (other bytes: %02x %02x ... %02x %02x)\n",
buffer[0], nbytes-1, buffer[1], buffer[2], buffer[nbytes-2], buffer[nbytes-1]);
else
log_error("Internal size mismatch in mpi size+body: only %d bytes\n", nbytes );
return gpg_error (GPG_ERR_INV_DATA);
}
return iobuf_write( out, buffer, nbytes );
}
/*
* Read a special size+body from inp into body[body_max_size] and return it in a buffer and as MPI.
* On success the number of consumed bytes will body[0]+1.
* The format of the content of the returned MPI is one byte LEN, following by LEN bytes.
* Caller is expected to pre-allocate fixed-size 255 byte buffer (or smaller when appropriate).
*/
int
iobuf_read_size_body( iobuf_t inp, byte *body, int body_max_size, int pktlen, gcry_mpi_t *out ) {
unsigned n;
int rc;
gcry_mpi_t result;
*out = NULL;
if( (n = iobuf_readbyte(inp)) == -1 ) {
return G10ERR_INVALID_PACKET;
}
if( n >= body_max_size || n < 2) {
log_error("invalid size+body field\n");
return G10ERR_INVALID_PACKET;
}
body[0] = n;
if( (n = iobuf_read(inp, body+1, n)) == -1 ) {
log_error("invalid size+body field\n");
return G10ERR_INVALID_PACKET;
}
if( n+1 > pktlen ) {
log_error("size+body field is larger than the packet\n");
return G10ERR_INVALID_PACKET;
}
rc = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, body, n+1, NULL);
if (rc)
log_fatal ("mpi_scan failed: %s\n", gpg_strerror (rc));
*out = result;
return rc;
}
/* pkey[1] or skey[1] is Q for ECDSA, which is an uncompressed point, i.e. 04 <x> <y> */
int ecdsa_qbits_from_Q( int qbits ) {
if( qbits%8>3 ) {
log_error(_("ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"));
return 0;
}
qbits -= qbits%8;
qbits /= 2;
return qbits;
}

View File

@ -939,20 +939,40 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
}
else
{
for (i = 0; i < ndata; i++)
{
n = pktlen;
k->data[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (list_mode)
{
es_fprintf (listfp, "\tdata: ");
mpi_print (listfp, k->data[i], mpi_print_mode);
es_putc ('\n', listfp);
}
if (!k->data[i])
rc = gpg_error (GPG_ERR_INV_PACKET);
}
if( k->pubkey_algo != PUBKEY_ALGO_ECDH ) {
for (i = 0; i < ndata; i++)
{
n = pktlen;
k->data[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (list_mode)
{
es_fprintf (listfp, "\tdata: ");
mpi_print (listfp, k->data[i], mpi_print_mode);
es_putc ('\n', listfp);
}
if (!k->data[i])
rc = gpg_error (GPG_ERR_INV_PACKET);
}
}
else
{
byte encr_buf[255];
assert( ndata == 2 );
n = pktlen; k->data[0] = mpi_read(inp, &n, 0); pktlen -=n;
rc = iobuf_read_size_body( inp, encr_buf, sizeof(encr_buf), pktlen, k->data+1 );
if( rc )
goto leave;
if( list_mode ) {
es_fprintf (listfp, "\tdata: ");
mpi_print(listfp, k->data[0], mpi_print_mode );
es_putc ('\n', listfp);
es_fprintf (listfp, "\tdata: [% 3d bytes] ", encr_buf[0]);
mpi_print(listfp, k->data[1], mpi_print_mode );
es_putc ('\n', listfp);
}
pktlen -= (encr_buf[0]+1);
}
}
leave:
@ -1926,20 +1946,61 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
else
{
/* Fill in public key parameters. */
for (i = 0; i < npkey; i++)
{
n = pktlen;
pk->pkey[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (list_mode)
{
es_fprintf (listfp, "\tpkey[%d]: ", i);
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
es_putc ('\n', listfp);
if( algorithm != PUBKEY_ALGO_ECDSA && algorithm != PUBKEY_ALGO_ECDH ) {
for (i = 0; i < npkey; i++)
{
n = pktlen;
pk->pkey[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (list_mode)
{
es_fprintf (listfp, "\tpkey[%d]: ", i);
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
es_putc ('\n', listfp);
}
if (!pk->pkey[i])
err = gpg_error (GPG_ERR_INV_PACKET);
}
}
else {
/* note that the code in this function ignores the errors */
byte name_oid[256];
err = iobuf_read_size_body( inp, name_oid, sizeof(name_oid), pktlen, pk->pkey+0 );
if( err )
goto leave;
n = name_oid[0];
if( list_mode )
es_fprintf (listfp, "\tpkey[0]: curve OID [%d] ...%02x %02x\n",
n, name_oid[1+n-2], name_oid[1+n-1] );
pktlen -= (n+1);
/* set item [1], which corresponds to the public key; these two fields are all we need to uniquely define the key */
// log_debug("Parsing ecc public key in the public packet, pktlen=%lu\n", pktlen);
n = pktlen; pk->pkey[1] = mpi_read( inp, &n, 0 ); pktlen -=n;
if( pk->pkey[1]==NULL )
err = gpg_error(G10ERR_INVALID_PACKET);
else if( list_mode ) {
es_fprintf (listfp, "\tpkey[1]: ");
mpi_print(listfp, pk->pkey[1], mpi_print_mode);
es_putc ('\n', listfp);
}
if (!pk->pkey[i])
err = gpg_error (GPG_ERR_INV_PACKET);
}
/* One more field for ECDH */
if( algorithm == PUBKEY_ALGO_ECDH ) {
#define kek_params name_oid
err = iobuf_read_size_body( inp, kek_params, sizeof(kek_params), pktlen, pk->pkey+2 );
if( err )
goto leave;
n = kek_params[0];
if( kek_params[1] != 1 ) {
log_error("invalid ecdh KEK parameters field type in private key: understand type 1, but found 0x%02x\n", kek_params[1]);
err = gpg_error(G10ERR_INVALID_PACKET);
goto leave;
}
if( list_mode )
es_fprintf (listfp, "\tpkey[2]: KEK params type=01 hash:%d sym-algo:%d\n", kek_params[1+n-2], kek_params[1+n-1] );
pktlen -= (n+1);
#undef kek_params
}
}
if (err)
goto leave;
}

View File

@ -323,7 +323,7 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
{
char *uid;
size_t uidlen;
const char *algo_name = gcry_pk_algo_name ( pk->pubkey_algo );
const char *algo_name = openpgp_pk_algo_name ( pk->pubkey_algo );
const char *timestr;
char *maink;
@ -585,7 +585,7 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
if ( !get_pubkey( pk, keyid ) )
{
const char *s = gcry_pk_algo_name ( pk->pubkey_algo );
const char *s = openpgp_pk_algo_name ( pk->pubkey_algo );
tty_printf (_("%u-bit %s key, ID %s, created %s"),
nbits_from_pk( pk ), s?s:"?", keystr(keyid),
@ -690,7 +690,7 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
char *desc;
const char *prompt;
algo_name = gcry_pk_algo_name (pk->pubkey_algo);
algo_name = openpgp_pk_algo_name (pk->pubkey_algo);
timestr = strtimestamp (pk->timestamp);
uid = get_user_id (pk->keyid, &uidlen);

View File

@ -27,9 +27,10 @@
#include "gpg.h"
#include "util.h"
#include "pkglue.h"
#include "main.h"
static gcry_mpi_t
gcry_mpi_t
mpi_from_sexp (gcry_sexp_t sexp, const char * item)
{
gcry_sexp_t list;
@ -44,6 +45,70 @@ mpi_from_sexp (gcry_sexp_t sexp, const char * item)
}
/****************
* Emulate our old PK interface here - sometime in the future we might
* change the internal design to directly fit to libgcrypt.
*/
int
pk_sign (int algo, gcry_mpi_t * data, gcry_mpi_t hash, gcry_mpi_t * skey)
{
gcry_sexp_t s_sig, s_hash, s_skey;
int rc;
int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
/* make a sexp from skey */
if (gcry_pkalgo == GCRY_PK_DSA)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
skey[0], skey[1], skey[2], skey[3], skey[4]);
}
else if (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
skey[0], skey[1], skey[2], skey[3], skey[4],
skey[5]);
}
else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
skey[0], skey[1], skey[2], skey[3]);
}
else if (gcry_pkalgo == GCRY_PK_ECDSA)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(ecdsa(c%m)(q%m)(d%m)))",
skey[0], skey[1], skey[2] );
}
else
return GPG_ERR_PUBKEY_ALGO;
if (rc)
BUG ();
/* put hash into a S-Exp s_hash */
if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
BUG ();
rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
gcry_sexp_release (s_hash);
gcry_sexp_release (s_skey);
if (rc)
;
else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_S)
data[0] = mpi_from_sexp (s_sig, "s");
else
{
data[0] = mpi_from_sexp (s_sig, "r");
data[1] = mpi_from_sexp (s_sig, "s");
}
gcry_sexp_release (s_sig);
return rc;
}
/****************
* Emulate our old PK interface here - sometime in the future we might
@ -54,25 +119,31 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
{
gcry_sexp_t s_sig, s_hash, s_pkey;
int rc;
const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
/* make a sexp from pkey */
if (algo == GCRY_PK_DSA)
if (gcry_pkalgo == GCRY_PK_DSA)
{
rc = gcry_sexp_build (&s_pkey, NULL,
"(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
pkey[0], pkey[1], pkey[2], pkey[3]);
}
else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
{
rc = gcry_sexp_build (&s_pkey, NULL,
"(public-key(elg(p%m)(g%m)(y%m)))",
pkey[0], pkey[1], pkey[2]);
}
else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_S)
else if (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S)
{
rc = gcry_sexp_build (&s_pkey, NULL,
"(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
}
else if (gcry_pkalgo == GCRY_PK_ECDSA) /* same as GCRY_PK_ECDH */
{
rc = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecdsa(c%m)(q%m)))", pkey[0], pkey[1]);
}
else
return GPG_ERR_PUBKEY_ALGO;
@ -85,7 +156,7 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
/* Put data into a S-Exp s_sig. */
s_sig = NULL;
if (algo == GCRY_PK_DSA)
if (gcry_pkalgo == GCRY_PK_DSA)
{
if (!data[0] || !data[1])
rc = gpg_error (GPG_ERR_BAD_MPI);
@ -93,7 +164,15 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
rc = gcry_sexp_build (&s_sig, NULL,
"(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
}
else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
else if (gcry_pkalgo == GCRY_PK_ECDSA)
{
if (!data[0] || !data[1])
rc = gpg_error (GPG_ERR_BAD_MPI);
else
rc = gcry_sexp_build (&s_sig, NULL,
"(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
}
else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
{
if (!data[0] || !data[1])
rc = gpg_error (GPG_ERR_BAD_MPI);
@ -101,7 +180,7 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
rc = gcry_sexp_build (&s_sig, NULL,
"(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
}
else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_S)
else if (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S)
{
if (!data[0])
rc = gpg_error (GPG_ERR_BAD_MPI);
@ -128,7 +207,7 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
* change the internal design to directly fit to libgcrypt.
*/
int
pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t * pkey)
{
gcry_sexp_t s_ciph, s_data, s_pkey;
int rc;
@ -146,6 +225,10 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
"(public-key(rsa(n%m)(e%m)))",
pkey[0], pkey[1]);
}
else if (algo == PUBKEY_ALGO_ECDH)
{
return pk_ecdh_encrypt( resarr, pk_fp, data, pkey );
}
else
return GPG_ERR_PUBKEY_ALGO;
@ -166,7 +249,7 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
else
{ /* add better error handling or make gnupg use S-Exp directly */
resarr[0] = mpi_from_sexp (s_ciph, "a");
if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E)
if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E && algo != PUBKEY_ALGO_ECDH)
resarr[1] = mpi_from_sexp (s_ciph, "b");
}
@ -181,7 +264,7 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
* change the internal design to directly fit to libgcrypt.
*/
int
pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
pk_decrypt (int algo, gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t * data,
gcry_mpi_t * skey)
{
gcry_sexp_t s_skey, s_data, s_plain;
@ -202,6 +285,9 @@ pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
skey[0], skey[1], skey[2], skey[3], skey[4],
skey[5]);
}
else if( algo == PUBKEY_ALGO_ECDH ) {
return pk_ecdh_decrypt( result, sk_fp, data, skey );
}
else
return GPG_ERR_PUBKEY_ALGO;
@ -244,3 +330,48 @@ pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
return 0;
}
/* Check whether SKEY is a suitable secret key. */
int
pk_check_secret_key (int algo, gcry_mpi_t *skey)
{
gcry_sexp_t s_skey;
int rc;
const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
if (gcry_pkalgo == GCRY_PK_DSA)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
skey[0], skey[1], skey[2], skey[3], skey[4]);
}
else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
skey[0], skey[1], skey[2], skey[3]);
}
else if (gcry_pkalgo == GCRY_PK_RSA
|| gcry_pkalgo == GCRY_PK_RSA_S || gcry_pkalgo == GCRY_PK_RSA_E)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
skey[0], skey[1], skey[2], skey[3], skey[4],
skey[5]);
}
else if (gcry_pkalgo == GCRY_PK_ECDSA || gcry_pkalgo == GCRY_PK_ECDH)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(ecdsa(c%m)(q%m)(d%m)))",
skey[0], skey[1], skey[2] );
}
else
return GPG_ERR_PUBKEY_ALGO;
if (!rc)
{
rc = gcry_pk_testkey (s_skey);
gcry_sexp_release (s_skey);
}
return rc;
}

View File

@ -20,13 +20,23 @@
#ifndef GNUPG_G10_PKGLUE_H
#define GNUPG_G10_PKGLUE_H
gcry_mpi_t mpi_from_sexp (gcry_sexp_t sexp, const char * item);
int pk_sign (int algo, gcry_mpi_t *data, gcry_mpi_t hash,
gcry_mpi_t *skey);
int pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data,
gcry_mpi_t *pkey);
int pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
const byte fp[MAX_FINGERPRINT_LEN],
gcry_mpi_t *pkey);
int pk_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
int pk_decrypt (int algo, gcry_mpi_t *result, const byte fp[MAX_FINGERPRINT_LEN], gcry_mpi_t *data,
gcry_mpi_t *skey);
int pk_check_secret_key (int algo, gcry_mpi_t *skey);
int pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t * pkey);
int pk_ecdh_decrypt (gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t *data, gcry_mpi_t * skey);
gcry_mpi_t pk_ecdh_default_params_to_mpi( int qbits );
byte *pk_ecdh_default_params( int qbits, size_t *sizeout );
#endif /*GNUPG_G10_PKGLUE_H*/

View File

@ -145,6 +145,8 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
gcry_sexp_t s_data;
char *desc;
char *keygrip;
byte fp[MAX_FINGERPRINT_LEN];
size_t fpn;
/* Get the keygrip. */
err = hexkeygrip_from_pk (sk, &keygrip);
@ -174,9 +176,12 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
if (err)
goto leave;
fingerprint_from_pk( sk, fp, &fpn );
assert( fpn == 20 );
/* Decrypt. */
desc = gpg_format_keydesc (sk, 0, 1);
err = agent_pkdecrypt (NULL, keygrip, desc, s_data, &frame, &nframe);
err = agent_pkdecrypt (NULL, keygrip, desc, s_data, fp, &frame, &nframe);
xfree (desc);
gcry_sexp_release (s_data);
if (err)
@ -202,28 +207,41 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
if (DBG_CIPHER)
log_printhex ("DEK frame:", frame, nframe);
n = 0;
if (!card)
{
if (n + 7 > nframe)
{
err = gpg_error (G10ERR_WRONG_SECKEY);
goto leave;
}
if (frame[n] == 1 && frame[nframe - 1] == 2)
{
log_info (_("old encoding of the DEK is not supported\n"));
err = gpg_error (G10ERR_CIPHER_ALGO);
goto leave;
}
if (frame[n] != 2) /* Something went wrong. */
{
err = gpg_error (G10ERR_WRONG_SECKEY);
goto leave;
}
for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */
;
n++; /* Skip the zero byte. */
if( sk->pubkey_algo != PUBKEY_ALGO_ECDH ) {
if (!card)
{
if (n + 7 > nframe)
{
err = gpg_error (G10ERR_WRONG_SECKEY);
goto leave;
}
if (frame[n] == 1 && frame[nframe - 1] == 2)
{
log_info (_("old encoding of the DEK is not supported\n"));
err = gpg_error (G10ERR_CIPHER_ALGO);
goto leave;
}
if (frame[n] != 2) /* Something went wrong. */
{
err = gpg_error (G10ERR_WRONG_SECKEY);
goto leave;
}
for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */
;
n++; /* Skip the zero byte. */
}
}
else {
/* Allow double padding for the benefit of DEK size concealment.
* Higher than this is wasteful.
*/
if( frame[nframe-1] > 8*2 || nframe <= 8 ) {
err = G10ERR_WRONG_SECKEY; goto leave;
}
nframe -= frame[nframe-1]; /* remove padding */
assert( n==0 ); /* used just bellow */
}
if (n + 4 > nframe)
{

View File

@ -27,6 +27,7 @@
#include "gpg.h"
#include "util.h"
#include "cipher.h"
#include "options.h"
#include "main.h"
#include "i18n.h"
@ -73,15 +74,48 @@ make_session_key( DEK *dek )
* returns: A mpi with the session key (caller must free)
*/
gcry_mpi_t
encode_session_key (DEK *dek, unsigned int nbits)
encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
{
size_t nframe = (nbits+7) / 8;
byte *p;
byte *frame;
int i,n;
u16 csum;
u16 csum = 0;
gcry_mpi_t a;
if( DBG_CIPHER )
log_debug("encode_session_key: encoding %d byte DEK", dek->keylen);
for( p = dek->key, i=0; i < dek->keylen; i++ )
csum += *p++;
/* Shortcut for ECDH. It's padding is minimal to simply make the output be a multiple of 8 bytes. */
if( openpgp_pk_algo == PUBKEY_ALGO_ECDH ) {
/* pad to 8 byte granulatiry; the padding byte is the number of padded bytes.
* A DEK(k bytes) CSUM(2 bytes) 0x 0x 0x 0x ... 0x
* +---- x times ---+
*/
nframe = ( 1 + dek->keylen + 2 /* the value so far is always odd */ + 7 ) & (~7);
assert( !(nframe%8) && nframe > 1 + dek->keylen + 2 ); /* alg+key+csum fit and the size is congruent to 8 */
frame = xmalloc_secure( nframe );
n = 0;
frame[n++] = dek->algo;
memcpy( frame+n, dek->key, dek->keylen ); n += dek->keylen;
frame[n++] = csum >>8;
frame[n++] = csum;
i = nframe - n; /* number padded bytes */
memset( frame+n, i, i );/* use it as the value of each padded byte */
assert( n+i == nframe );
if( DBG_CIPHER )
log_debug("encode_session_key: [%d] %02x %02x %02x ... %02x %02x %02x", nframe, frame[0],frame[1],frame[2], frame[nframe-3],frame[nframe-2],frame[nframe-1]);
if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, nframe, &nframe))
BUG();
xfree(frame);
return a;
}
/* The current limitation is that we can only use a session key
* whose length is a multiple of BITS_PER_MPI_LIMB
* I think we can live with that.
@ -103,9 +137,6 @@ encode_session_key (DEK *dek, unsigned int nbits)
* cipher algorithm (20 is used with blowfish160).
* CSUM is the 16 bit checksum over the DEK
*/
csum = 0;
for( p = dek->key, i=0; i < dek->keylen; i++ )
csum += *p++;
frame = xmalloc_secure( nframe );
n = 0;
@ -161,8 +192,8 @@ do_encode_md( gcry_md_hd_t md, int algo, size_t len, unsigned nbits,
gcry_mpi_t a;
if( len + asnlen + 4 > nframe )
log_bug("can't encode a %d bit MD into a %d bits frame\n",
(int)(len*8), (int)nbits);
log_bug("can't encode a %d bit MD into a %d bits frame, algo=%d\n",
(int)(len*8), (int)nbits, algo);
/* We encode the MD in this way:
*
@ -209,16 +240,23 @@ gcry_mpi_t
encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
{
gcry_mpi_t frame;
int gcry_pkalgo;
assert (hash_algo);
assert (pk);
if (pk->pubkey_algo == GCRY_PK_DSA)
gcry_pkalgo = map_pk_openpgp_to_gcry( pk->pubkey_algo );
if (gcry_pkalgo == GCRY_PK_DSA || gcry_pkalgo == GCRY_PK_ECDSA )
{
/* It's a DSA signature, so find out the size of q. */
size_t qbytes = gcry_mpi_get_nbits (pk->pkey[1]);
/* pkey[1] is Q for ECDSA, which is an uncompressed point, i.e. 04 <x> <y> */
if( gcry_pkalgo==GCRY_PK_ECDSA )
qbytes = ecdsa_qbits_from_Q( qbytes );
/* Make sure it is a multiple of 8 bits. */
if(qbytes%8)
@ -236,7 +274,8 @@ encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
DSA. ;) */
if (qbytes < 160)
{
log_error (_("DSA key %s uses an unsafe (%zu bit) hash\n"),
log_error (_("%s key %s uses an unsafe (%zu bit) hash\n"),
gcry_pk_algo_name( gcry_pkalgo ),
keystr_from_pk (pk), qbytes);
return NULL;
}
@ -245,10 +284,16 @@ encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
/* Check if we're too short. Too long is safe as we'll
automatically left-truncate. */
if (gcry_md_get_algo_dlen (hash_algo) < qbytes)
/* This checks would require the use of SHA512 with ECDSA 512. I think this is overkill to fail in this case.
* Therefore, relax the check, but only for ECDSA keys. We may need to adjust it later for general case.
* ( Note that the check will never pass for ECDSA 521 anyway as the only hash that intended to match it is SHA 512, but 512 < 521 ).
*/
//if (gcry_md_get_algo_dlen (hash_algo) < qbytes )
if (gcry_md_get_algo_dlen (hash_algo) < ((gcry_pkalgo==GCRY_PK_ECDSA && qbytes>(521)/8) ? 512/8 : qbytes) )
{
log_error (_("DSA key %s requires a %zu bit or larger hash\n"),
keystr_from_pk(pk), qbytes*8);
log_error (_("%s key %s requires a %zu bit or larger hash, used hash-algo=%d\n"),
gcry_pk_algo_name( gcry_pkalgo ),
keystr_from_pk(pk), qbytes*8, hash_algo);
return NULL;
}

View File

@ -227,21 +227,6 @@ hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig)
}
}
static gcry_mpi_t
mpi_from_sexp (gcry_sexp_t sexp, const char * item)
{
gcry_sexp_t list;
gcry_mpi_t data;
list = gcry_sexp_find_token (sexp, item, 0);
assert (list);
data = gcry_sexp_nth_mpi (list, 1, 0);
assert (data);
gcry_sexp_release (list);
return data;
}
/* Perform the sign operation. If CACHE_NONCE is given the agent is
advised to use that cached passphrase fro the key. */
static int
@ -418,7 +403,7 @@ match_dsa_hash (unsigned int qbytes)
if (qbytes <= 48)
return DIGEST_ALGO_SHA384;
if (qbytes <= 64)
if (qbytes <= 66 ) /* 66 corresponds to 521 (64 to 512) */
return DIGEST_ALGO_SHA512;
return DEFAULT_DIGEST_ALGO;
@ -451,9 +436,13 @@ hash_for (PKT_public_key *pk)
{
return recipient_digest_algo;
}
else if (pk->pubkey_algo == PUBKEY_ALGO_DSA)
else if(pk->pubkey_algo==PUBKEY_ALGO_DSA || pk->pubkey_algo==PUBKEY_ALGO_ECDSA )
{
unsigned int qbytes = gcry_mpi_get_nbits (pk->pkey[1]) / 8;
unsigned int qbytes = gcry_mpi_get_nbits (pk->pkey[1]);
if( pk->pubkey_algo==PUBKEY_ALGO_ECDSA )
qbytes = ecdsa_qbits_from_Q(qbytes);
qbytes = qbytes/8;
/* It's a DSA key, so find a hash that is the same size as q or
larger. If q is 160, assume it is an old DSA key and use a
@ -935,10 +924,13 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next )
{
if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA)
if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA )
{
int temp_hashlen = gcry_mpi_get_nbits
(sk_rover->pk->pkey[1])+7/8;
int temp_hashlen = gcry_mpi_get_nbits(sk_rover->pk->pkey[1]);
if( sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA )
temp_hashlen = ecdsa_qbits_from_Q( temp_hashlen );
temp_hashlen = (temp_hashlen+7)/8;
/* Pick a hash that is large enough for our
largest q */
@ -1494,7 +1486,9 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
&& pk->version<4 && sigversion<4)
digest_algo = DIGEST_ALGO_MD5;
else if(pksk->pubkey_algo==PUBKEY_ALGO_DSA)
digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8);
digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8 );
else if(pksk->pubkey_algo==PUBKEY_ALGO_ECDSA )
digest_algo = match_dsa_hash (ecdsa_qbits_from_Q( gcry_mpi_get_nbits (pksk->pkey[1]) ) / 8);
else
digest_algo = DIGEST_ALGO_SHA1;
}

30
g10/verify-stubs.c Normal file
View File

@ -0,0 +1,30 @@
/* To satisfy the linker for the gpgv target
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006,
* 2007 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include "gpg.h"
#include "main.h"
int
pk_ecc_keypair_gen( PKT_public_key **pk_out, int algo, int keygen_flags, char **cache_nonce_addr, unsigned nbits) {
return GPG_ERR_NOT_IMPLEMENTED;
}

View File

@ -176,5 +176,7 @@ next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length)
}
return NULL;
}
}

View File

@ -38,7 +38,7 @@ const void *find_tuple (tupledesc_t tupledesc,
unsigned int tag, size_t *r_length);
const void *next_tuple (tupledesc_t tupledesc,
unsigned int *r_tag, size_t *r_length);
char *mpi2hex( gcry_mpi_t m );
#endif /*G13_UTILS_H*/

View File

@ -56,6 +56,8 @@
#define PUBKEY_ALGO_RSA_S /* 3 */ GCRY_PK_RSA_S /* RSA sign only. */
#define PUBKEY_ALGO_ELGAMAL_E /* 16 */ GCRY_PK_ELG_E /* Elgamal encr only */
#define PUBKEY_ALGO_DSA /* 17 */ GCRY_PK_DSA
#define PUBKEY_ALGO_ECDH 18 /* corresponds to GCRY_PK_ECDH ECC DH; encrypt only */
#define PUBKEY_ALGO_ECDSA 19 /* corresponds to GCRY_PK_ECDSA ECC DSA; sign only */
#define PUBKEY_ALGO_ELGAMAL /* 20 */ GCRY_PK_ELG /* Elgamal encr+sign */
#define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */

View File

@ -186,7 +186,7 @@ next_packet (unsigned char const **bufptr, size_t *buflen,
}
/* Parse a key packet and store the ionformation in KI. */
/* Parse a key packet and store the information in KI. */
static gpg_error_t
parse_key (const unsigned char *data, size_t datalen,
struct _keybox_openpgp_key_info *ki)
@ -243,6 +243,11 @@ parse_key (const unsigned char *data, size_t datalen,
case 17: /* DSA */
npkey = 4;
break;
case 18: /* ECDH */
npkey = 3;
case 19: /* ECDSA */
npkey = 2;
break;
default: /* Unknown algorithm. */
return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
}