mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Editorial changes and allow building with old libgcrypts.
Changed order of some conditional to make to put the special case into the true branch. Indentation changes. Minor other changes to make the ECC code more similar to the rest of our code. It builds but many sefltests still fail. Need to fix that before using it with an ECDH enabled libgcrypt. [/] 2011-01-21 Werner Koch <wk@g10code.com> * configure.ac: Need Libgcrypt 1.4.6 due to AESWRAP. (HAVE_GCRY_PK_ECDH): Add new test. [agent/] 2011-01-21 Werner Koch <wk@g10code.com> * cvt-openpgp.c (GCRY_PK_ECDH) [!HAVE_GCRY_PK_ECDH]: New. [include/] 2011-01-21 Werner Koch <wk@g10code.com> * cipher.h (GCRY_PK_USAGE_CERT): Remove compatibility macros because we now require libgcrypt 1.4.6. (GCRY_PK_ECDH): Add replacement.
This commit is contained in:
parent
a66772aa63
commit
90b0ff23b7
@ -1,3 +1,8 @@
|
||||
2011-01-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac: Need Libgcrypt 1.4.6 due to AESWRAP.
|
||||
(HAVE_GCRY_PK_ECDH): Add new test.
|
||||
|
||||
2011-01-03 Werner Koch <wk@g10code.com>
|
||||
|
||||
* README.SVN: Rename to README.GIT.
|
||||
|
@ -1,3 +1,7 @@
|
||||
2011-01-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cvt-openpgp.c (GCRY_PK_ECDH) [!HAVE_GCRY_PK_ECDH]: New.
|
||||
|
||||
2010-12-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg-agent.c (CHECK_OWN_SOCKET_INTERVAL) [W32CE]: Set to 60
|
||||
|
@ -28,6 +28,13 @@
|
||||
#include "i18n.h"
|
||||
#include "cvt-openpgp.h"
|
||||
|
||||
/* Macros for compatibility with older libgcrypt versions. */
|
||||
#ifndef HAVE_GCRY_PK_ECDSA
|
||||
# define GCRY_PK_ECDH 302
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/* Helper to pass data via the callback to do_unprotect. */
|
||||
struct try_do_unprotect_arg_s
|
||||
@ -100,8 +107,8 @@ 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.
|
||||
pubkey_algo is a libgcrypt ID
|
||||
parameters into our s-expression based format. Note that
|
||||
PUBKEY_ALGO is a standard id and not an OpenPGP id.
|
||||
*/
|
||||
static gpg_error_t
|
||||
convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
|
||||
@ -111,6 +118,7 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
|
||||
|
||||
*r_key = NULL;
|
||||
|
||||
/* FIXME: This is not consistent with the above comment. */
|
||||
pubkey_algo = map_pk_openpgp_to_gcry (pubkey_algo);
|
||||
|
||||
switch (pubkey_algo)
|
||||
@ -224,8 +232,8 @@ do_unprotect (const char *passphrase,
|
||||
|
||||
*r_key = NULL;
|
||||
|
||||
/* Unfortunately, the OpenPGP PK algorithm numbers need to be re-mapped for Libgcrypt
|
||||
*/
|
||||
/* 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
|
||||
@ -655,7 +663,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); /* ligcrypt IDs */
|
||||
pubkey_algo = gcry_pk_map_name (string);
|
||||
xfree (string);
|
||||
|
||||
if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
|
||||
@ -1022,7 +1030,6 @@ 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)
|
||||
@ -1052,7 +1059,6 @@ 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)
|
||||
@ -1082,8 +1088,6 @@ 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);
|
||||
@ -1093,7 +1097,6 @@ 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"
|
||||
@ -1106,7 +1109,6 @@ 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);
|
||||
@ -1116,8 +1118,5 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -2304,6 +2304,8 @@ check_for_running_agent (int silent, int mode)
|
||||
}
|
||||
|
||||
/* TODO: it is also in misc, which is not linked with the agent */
|
||||
/* FIXME: The agent should not know about openpgp internals - weel
|
||||
except for some stuff in cvt-openpgp. */
|
||||
int
|
||||
map_pk_openpgp_to_gcry (int algo)
|
||||
{
|
||||
|
@ -43,7 +43,7 @@
|
||||
|
||||
|
||||
/* A table containing the information needed to create a protected
|
||||
private key */
|
||||
private key. */
|
||||
static struct {
|
||||
const char *algo;
|
||||
const char *parmlist;
|
||||
@ -428,9 +428,6 @@ 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);
|
||||
@ -459,55 +456,41 @@ 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) {
|
||||
log_info ("Unsupported alg %d for protection\n", protect_info[infidx].algo);
|
||||
if (!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 != '(') {
|
||||
log_info ("Unbalanced bracket in S-expression #1\n");
|
||||
if (*s != '(')
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
}
|
||||
depth++;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n) {
|
||||
log_info ("Cannot get the length of S-expression field\n");
|
||||
if (!n)
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
}
|
||||
if (n != 1 || c != *s) {
|
||||
log_info ("Invalid length in S-expression field\n");
|
||||
if (n != 1 || c != *s)
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
}
|
||||
s += n;
|
||||
n = snext (&s);
|
||||
if (!n) {
|
||||
log_info ("Invalid fieled in S-expression field\n");
|
||||
if (!n)
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
}
|
||||
s +=n; /* skip value */
|
||||
if (*s != ')') {
|
||||
log_info ("Unbalanced bracket in S-expression #2\n");
|
||||
if (*s != ')')
|
||||
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 ) {
|
||||
log_info ("Unbalanced bracket in S-expression #3\n");
|
||||
if (*s != ')' || !prot_begin || !prot_end )
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
}
|
||||
depth--;
|
||||
hash_end = s;
|
||||
s++;
|
||||
/* skip to the end of the S-exp */
|
||||
/* Skip to the end of the S-expression. */
|
||||
assert (depth == 1);
|
||||
rc = sskip (&s, &depth);
|
||||
if (rc)
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "gcrypt.h"
|
||||
#include "gcrypt.h" /* FIXME: really needed? */
|
||||
|
||||
|
||||
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
|
||||
@ -250,7 +250,10 @@ hex2str_alloc (const char *hexstring, size_t *r_count)
|
||||
* caller must free with xfree
|
||||
* Returns NULL on error, never throws
|
||||
*/
|
||||
char *mpi2hex( gcry_mpi_t m ) {
|
||||
char *
|
||||
mpi2hex( gcry_mpi_t m )
|
||||
{
|
||||
#warning we have code for this in libcrypt
|
||||
size_t nbytes;
|
||||
size_t nbytes2;
|
||||
int rc;
|
||||
@ -270,7 +273,9 @@ char *mpi2hex( gcry_mpi_t m ) {
|
||||
|
||||
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);
|
||||
/*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;
|
||||
}
|
||||
|
||||
|
18
configure.ac
18
configure.ac
@ -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.2.0])
|
||||
m4_define([my_version], [2.1.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.6.0
|
||||
NEED_LIBGCRYPT_VERSION=1.4.6
|
||||
|
||||
NEED_LIBASSUAN_API=2
|
||||
NEED_LIBASSUAN_VERSION=2.0.0
|
||||
@ -724,6 +724,20 @@ AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION",
|
||||
AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_API:$NEED_LIBGCRYPT_VERSION",
|
||||
have_libgcrypt=yes,have_libgcrypt=no)
|
||||
|
||||
AC_CACHE_CHECK([whether Libgcrypt support ECDH], gnupg_cv_gcry_pk_ecdh,
|
||||
[ _gnupg_gcry_save_cflags=$CFLAGS
|
||||
CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
|
||||
AC_TRY_COMPILE(
|
||||
[#include <gcrypt>],
|
||||
[ return GCRY_PK_ECDH; ],
|
||||
gnupg_cv_gcry_pk_ecdh=yes,
|
||||
gnupg_cv_gcry_pk_ecdh=no)
|
||||
CFLAGS=$_gnupg_gcry_save_cflags])
|
||||
if test "$gnupg_cv_gcry_pk_ecdh" = yes; then
|
||||
AC_DEFINE([HAVE_GCRY_PK_ECDH], 1,
|
||||
[Define if gcrypt.h has the enum value for ECDH.])
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# libassuan is used for IPC
|
||||
|
@ -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) -llber
|
||||
dirmngr_LDADD += $(LDAPLIBS) -llber #FIXME: Test for liblber first.
|
||||
endif
|
||||
dirmngr_LDFLAGS = $(extra_bin_ldflags)
|
||||
|
||||
|
@ -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 "-ecc ("
|
||||
iobuf_writestr(a, "Version: GnuPG v" VERSION " ("
|
||||
PRINTABLE_OS_NAME ")" );
|
||||
iobuf_writestr(a,afx->eol);
|
||||
}
|
||||
|
@ -178,21 +178,20 @@ 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.
|
||||
*/
|
||||
/* 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
|
||||
|
||||
|
||||
/****************
|
||||
* calculate the length of a packet described by PKT
|
||||
*/
|
||||
/* Calculate the length of a packet described by PKT. */
|
||||
u32
|
||||
calc_packet_length( PACKET *pkt )
|
||||
{
|
||||
@ -300,24 +299,35 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
||||
}
|
||||
assert (npkey < nskey);
|
||||
|
||||
if( pk->pubkey_algo != PUBKEY_ALGO_ECDSA && pk->pubkey_algo != PUBKEY_ALGO_ECDH ) {
|
||||
/* Writing the public parameters is easy, */
|
||||
/* Writing the public parameters is easy. Except if we do an
|
||||
adjustment for ECC OID and possibly KEK params for ECDH. */
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
/* Write DER of OID with preceeding length byte. */
|
||||
err = iobuf_name_oid_write (a, pk->pkey[0]);
|
||||
if (err)
|
||||
goto leave;
|
||||
/* Write point Q, the public key. */
|
||||
err = mpi_write (a, pk->pkey[1]);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Write one more public field for ECDH. */
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
err = ecdh_kek_params_write(a,pk->pkey[2]);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -483,16 +493,19 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
|
||||
if ( !n )
|
||||
write_fake_data( a, enc->data[0] );
|
||||
|
||||
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 */
|
||||
if (enc->pubkey_algo == PUBKEY_ALGO_ECDH )
|
||||
{
|
||||
/* 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)
|
||||
rc = ecdh_esk_write (a, enc->data[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i < n && !rc ; i++ )
|
||||
rc = mpi_write(a, enc->data[i] );
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
|
237
g10/ecdh.c
237
g10/ecdh.c
@ -1,5 +1,5 @@
|
||||
/* ecdh.c - ECDH public key operations used in public key glue code
|
||||
* Copyright (C) 2000, 2003 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -31,10 +31,12 @@
|
||||
#include "options.h"
|
||||
|
||||
gcry_mpi_t
|
||||
pk_ecdh_default_params_to_mpi( int qbits ) {
|
||||
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. */
|
||||
/* 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*/,
|
||||
@ -50,11 +52,15 @@ pk_ecdh_default_params_to_mpi( int qbits ) {
|
||||
} 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
|
||||
|
||||
/* Note: 528 is 521 rounded to the 8 bit boundary */
|
||||
{ 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 }
|
||||
};
|
||||
|
||||
for( i=0; i<sizeof(kek_params_table)/sizeof(kek_params_table[0]); i++ ) {
|
||||
if( kek_params_table[i].qbits >= qbits ) {
|
||||
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;
|
||||
@ -63,20 +69,24 @@ pk_ecdh_default_params_to_mpi( int qbits ) {
|
||||
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);
|
||||
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
|
||||
|
||||
/* Returns allocated (binary) KEK parameters; the size is returned in
|
||||
* sizeout. The caller must free the returned value with xfree.
|
||||
* Returns NULL on error.
|
||||
*/
|
||||
byte *
|
||||
pk_ecdh_default_params( int qbits, size_t *sizeout ) {
|
||||
/* Defaults are the strongest possible choices. Performance is not an issue here, only interoperability. */
|
||||
pk_ecdh_default_params (int qbits, size_t *sizeout)
|
||||
{
|
||||
/* 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*/,
|
||||
@ -92,15 +102,18 @@ pk_ecdh_default_params( int qbits, size_t *sizeout ) {
|
||||
} 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
|
||||
/* Note: 528 is 521 rounded to the 8 bit boundary */
|
||||
{ 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 }
|
||||
};
|
||||
|
||||
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 ) {
|
||||
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;
|
||||
@ -110,21 +123,27 @@ pk_ecdh_default_params( int qbits, size_t *sizeout ) {
|
||||
log_printhex ("ecdh kek params are", kek_params, sizeof(kek_params));
|
||||
|
||||
p = xtrymalloc (sizeof(kek_params));
|
||||
if( p == NULL )
|
||||
if (!p)
|
||||
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.
|
||||
|
||||
/* 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)
|
||||
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;
|
||||
@ -141,13 +160,17 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
|
||||
{
|
||||
size_t nbytes;
|
||||
/* extract x component of the shared point: this is the actual shared secret */
|
||||
/* 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 ) {
|
||||
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) );
|
||||
log_error ("ec ephemeral export of shared point failed: %s\n",
|
||||
gpg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
secret_x_size = (nbits+7)/8;
|
||||
@ -159,37 +182,48 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
log_printhex ("ecdh shared secret X is:", secret_x, secret_x_size );
|
||||
}
|
||||
|
||||
/*** We have now the shared secret bytes in secret_x ***/
|
||||
/*** 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.
|
||||
/* 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) );
|
||||
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 );
|
||||
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 */
|
||||
/* Expect 4 bytes 03 01 hash_alg symm_alg. */
|
||||
if (kdf_params_size != 4 || kdf_params[0] != 3 || kdf_params[1] != 1)
|
||||
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) );
|
||||
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 )
|
||||
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 )
|
||||
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 */
|
||||
/* Build kdf_params. */
|
||||
{
|
||||
IOBUF obuf;
|
||||
|
||||
@ -205,13 +239,15 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
/* 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) );
|
||||
kdf_params_size = iobuf_temp_to_buffer (obuf,
|
||||
kdf_params, sizeof(kdf_params));
|
||||
iobuf_close (obuf);
|
||||
if( rc ) {
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if(DBG_CIPHER)
|
||||
log_printhex ("ecdh KDF message params are:", kdf_params, kdf_params_size );
|
||||
log_printhex ("ecdh KDF message params are:",
|
||||
kdf_params, kdf_params_size );
|
||||
}
|
||||
|
||||
/* Derive a KEK (key wrapping key) using kdf_params and secret_x. */
|
||||
@ -231,7 +267,8 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
|
||||
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));
|
||||
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;
|
||||
@ -239,12 +276,13 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
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 */
|
||||
/* We could have allocated more, so clean the tail before returning. */
|
||||
memset( secret_x+secret_x_size, old_size-secret_x_size, 0 );
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ecdh KEK is:", secret_x, secret_x_size );
|
||||
}
|
||||
|
||||
/* And, finally, aeswrap with key secret_x */
|
||||
/* And, finally, aeswrap with key secret_x. */
|
||||
{
|
||||
gcry_cipher_hd_t hd;
|
||||
size_t nbytes;
|
||||
@ -257,7 +295,8 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
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));
|
||||
log_error ("ecdh failed to initialize AESWRAP: %s\n",
|
||||
gpg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -266,25 +305,31 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
if (rc)
|
||||
{
|
||||
gcry_cipher_close (hd);
|
||||
log_error("ecdh failed in gcry_cipher_setkey: %s\n", gpg_strerror (rc));
|
||||
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 ) {
|
||||
data_buf = xtrymalloc_secure( 1 + 2*data_buf_size + 8);
|
||||
if (!data_buf)
|
||||
{
|
||||
gcry_cipher_close (hd);
|
||||
return GPG_ERR_ENOMEM;
|
||||
}
|
||||
|
||||
if( is_encrypt ) {
|
||||
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 ) {
|
||||
/* 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);
|
||||
@ -294,12 +339,14 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
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);
|
||||
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));
|
||||
log_error ("ecdh failed in gcry_cipher_encrypt: %s\n",
|
||||
gpg_strerror (rc));
|
||||
xfree (data_buf);
|
||||
return rc;
|
||||
}
|
||||
@ -308,7 +355,9 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
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 */
|
||||
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)
|
||||
{
|
||||
@ -318,11 +367,14 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
|
||||
*out = result;
|
||||
}
|
||||
else {
|
||||
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 ) {
|
||||
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;
|
||||
@ -333,11 +385,13 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
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 );
|
||||
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));
|
||||
log_error ("ecdh failed in gcry_cipher_decrypt: %s\n",
|
||||
gpg_strerror (rc));
|
||||
xfree (data_buf);
|
||||
return rc;
|
||||
}
|
||||
@ -347,17 +401,20 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
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;
|
||||
//}
|
||||
/* 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));
|
||||
log_error ("ecdh failed to create a plain text MPI: %s\n",
|
||||
gpg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -380,7 +437,8 @@ gen_k (unsigned nbits)
|
||||
|
||||
gcry_mpi_randomize (k, nbits-1, GCRY_STRONG_RANDOM);
|
||||
|
||||
if( DBG_CIPHER ) {
|
||||
if (DBG_CIPHER)
|
||||
{
|
||||
unsigned char *buffer;
|
||||
if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, k))
|
||||
BUG ();
|
||||
@ -391,10 +449,10 @@ gen_k (unsigned nbits)
|
||||
return k;
|
||||
}
|
||||
|
||||
/* Perform ECDH encryption, which involves ECDH key generation.
|
||||
*/
|
||||
/* 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)
|
||||
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;
|
||||
|
||||
@ -404,7 +462,7 @@ pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcr
|
||||
|
||||
nbits = pubkey_nbits (PUBKEY_ALGO_ECDH, pkey);
|
||||
|
||||
/*** Generate an ephemeral key, actually, a scalar ***/
|
||||
/*** Generate an ephemeral key, actually, a scalar. ***/
|
||||
|
||||
k = gen_k (nbits);
|
||||
if( k == NULL )
|
||||
@ -414,50 +472,63 @@ pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcr
|
||||
* 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]);
|
||||
"(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", k)) /* ephemeral scalar goes as data */
|
||||
/* Put the data into a simple list. */
|
||||
/* Ephemeral scalar goes as data. */
|
||||
if (gcry_sexp_build (&s_data, NULL, "%m", k))
|
||||
BUG ();
|
||||
|
||||
/* pass it to libgcrypt */
|
||||
/* 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 */
|
||||
/* 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] = mpi_from_sexp (s_ciph, "b"); /* ephemeral public key */
|
||||
/* ... and get the shared point/ */
|
||||
gcry_mpi_t shared;
|
||||
|
||||
if( DBG_CIPHER ) {
|
||||
shared = mpi_from_sexp (s_ciph, "a");
|
||||
gcry_sexp_release (s_ciph);
|
||||
/* Ephemeral public key. */
|
||||
resarr[0] = mpi_from_sexp (s_ciph, "b");
|
||||
|
||||
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 );
|
||||
rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
|
||||
pk_fp, data, pkey, resarr+1);
|
||||
mpi_release (shared);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Perform ECDH decryption.
|
||||
*/
|
||||
|
||||
/* 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 shared, gcry_mpi_t * skey) {
|
||||
pk_ecdh_decrypt (gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN],
|
||||
gcry_mpi_t data, gcry_mpi_t shared, gcry_mpi_t * skey)
|
||||
{
|
||||
if (!data)
|
||||
return gpg_error (GPG_ERR_BAD_MPI);
|
||||
return pk_ecdh_encrypt_with_shared_point ( 0 /*=decryption*/, shared, sk_fp, data/*encr data as an MPI*/, skey, result );
|
||||
return pk_ecdh_encrypt_with_shared_point (0 /*=decryption*/, shared,
|
||||
sk_fp, data/*encr data as an MPI*/,
|
||||
skey, result);
|
||||
}
|
||||
|
||||
|
||||
|
22
g10/export.c
22
g10/export.c
@ -1161,18 +1161,16 @@ 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 (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"); */
|
||||
|
@ -813,7 +813,7 @@ my_strusage( int level )
|
||||
const char *p;
|
||||
|
||||
switch( level ) {
|
||||
case 11: p = "gpg (GnuPG) ecc";
|
||||
case 11: p = "gpg (GnuPG)";
|
||||
break;
|
||||
case 13: p = VERSION; break;
|
||||
case 17: p = PRINTABLE_OS_NAME; break;
|
||||
|
@ -18,6 +18,7 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#warning wk: check these changes.
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -43,7 +44,6 @@
|
||||
#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
|
||||
|
29
g10/keyid.c
29
g10/keyid.c
@ -57,8 +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)
|
||||
case PUBKEY_ALGO_ECDSA: return 'E' ; /* ECC DSA (sign only) */
|
||||
case PUBKEY_ALGO_ECDH: return 'e' ; /* ECC DH (encrypt only) */
|
||||
default: return '?';
|
||||
}
|
||||
}
|
||||
@ -76,8 +76,6 @@ 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)
|
||||
@ -94,8 +92,14 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
|
||||
{
|
||||
for (i=0; i < npkey; 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);
|
||||
enum gcry_mpi_format fmt;
|
||||
|
||||
if ((pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
&& (i == 0 || i == 2))
|
||||
fmt = GCRYMPI_FMT_USG; /* Name of OID or KEK parms. */
|
||||
else
|
||||
fmt = GCRYMPI_FMT_PGP;
|
||||
|
||||
if (gcry_mpi_print (fmt, NULL, 0, &nbytes, pk->pkey[i]))
|
||||
BUG ();
|
||||
@ -724,13 +728,12 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
|
||||
"(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;
|
||||
*/
|
||||
|
||||
/* 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);
|
||||
|
16
g10/main.h
16
g10/main.h
@ -87,9 +87,12 @@ u16 checksum_mpi( gcry_mpi_t a );
|
||||
u32 buffer_to_u32( const byte *buffer );
|
||||
const byte *get_session_marker( size_t *rlen );
|
||||
int map_cipher_openpgp_to_gcry (int algo);
|
||||
#define openpgp_cipher_open(_a,_b,_c,_d) gcry_cipher_open((_a),map_cipher_openpgp_to_gcry((_b)),(_c),(_d))
|
||||
#define openpgp_cipher_get_algo_keylen(_a) gcry_cipher_get_algo_keylen(map_cipher_openpgp_to_gcry((_a)))
|
||||
#define openpgp_cipher_get_algo_blklen(_a) gcry_cipher_get_algo_blklen(map_cipher_openpgp_to_gcry((_a)))
|
||||
#define openpgp_cipher_open(_a,_b,_c,_d) \
|
||||
gcry_cipher_open((_a),map_cipher_openpgp_to_gcry((_b)),(_c),(_d))
|
||||
#define openpgp_cipher_get_algo_keylen(_a) \
|
||||
gcry_cipher_get_algo_keylen(map_cipher_openpgp_to_gcry((_a)))
|
||||
#define openpgp_cipher_get_algo_blklen(_a) \
|
||||
gcry_cipher_get_algo_blklen(map_cipher_openpgp_to_gcry((_a)))
|
||||
int openpgp_cipher_blocklen (int algo);
|
||||
int openpgp_cipher_test_algo( int algo );
|
||||
const char *openpgp_cipher_algo_name (int algo);
|
||||
@ -159,7 +162,8 @@ 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 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 );
|
||||
|
||||
@ -258,7 +262,9 @@ int save_unprotected_key_to_card (PKT_public_key *sk, int keyno);
|
||||
|
||||
#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);
|
||||
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 );
|
||||
|
97
g10/misc.c
97
g10/misc.c
@ -1,6 +1,6 @@
|
||||
/* misc.c - miscellaneous functions
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
* 2008, 2009 Free Software Foundation, Inc.
|
||||
* 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -366,10 +366,17 @@ map_cipher_gcry_to_openpgp (int algo)
|
||||
}
|
||||
}
|
||||
|
||||
/* Map OpenPGP public key algorithm numbers to those used by
|
||||
Libgcrypt. */
|
||||
int
|
||||
map_pk_openpgp_to_gcry (int algo)
|
||||
{
|
||||
return (algo==PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : (algo==PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo));
|
||||
switch (algo)
|
||||
{
|
||||
case PUBKEY_ALGO_ECDSA: return GCRY_PK_ECDSA;
|
||||
case PUBKEY_ALGO_ECDH: return GCRY_PK_ECDH;
|
||||
default: return algo;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -416,13 +423,7 @@ openpgp_cipher_test_algo( int algo )
|
||||
const char *
|
||||
openpgp_cipher_algo_name (int 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 ) );
|
||||
return gnupg_cipher_algo_name (map_cipher_openpgp_to_gcry (algo));
|
||||
}
|
||||
|
||||
int
|
||||
@ -438,12 +439,7 @@ openpgp_pk_test_algo( int algo )
|
||||
if (algo < 0 || algo > 110)
|
||||
return gpg_error (GPG_ERR_PUBKEY_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 );
|
||||
return gcry_pk_test_algo (map_pk_openpgp_to_gcry (algo));
|
||||
}
|
||||
|
||||
int
|
||||
@ -461,12 +457,8 @@ openpgp_pk_test_algo2( int algo, unsigned int use )
|
||||
if (algo < 0 || algo > 110)
|
||||
return gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
|
||||
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);
|
||||
return gcry_pk_algo_info (map_pk_openpgp_to_gcry (algo),
|
||||
GCRYCTL_TEST_ALGO, NULL, &use_buf);
|
||||
}
|
||||
|
||||
int
|
||||
@ -507,10 +499,12 @@ 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)
|
||||
{
|
||||
/* We use fixed strings to have pretty names instead of those from
|
||||
libgcrypt. */
|
||||
switch (algo)
|
||||
{
|
||||
case PUBKEY_ALGO_RSA:
|
||||
@ -522,10 +516,13 @@ openpgp_pk_algo_name (int algo)
|
||||
|
||||
case PUBKEY_ALGO_DSA: return "dsa";
|
||||
|
||||
default: return "?";
|
||||
case PUBKEY_ALGO_ECDSA:return "ecdsa";
|
||||
|
||||
case PUBKEY_ALGO_ECDH: return "ecdh";
|
||||
|
||||
default: gcry_pk_algo_name (map_pk_openpgp_to_gcry (algo));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
int
|
||||
@ -1444,6 +1441,7 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
|
||||
int rc, nbits;
|
||||
gcry_sexp_t sexp;
|
||||
|
||||
#warning Why this assert
|
||||
assert( algo != GCRY_PK_ECDSA && algo != GCRY_PK_ECDH );
|
||||
|
||||
if( algo == GCRY_PK_DSA ) {
|
||||
@ -1506,10 +1504,12 @@ 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
|
||||
* 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.
|
||||
*/
|
||||
/* FIXME: Rename this function: it is not in iobuf.c */
|
||||
int
|
||||
iobuf_write_size_body_mpi (iobuf_t out, gcry_mpi_t a)
|
||||
{
|
||||
@ -1538,33 +1538,43 @@ iobuf_write_size_body_mpi (iobuf_t out, gcry_mpi_t a)
|
||||
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).
|
||||
* 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).
|
||||
*/
|
||||
/* FIXME: Rename this function: it is not in iobuf.c */
|
||||
int
|
||||
iobuf_read_size_body( iobuf_t inp, byte *body, int body_max_size, int pktlen, gcry_mpi_t *out ) {
|
||||
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 ) {
|
||||
if( (n = iobuf_readbyte(inp)) == -1 )
|
||||
{
|
||||
return G10ERR_INVALID_PACKET;
|
||||
}
|
||||
if( n >= body_max_size || n < 2) {
|
||||
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 ) {
|
||||
if ((n = iobuf_read(inp, body+1, n)) == -1)
|
||||
{
|
||||
log_error("invalid size+body field\n");
|
||||
return G10ERR_INVALID_PACKET;
|
||||
}
|
||||
if( n+1 > pktlen ) {
|
||||
if (n+1 > pktlen)
|
||||
{
|
||||
log_error("size+body field is larger than the packet\n");
|
||||
return G10ERR_INVALID_PACKET;
|
||||
}
|
||||
@ -1578,17 +1588,18 @@ iobuf_read_size_body( iobuf_t inp, byte *body, int body_max_size, int pktlen, gc
|
||||
}
|
||||
|
||||
|
||||
/* 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"));
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -939,7 +939,32 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
}
|
||||
else
|
||||
{
|
||||
if( k->pubkey_algo != PUBKEY_ALGO_ECDH ) {
|
||||
if (k->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
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]+1);
|
||||
mpi_print (listfp, k->data[1], mpi_print_mode );
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
pktlen -= (encr_buf[0]+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < ndata; i++)
|
||||
{
|
||||
n = pktlen;
|
||||
@ -955,24 +980,6 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
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]+1);
|
||||
mpi_print(listfp, k->data[1], mpi_print_mode );
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
pktlen -= (encr_buf[0]+1);
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
@ -1946,7 +1953,59 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
else
|
||||
{
|
||||
/* Fill in public key parameters. */
|
||||
if( algorithm != PUBKEY_ALGO_ECDSA && algorithm != PUBKEY_ALGO_ECDH ) {
|
||||
if (algorithm == PUBKEY_ALGO_ECDSA && algorithm == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
/* FIXME: 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/ */
|
||||
n = pktlen;
|
||||
pk->pkey[1] = mpi_read( inp, &n, 0 );
|
||||
pktlen -=n;
|
||||
if (!pk->pkey[1])
|
||||
err = gpg_error (GPG_ERR_INV_PACKET);
|
||||
else if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp, "\tpkey[1]: ");
|
||||
mpi_print (listfp, pk->pkey[1], mpi_print_mode);
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
/* One more field for ECDH. */
|
||||
if (algorithm == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
/* (NAMEOID holds the KEK params.) */
|
||||
err = iobuf_read_size_body (inp, name_oid, sizeof(name_oid),
|
||||
pktlen, pk->pkey+2);
|
||||
if (err)
|
||||
goto leave;
|
||||
n = name_oid[0];
|
||||
if (name_oid[1] != 1)
|
||||
{
|
||||
log_error ("invalid ecdh KEK parameters field type in "
|
||||
"private key: understand type 1, "
|
||||
"but found 0x%02x\n", name_oid[1]);
|
||||
err = gpg_error (GPG_ERR_INV_PACKET);
|
||||
goto leave;
|
||||
}
|
||||
if (list_mode)
|
||||
es_fprintf (listfp, "\tpkey[2]: KEK params type=01 "
|
||||
"hash:%d sym-algo:%d\n",
|
||||
name_oid[1+n-2], name_oid[1+n-1]);
|
||||
pktlen -= (n+1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < npkey; i++)
|
||||
{
|
||||
n = pktlen;
|
||||
@ -1961,45 +2020,6 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
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);
|
||||
}
|
||||
/* 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;
|
||||
|
107
g10/pkglue.c
107
g10/pkglue.c
@ -1,5 +1,5 @@
|
||||
/* pkglue.c - public key operations glue code
|
||||
* Copyright (C) 2000, 2003 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -29,7 +29,8 @@
|
||||
#include "pkglue.h"
|
||||
#include "main.h"
|
||||
|
||||
|
||||
/* FIXME: Better chnage the fucntion name because mpi_ is used by
|
||||
gcrypt macros. */
|
||||
gcry_mpi_t
|
||||
mpi_from_sexp (gcry_sexp_t sexp, const char * item)
|
||||
{
|
||||
@ -45,70 +46,6 @@ 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
|
||||
@ -119,27 +56,27 @@ 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 );
|
||||
const int pkalgo = map_pk_openpgp_to_gcry (algo);
|
||||
|
||||
/* make a sexp from pkey */
|
||||
if (gcry_pkalgo == GCRY_PK_DSA)
|
||||
/* Make a sexp from pkey. */
|
||||
if (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 (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
|
||||
else if (pkalgo == GCRY_PK_ELG || 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 (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S)
|
||||
else if (pkalgo == GCRY_PK_RSA || 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 */
|
||||
else if (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]);
|
||||
@ -150,13 +87,13 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
|
||||
if (rc)
|
||||
BUG (); /* gcry_sexp_build should never fail. */
|
||||
|
||||
/* put hash into a S-Exp s_hash */
|
||||
/* Put hash into a S-Exp s_hash. */
|
||||
if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
|
||||
BUG (); /* gcry_sexp_build should never fail. */
|
||||
|
||||
/* Put data into a S-Exp s_sig. */
|
||||
s_sig = NULL;
|
||||
if (gcry_pkalgo == GCRY_PK_DSA)
|
||||
if (pkalgo == GCRY_PK_DSA)
|
||||
{
|
||||
if (!data[0] || !data[1])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
@ -164,7 +101,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(dsa(r%m)(s%m)))", data[0], data[1]);
|
||||
}
|
||||
else if (gcry_pkalgo == GCRY_PK_ECDSA)
|
||||
else if (pkalgo == GCRY_PK_ECDSA)
|
||||
{
|
||||
if (!data[0] || !data[1])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
@ -172,7 +109,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(ecdsa(r%m)(s%m)))", data[0], data[1]);
|
||||
}
|
||||
else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
|
||||
else if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
|
||||
{
|
||||
if (!data[0] || !data[1])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
@ -180,7 +117,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 (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S)
|
||||
else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_S)
|
||||
{
|
||||
if (!data[0])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
@ -207,12 +144,13 @@ 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, const byte pk_fp[MAX_FINGERPRINT_LEN], 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;
|
||||
|
||||
/* make a sexp from pkey */
|
||||
/* Make a sexp from pkey. */
|
||||
if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
|
||||
{
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
@ -235,11 +173,11 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, const byte pk_fp[MAX
|
||||
if (rc)
|
||||
BUG ();
|
||||
|
||||
/* put the data into a simple list */
|
||||
/* Put the data into a simple list. */
|
||||
if (gcry_sexp_build (&s_data, NULL, "%m", data))
|
||||
BUG ();
|
||||
|
||||
/* pass it to libgcrypt */
|
||||
/* Pass it to libgcrypt. */
|
||||
rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
|
||||
gcry_sexp_release (s_data);
|
||||
gcry_sexp_release (s_pkey);
|
||||
@ -247,9 +185,11 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, const byte pk_fp[MAX
|
||||
if (rc)
|
||||
;
|
||||
else
|
||||
{ /* add better error handling or make gnupg use S-Exp directly */
|
||||
{ /* 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 && algo != PUBKEY_ALGO_ECDH)
|
||||
if (algo != GCRY_PK_RSA
|
||||
&& algo != GCRY_PK_RSA_E
|
||||
&& algo != PUBKEY_ALGO_ECDH)
|
||||
resarr[1] = mpi_from_sexp (s_ciph, "b");
|
||||
}
|
||||
|
||||
@ -257,6 +197,7 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, const byte pk_fp[MAX
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Check whether SKEY is a suitable secret key. */
|
||||
int
|
||||
pk_check_secret_key (int algo, gcry_mpi_t *skey)
|
||||
|
12
g10/pkglue.h
12
g10/pkglue.h
@ -1,5 +1,5 @@
|
||||
/* pkglue.h - public key operations definitions
|
||||
* Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2003, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -22,19 +22,17 @@
|
||||
|
||||
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, 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 shared, 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 shared, 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);
|
||||
|
@ -218,23 +218,61 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
|
||||
log_printhex ("DEK frame:", frame, nframe);
|
||||
n = 0;
|
||||
|
||||
if( sk->pubkey_algo != PUBKEY_ALGO_ECDH ) {
|
||||
if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
gcry_mpi_t shared_mpi;
|
||||
gcry_mpi_t decoded;
|
||||
|
||||
/* At the beginning the frame are the bytes of shared point MPI. */
|
||||
err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL);
|
||||
if (err)
|
||||
{
|
||||
log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/,
|
||||
shared_mpi, sk->pkey);
|
||||
mpi_release (shared_mpi);
|
||||
if(err)
|
||||
goto leave;
|
||||
|
||||
/* Reuse NFRAME, which size is sufficient to include the session key. */
|
||||
err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, decoded);
|
||||
mpi_release (decoded);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Now the frame are the bytes decrypted but padded session key. */
|
||||
|
||||
/* Allow double padding for the benefit of DEK size concealment.
|
||||
Higher than this is wasteful. */
|
||||
if (frame[nframe-1] > 8*2 || nframe <= 8)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
||||
goto leave;
|
||||
}
|
||||
nframe -= frame[nframe-1]; /* Remove padding. */
|
||||
assert (n); /* (used just below) */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!card)
|
||||
{
|
||||
if (n + 7 > nframe)
|
||||
{
|
||||
err = gpg_error (G10ERR_WRONG_SECKEY);
|
||||
err = gpg_error (GPG_ERR_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);
|
||||
err = gpg_error (GPG_ERR_CIPHER_ALGO);
|
||||
goto leave;
|
||||
}
|
||||
if (frame[n] != 2) /* Something went wrong. */
|
||||
{
|
||||
err = gpg_error (G10ERR_WRONG_SECKEY);
|
||||
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
||||
goto leave;
|
||||
}
|
||||
for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */
|
||||
@ -242,44 +280,10 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
|
||||
n++; /* Skip the zero byte. */
|
||||
}
|
||||
}
|
||||
else {
|
||||
gcry_mpi_t shared_mpi;
|
||||
gcry_mpi_t decoded;
|
||||
|
||||
/* at the beginning the frame is the bytes of shared point MPI */
|
||||
|
||||
err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL);
|
||||
if (err) {
|
||||
log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/, shared_mpi, sk->pkey);
|
||||
mpi_release( shared_mpi );
|
||||
if( err )
|
||||
goto leave;
|
||||
|
||||
/* reuse nframe, which size is sufficient to include the session key */
|
||||
err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, decoded);
|
||||
mpi_release( decoded );
|
||||
if( err )
|
||||
goto leave;
|
||||
|
||||
/* Now the frame is the bytes decrypted but padded session key */
|
||||
|
||||
/* 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)
|
||||
{
|
||||
err = gpg_error (G10ERR_WRONG_SECKEY);
|
||||
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
95
g10/seskey.c
95
g10/seskey.c
@ -1,6 +1,6 @@
|
||||
/* seskey.c - make sesssion keys etc.
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
* 2006, 2009 Free Software Foundation, Inc.
|
||||
* 2006, 2009, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -80,35 +80,48 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
|
||||
byte *p;
|
||||
byte *frame;
|
||||
int i,n;
|
||||
u16 csum = 0;
|
||||
u16 csum;
|
||||
gcry_mpi_t a;
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_debug ("encode_session_key: encoding %d byte DEK", dek->keylen);
|
||||
|
||||
csum = 0;
|
||||
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.
|
||||
/* 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 */
|
||||
nframe = (( 1 + dek->keylen + 2 /* The value so far is always odd. */
|
||||
+ 7 ) & (~7));
|
||||
|
||||
/* alg+key+csum fit and the size is congruent to 8. */
|
||||
assert (!(nframe%8) && nframe > 1 + dek->keylen + 2 );
|
||||
|
||||
frame = xmalloc_secure (nframe);
|
||||
n = 0;
|
||||
frame[n++] = dek->algo;
|
||||
memcpy( frame+n, dek->key, dek->keylen ); n += dek->keylen;
|
||||
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 */
|
||||
i = nframe - n; /* Number of 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]);
|
||||
log_debug ("encode_session_key: "
|
||||
"[%d] %02x %02x %02x ... %02x %02x %02x\n",
|
||||
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();
|
||||
@ -146,19 +159,21 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
|
||||
assert( i > 0 );
|
||||
p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
|
||||
/* Replace zero bytes by new values. */
|
||||
for(;;) {
|
||||
for (;;)
|
||||
{
|
||||
int j, k;
|
||||
byte *pp;
|
||||
|
||||
/* count the zero bytes */
|
||||
/* Count the zero bytes. */
|
||||
for (j=k=0; j < i; j++ )
|
||||
if (!p[j])
|
||||
k++;
|
||||
if (!k)
|
||||
break; /* okay: no zero bytes */
|
||||
k += k/128 + 3; /* better get some more */
|
||||
break; /* Okay: no zero bytes. */
|
||||
k += k/128 + 3; /* Better get some more. */
|
||||
pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
|
||||
for(j=0; j < i && k ;) {
|
||||
for (j=0; j < i && k ;)
|
||||
{
|
||||
if (!p[j])
|
||||
p[j] = pp[--k];
|
||||
if (p[j])
|
||||
@ -171,7 +186,8 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
|
||||
n += i;
|
||||
frame[n++] = 0;
|
||||
frame[n++] = dek->algo;
|
||||
memcpy( frame+n, dek->key, dek->keylen ); n += dek->keylen;
|
||||
memcpy (frame+n, dek->key, dek->keylen );
|
||||
n += dek->keylen;
|
||||
frame[n++] = csum >>8;
|
||||
frame[n++] = csum;
|
||||
assert (n == nframe);
|
||||
@ -240,21 +256,22 @@ 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;
|
||||
int pkalgo;
|
||||
|
||||
assert (hash_algo);
|
||||
assert (pk);
|
||||
|
||||
gcry_pkalgo = map_pk_openpgp_to_gcry( pk->pubkey_algo );
|
||||
pkalgo = map_pk_openpgp_to_gcry (pk->pubkey_algo);
|
||||
|
||||
if (gcry_pkalgo == GCRY_PK_DSA || gcry_pkalgo == GCRY_PK_ECDSA )
|
||||
if (pkalgo == GCRY_PK_DSA || 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 )
|
||||
/* pkey[1] is Q for ECDSA, which is an uncompressed point,
|
||||
i.e. 04 <x> <y> */
|
||||
if (pkalgo == GCRY_PK_ECDSA)
|
||||
qbytes = ecdsa_qbits_from_Q (qbytes);
|
||||
|
||||
/* Make sure it is a multiple of 8 bits. */
|
||||
@ -275,30 +292,38 @@ encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
|
||||
if (qbytes < 160)
|
||||
{
|
||||
log_error (_("%s key %s uses an unsafe (%zu bit) hash\n"),
|
||||
gcry_pk_algo_name( gcry_pkalgo ),
|
||||
keystr_from_pk (pk), qbytes);
|
||||
gcry_pk_algo_name (pkalgo), keystr_from_pk (pk), qbytes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qbytes /= 8;
|
||||
|
||||
/* Check if we're too short. Too long is safe as we'll
|
||||
automatically left-truncate. */
|
||||
/* 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) < ((gcry_pkalgo==GCRY_PK_ECDSA && qbytes>(521)/8) ? 512/8 : qbytes) )
|
||||
automatically left-truncate.
|
||||
|
||||
FIXME: Check against FIPS.
|
||||
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)
|
||||
< ((pkalgo == GCRY_PK_ECDSA && qbytes > (521)/8) ? 512/8 : qbytes))
|
||||
{
|
||||
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);
|
||||
log_error (_("%s key %s requires a %zu bit or larger hash "
|
||||
"(hash is %s\n"),
|
||||
gcry_pk_algo_name (pkalgo),
|
||||
keystr_from_pk(pk), qbytes*8,
|
||||
gcry_md_algo_name (hash_algo));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Note that in case of ECDSA 521 hash is always smaller than the key size */
|
||||
/* Note that in case of ECDSA 521 hash is always smaller than
|
||||
the key size. */
|
||||
if (gcry_mpi_scan (&frame, GCRYMPI_FMT_USG,
|
||||
gcry_md_read (md, hash_algo), gcry_md_get_algo_dlen (hash_algo), &qbytes))
|
||||
gcry_md_read (md, hash_algo),
|
||||
gcry_md_get_algo_dlen (hash_algo), &qbytes))
|
||||
BUG();
|
||||
}
|
||||
else
|
||||
|
12
g10/sign.c
12
g10/sign.c
@ -436,7 +436,8 @@ hash_for (PKT_public_key *pk)
|
||||
{
|
||||
return recipient_digest_algo;
|
||||
}
|
||||
else if(pk->pubkey_algo==PUBKEY_ALGO_DSA || pk->pubkey_algo==PUBKEY_ALGO_ECDSA )
|
||||
else if (pk->pubkey_algo == PUBKEY_ALGO_DSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
|
||||
{
|
||||
unsigned int qbytes = gcry_mpi_get_nbits (pk->pkey[1]);
|
||||
|
||||
@ -924,9 +925,11 @@ 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 || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA )
|
||||
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]);
|
||||
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);
|
||||
@ -1488,7 +1491,8 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
|
||||
else if(pksk->pubkey_algo == PUBKEY_ALGO_DSA)
|
||||
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);
|
||||
digest_algo = match_dsa_hash (ecdsa_qbits_from_Q
|
||||
(gcry_mpi_get_nbits (pksk->pkey[1]))/8);
|
||||
else
|
||||
digest_algo = DIGEST_ALGO_SHA1;
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* To satisfy the linker for the gpgv target
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006,
|
||||
* 2007 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -25,6 +24,8 @@
|
||||
#include "main.h"
|
||||
|
||||
int
|
||||
pk_ecc_keypair_gen( PKT_public_key **pk_out, int algo, int keygen_flags, char **cache_nonce_addr, unsigned nbits) {
|
||||
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;
|
||||
}
|
||||
|
@ -178,5 +178,3 @@ next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,3 +1,9 @@
|
||||
2011-01-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cipher.h (GCRY_PK_USAGE_CERT): Remove comaptibility macros
|
||||
because we now require libgcrypt 1.4.6.
|
||||
(GCRY_PK_ECDH): Add replacement.
|
||||
|
||||
2009-08-20 Daiki Ueno <ueno@unixuser.org> (wk)
|
||||
|
||||
* cipher.h (struct DEK): Add field S2K_CACHEID.
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* cipher.h - Definitions for OpenPGP
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2006,
|
||||
* 2007 Free Software Foundation, Inc.
|
||||
* 2007, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -23,10 +23,8 @@
|
||||
#include <gcrypt.h>
|
||||
|
||||
/* Macros for compatibility with older libgcrypt versions. */
|
||||
#ifndef GCRY_PK_USAGE_CERT
|
||||
# define GCRY_PK_USAGE_CERT 4
|
||||
# define GCRY_PK_USAGE_AUTH 8
|
||||
# define GCRY_PK_USAGE_UNKN 128
|
||||
#ifndef HAVE_GCRY_PK_ECDSA
|
||||
# define GCRY_PK_ECDH 302
|
||||
#endif
|
||||
|
||||
|
||||
@ -56,8 +54,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_ECDH 18
|
||||
#define PUBKEY_ALGO_ECDSA 19
|
||||
#define PUBKEY_ALGO_ELGAMAL /* 20 */ GCRY_PK_ELG /* Elgamal encr+sign */
|
||||
|
||||
#define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */
|
||||
|
@ -245,6 +245,7 @@ parse_key (const unsigned char *data, size_t datalen,
|
||||
break;
|
||||
case 18: /* ECDH */
|
||||
npkey = 3;
|
||||
break;
|
||||
case 19: /* ECDSA */
|
||||
npkey = 2;
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user