From 46900fbd437a134bd16e5030182fb3a219cd370e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 24 Nov 1997 22:24:04 +0000 Subject: [PATCH] ElGamal funktioniert und ist default --- cipher/elgamal.c | 273 +++++++++++++++++++++++++++++++++++++--- cipher/elgamal.h | 26 ++-- cipher/primegen.c | 17 ++- cipher/rsa.c | 8 +- doc/DETAILS | 7 ++ g10/Makefile.am | 1 + g10/Makefile.in | 15 +-- g10/build-packet.c | 43 ++++++- g10/checksig.c | 96 -------------- g10/encode.c | 29 ++++- g10/free-packet.c | 91 ++++++++++---- g10/g10.c | 2 +- g10/getkey.c | 43 +++---- g10/keydb.h | 7 +- g10/keygen.c | 129 ++++++++++++++++++- g10/keyid.c | 88 +++++++++++++ g10/main.h | 12 ++ g10/mainproc.c | 33 ++++- g10/packet.h | 61 +++++++-- g10/parse-packet.c | 121 +++++++++++++++++- g10/pubkey-enc.c | 55 ++++++--- g10/seckey-cert.c | 102 +++++++++++++-- g10/seskey.c | 47 ++++++- g10/sig-check.c | 302 ++++++++++++++++++++++++--------------------- include/cipher.h | 33 ++--- include/mpi.h | 6 +- mpi/mpi-add.c | 14 +++ mpi/mpi-inv.c | 2 +- mpi/mpi-mul.c | 7 ++ tools/mpicalc.c | 2 +- util/logger.c | 10 +- 31 files changed, 1273 insertions(+), 409 deletions(-) create mode 100644 doc/DETAILS delete mode 100644 g10/checksig.c create mode 100644 g10/keyid.c diff --git a/cipher/elgamal.c b/cipher/elgamal.c index 305e1db92..b1239732d 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -28,34 +28,279 @@ #include #include "util.h" #include "mpi.h" +#include "cipher.h" #include "elgamal.h" -/**************** - * Public key operation. Encrypt INPUT with PKEY and put result into OUTPUT. - * - * - * - * Where c is OUTPUT, m is INPUT and e,n are elements of PKEY. - */ void -elg_public(MPI output, MPI input, ELG_public_key *pkey ) +elg_free_public_key( ELG_public_key *pk ) { + mpi_free( pk->p ); pk->p = NULL; + mpi_free( pk->g ); pk->g = NULL; + mpi_free( pk->y ); pk->y = NULL; +} +void +elg_free_secret_key( ELG_secret_key *sk ) +{ + mpi_free( sk->p ); sk->p = NULL; + mpi_free( sk->g ); sk->g = NULL; + mpi_free( sk->y ); sk->y = NULL; + mpi_free( sk->x ); sk->x = NULL; +} + + +static void +test_keys( ELG_public_key *pk, ELG_secret_key *sk, unsigned nbits ) +{ + MPI test = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); + MPI out1_a = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); + MPI out1_b = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); + MPI out2 = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); + + mpi_set_bytes( test, nbits, get_random_byte, 0 ); + + elg_encipher( out1_a, out1_b, test, pk ); + elg_decipher( out2, out1_a, out1_b, sk ); + if( mpi_cmp( test, out2 ) ) + log_fatal("ElGamal operation: encipher, decipher failed\n"); + + elg_sign( out1_a, out1_b, test, sk ); + if( !elg_verify( out1_a, out1_b, test, pk ) ) + log_fatal("ElGamal operation: sign, verify failed\n"); + + mpi_free( test ); + mpi_free( out1_a ); + mpi_free( out1_b ); + mpi_free( out2 ); +} + + +/**************** + * generate a random secret exponent k from prime p, so + * that k is relatively prime to p-1 + */ +static MPI +gen_k( MPI p ) +{ + MPI k = mpi_alloc_secure( mpi_get_nlimbs(p) ); + MPI temp = mpi_alloc( mpi_get_nlimbs(p) ); + MPI p_1 = mpi_copy(p); + unsigned nbits = mpi_get_nbits(p); + + if( DBG_CIPHER ) + log_debug("choosing a random k "); + mpi_sub_ui( p_1, p, 1); + for(;;) { + if( DBG_CIPHER ) + fputc('.', stderr); + mpi_set_bytes( k, nbits, get_random_byte, 1 ); + mpi_set_bit( k, nbits-1 ); /* make sure it's high (needed?) */ + if( mpi_cmp( k, p_1 ) >= 0 ) + continue; /* is not smaller than (p-1) */ + if( mpi_gcd( temp, k, p_1 ) ) + break; /* okay, k is relatively prime to (p-1) */ + } + if( DBG_CIPHER ) + fputc('\n', stderr); + mpi_free(p_1); + mpi_free(temp); + + return k; } /**************** - * Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT. - * - * - * - * Where m is OUTPUT, c is INPUT and d,n are elements of PKEY. + * Generate a key pair with a key of size NBITS + * Returns: 2 structures filles with all needed values */ void -elg_secret(MPI output, MPI input, ELG_secret_key *skey ) +elg_generate( ELG_public_key *pk, ELG_secret_key *sk, unsigned nbits ) { + MPI p; /* the prime */ + MPI g; + MPI x; /* the secret exponent */ + MPI y; + p = generate_public_prime( nbits ); + /* FIXME: check wether we shall assert that (p-1)/2 is also prime + * Schneier votes against it + */ + g = mpi_alloc_set_ui(3); + + /* select a random number */ + x = mpi_alloc_secure( nbits/BITS_PER_MPI_LIMB ); + if( DBG_CIPHER ) + log_debug("choosing a random x "); + do { + if( DBG_CIPHER ) + fputc('.', stderr); + mpi_set_bytes( x, nbits, get_random_byte, 1 ); /* fixme: should be 2 */ + mpi_set_bit( x, nbits-1 ); /* make sure it's high (needed?) */ + } while( mpi_cmp( x, p ) >= 0 ); /* x must be samller than p */ + + y = mpi_alloc(nbits/BITS_PER_MPI_LIMB); + mpi_powm( y, g, x, p ); + + if( DBG_CIPHER ) { + fputc('\n', stderr); + log_mpidump("elg p= ", p ); + log_mpidump("elg g= ", g ); + log_mpidump("elg y= ", y ); + log_mpidump("elg x= ", x ); + } + + + /* copy the stuff to the key structures */ + pk->p = mpi_copy(p); + pk->g = mpi_copy(g); + pk->y = mpi_copy(y); + sk->p = p; + sk->g = g; + sk->y = y; + sk->x = x; + + /* now we can test our keys (this should never fail!) */ + test_keys( pk, sk, nbits - 64 ); +} + + +/**************** + * Test wether the secret key is valid. + * Returns: if this is a valid key. + */ +int +elg_check_secret_key( ELG_secret_key *sk ) +{ + int rc; + MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) ); + + mpi_powm( y, sk->g, sk->x, sk->p ); + rc = !mpi_cmp( y, sk->y ); + mpi_free( y ); + return rc; +} + + +void +elg_encipher(MPI a, MPI b, MPI input, ELG_public_key *pkey ) +{ + MPI k; + + k = gen_k( pkey->p ); + mpi_powm( a, pkey->g, k, pkey->p ); + /* b = (y^k * input) mod p + * = ((y^k mod p) * (input mod p)) mod p + * and because input is < p (FIXME: check this!) + * = ((y^k mod p) * input) mod p + */ + mpi_powm( b, pkey->y, k, pkey->p ); + mpi_mulm( b, b, input, pkey->p ); + #if 0 + if( DBG_CIPHER ) { + log_mpidump("elg encipher y= ", pkey->y); + log_mpidump("elg encipher p= ", pkey->p); + log_mpidump("elg encipher k= ", k); + log_mpidump("elg encipher M= ", input); + log_mpidump("elg encipher a= ", a); + log_mpidump("elg encipher b= ", b); + } + #endif + mpi_free(k); } + +void +elg_decipher(MPI output, MPI a, MPI b, ELG_secret_key *skey ) +{ + MPI t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) ); + + /* output = b/(a^x) mod p */ + + mpi_powm( t1, a, skey->x, skey->p ); + mpi_invm( t1, t1, skey->p ); + mpi_mulm( output, b, t1, skey->p ); + #if 0 + if( DBG_CIPHER ) { + log_mpidump("elg decipher x= ", skey->x); + log_mpidump("elg decipher p= ", skey->p); + log_mpidump("elg decipher a= ", a); + log_mpidump("elg decipher b= ", b); + log_mpidump("elg decipher M= ", output); + } + #endif + mpi_free(t1); +} + + +/**************** + * Make an Elgamal signature out of INPUT + */ + +void +elg_sign(MPI a, MPI b, MPI input, ELG_secret_key *skey ) +{ + MPI k; + MPI t = mpi_alloc( mpi_get_nlimbs(a) ); + MPI inv = mpi_alloc( mpi_get_nlimbs(a) ); + MPI p_1 = mpi_copy(skey->p); + + /* + * b = (t * inv) mod (p-1) + * b = (t * inv(k,(p-1),(p-1)) mod (p-1) + * b = (((M-x*a) mod (p-1)) * inv(k,(p-1),(p-1))) mod (p-1) + * + */ + mpi_sub_ui(p_1, p_1, 1); + k = gen_k( skey->p ); + mpi_powm( a, skey->g, k, skey->p ); + mpi_mul(t, skey->x, a ); + mpi_subm(t, input, t, p_1 ); + while( mpi_is_neg(t) ) + mpi_add(t, t, p_1); + mpi_invm(inv, k, p_1 ); + mpi_mulm(b, t, inv, p_1 ); + + #if 0 + if( DBG_CIPHER ) { + log_mpidump("elg sign p= ", skey->p); + log_mpidump("elg sign g= ", skey->g); + log_mpidump("elg sign y= ", skey->y); + log_mpidump("elg sign x= ", skey->x); + log_mpidump("elg sign k= ", k); + log_mpidump("elg sign M= ", input); + log_mpidump("elg sign a= ", a); + log_mpidump("elg sign b= ", b); + } + #endif + mpi_free(k); + mpi_free(t); + mpi_free(inv); + mpi_free(p_1); +} + + +/**************** + * Returns true if the signature composed from A and B is valid. + */ +int +elg_verify(MPI a, MPI b, MPI input, ELG_public_key *pkey ) +{ + int rc; + MPI t1 = mpi_alloc( mpi_get_nlimbs(a) ); + MPI t2 = mpi_alloc( mpi_get_nlimbs(a) ); + + mpi_powm( t1, pkey->y, a, pkey->p ); + mpi_powm( t2, a, b, pkey->p ); + mpi_mulm( t1, t1, t2, pkey->p ); + + mpi_powm( t2, pkey->g, input, pkey->p ); + + rc = !mpi_cmp( t1, t2 ); + + mpi_free(t1); + mpi_free(t2); + return rc; +} + diff --git a/cipher/elgamal.h b/cipher/elgamal.h index 3b6317599..e93b49e59 100644 --- a/cipher/elgamal.h +++ b/cipher/elgamal.h @@ -23,23 +23,27 @@ #include "mpi.h" typedef struct { - MPI e; /* exponent */ - MPI n; /* modulus */ + MPI p; /* prime */ + MPI g; /* group generator */ + MPI y; /* g^x mod p */ } ELG_public_key; typedef struct { - MPI e; /* public exponent */ - MPI n; /* public modulus */ - MPI p; /* prime p. */ - MPI q; /* prime q. */ - MPI d; /* exponent */ - MPI u; /* inverse of p mod q. */ + MPI p; /* prime */ + MPI g; /* group generator */ + MPI y; /* g^x mod p */ + MPI x; /* secret exponent */ } ELG_secret_key; -void elg_public(MPI output, MPI input, ELG_public_key *skey ); -void elg_secret(MPI output, MPI input, ELG_secret_key *skey ); - +void elg_free_public_key( ELG_public_key *pk ); +void elg_free_secret_key( ELG_secret_key *sk ); +void elg_generate( ELG_public_key *pk, ELG_secret_key *sk, unsigned nbits ); +int elg_check_secret_key( ELG_secret_key *sk ); +void elg_encipher(MPI a, MPI b, MPI input, ELG_public_key *pkey ); +void elg_decipher(MPI output, MPI a, MPI b, ELG_secret_key *skey ); +void elg_sign(MPI a, MPI b, MPI input, ELG_secret_key *skey); +int elg_verify(MPI a, MPI b, MPI input, ELG_public_key *pkey); #endif /*G10_ELGAMAL_H*/ diff --git a/cipher/primegen.c b/cipher/primegen.c index 07d83d831..0173b3d0b 100644 --- a/cipher/primegen.c +++ b/cipher/primegen.c @@ -29,13 +29,26 @@ static int no_of_small_prime_numbers; static int rabin_miller( MPI n ); +static MPI gen_prime( unsigned nbits, int mode ); /**************** * Generate a prime number (stored in secure memory) */ MPI -generate_random_prime( unsigned nbits ) +generate_secret_prime( unsigned nbits ) +{ + return gen_prime( nbits, 1 ); +} + +MPI +generate_public_prime( unsigned nbits ) +{ + return gen_prime( nbits, 0 ); +} + +static MPI +gen_prime( unsigned nbits, int secret ) { unsigned nlimbs; @@ -61,7 +74,7 @@ generate_random_prime( unsigned nbits ) val_3 = mpi_alloc( nlimbs ); mpi_set_ui(val_3, 3); result = mpi_alloc( nlimbs ); - prime = mpi_alloc_secure( nlimbs ); + prime = secret? mpi_alloc_secure( nlimbs ): mpi_alloc( nlimbs ); count1 = count2 = 0; /* enter (endless) loop */ for(;;) { diff --git a/cipher/rsa.c b/cipher/rsa.c index b2694ed5e..a1f08457b 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -95,8 +95,8 @@ rsa_generate( RSA_public_key *pk, RSA_secret_key *sk, unsigned nbits ) MPI f; /* select two (very secret) primes */ - p = generate_random_prime( nbits / 2 ); - q = generate_random_prime( nbits / 2 ); + p = generate_secret_prime( nbits / 2 ); + q = generate_secret_prime( nbits / 2 ); if( mpi_cmp( p, q ) > 0 ) /* p shall be smaller than q (for calc of u)*/ mpi_swap(p,q); /* calculate Euler totient: phi = (p-1)(q-1) */ @@ -120,10 +120,10 @@ rsa_generate( RSA_public_key *pk, RSA_secret_key *sk, unsigned nbits ) mpi_add_ui( e, e, 2); /* calculate the secret key d = e^1 mod phi */ d = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); - mpi_inv_mod(d, e, f ); + mpi_invm(d, e, f ); /* calculate the inverse of p and q (used for chinese remainder theorem)*/ u = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); - mpi_inv_mod(u, p, q ); + mpi_invm(u, p, q ); if( DBG_CIPHER ) { log_mpidump(" p= ", p ); diff --git a/doc/DETAILS b/doc/DETAILS new file mode 100644 index 000000000..3b447c79b --- /dev/null +++ b/doc/DETAILS @@ -0,0 +1,7 @@ + + + * For packet version 3 we calculate the keyids this way: + RSA := low 64 bits of n + ELGAMAL := low 64 bits of y + + diff --git a/g10/Makefile.am b/g10/Makefile.am index a8d13eaec..bb0b96552 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -21,6 +21,7 @@ g10_SOURCES = g10.c \ cipher.c \ options.h \ openfile.c \ + keyid.c \ packet.h \ parse-packet.c \ passphrase.c \ diff --git a/g10/Makefile.in b/g10/Makefile.in index d7b08551d..651fdf2dd 100644 --- a/g10/Makefile.in +++ b/g10/Makefile.in @@ -59,6 +59,7 @@ g10_SOURCES = g10.c \ cipher.c \ options.h \ openfile.c \ + keyid.c \ packet.h \ parse-packet.c \ passphrase.c \ @@ -90,7 +91,7 @@ COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) LINK = $(CC) $(LDFLAGS) -o $@ g10_OBJECTS = g10.o build-packet.o compress.o encode.o encr-data.o \ free-packet.o getkey.o keygen.o mainproc.o armor.o mdfilter.o cipher.o \ -openfile.o parse-packet.o passphrase.o plaintext.o pubkey-enc.o \ +openfile.o keyid.o parse-packet.o passphrase.o plaintext.o pubkey-enc.o \ seckey-cert.o seskey.o sign.o comment.o sig-check.o EXTRA_g10_SOURCES = g10_LDADD = $(LDADD) @@ -111,12 +112,12 @@ $(srcdir)/.deps/cipher.P $(srcdir)/.deps/comment.P \ $(srcdir)/.deps/compress.P $(srcdir)/.deps/encode.P \ $(srcdir)/.deps/encr-data.P $(srcdir)/.deps/free-packet.P \ $(srcdir)/.deps/g10.P $(srcdir)/.deps/getkey.P $(srcdir)/.deps/keygen.P \ -$(srcdir)/.deps/mainproc.P $(srcdir)/.deps/mdfilter.P \ -$(srcdir)/.deps/openfile.P $(srcdir)/.deps/parse-packet.P \ -$(srcdir)/.deps/passphrase.P $(srcdir)/.deps/plaintext.P \ -$(srcdir)/.deps/pubkey-enc.P $(srcdir)/.deps/seckey-cert.P \ -$(srcdir)/.deps/seskey.P $(srcdir)/.deps/sig-check.P \ -$(srcdir)/.deps/sign.P +$(srcdir)/.deps/keyid.P $(srcdir)/.deps/mainproc.P \ +$(srcdir)/.deps/mdfilter.P $(srcdir)/.deps/openfile.P \ +$(srcdir)/.deps/parse-packet.P $(srcdir)/.deps/passphrase.P \ +$(srcdir)/.deps/plaintext.P $(srcdir)/.deps/pubkey-enc.P \ +$(srcdir)/.deps/seckey-cert.P $(srcdir)/.deps/seskey.P \ +$(srcdir)/.deps/sig-check.P $(srcdir)/.deps/sign.P SOURCES = $(g10_SOURCES) OBJECTS = $(g10_OBJECTS) diff --git a/g10/build-packet.c b/g10/build-packet.c index 5bda607b9..c0ddb9e24 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -163,7 +163,12 @@ do_pubkey_cert( IOBUF out, int ctb, PKT_pubkey_cert *pkc ) write_32(a, pkc->timestamp ); write_16(a, pkc->valid_days ); iobuf_put(a, pkc->pubkey_algo ); - if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) { + if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + mpi_encode(a, pkc->d.elg.p ); + mpi_encode(a, pkc->d.elg.g ); + mpi_encode(a, pkc->d.elg.y ); + } + else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) { mpi_encode(a, pkc->d.rsa.rsa_n ); mpi_encode(a, pkc->d.rsa.rsa_e ); } @@ -191,7 +196,26 @@ do_seckey_cert( IOBUF out, int ctb, PKT_seckey_cert *skc ) write_32(a, skc->timestamp ); write_16(a, skc->valid_days ); iobuf_put(a, skc->pubkey_algo ); - if( skc->pubkey_algo == PUBKEY_ALGO_RSA ) { + if( skc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + mpi_encode(a, skc->d.elg.p ); + mpi_encode(a, skc->d.elg.g ); + mpi_encode(a, skc->d.elg.y ); + iobuf_put(a, skc->d.elg.protect_algo ); + skc->d.elg.calc_csum = 0; + if( skc->d.elg.protect_algo ) { + assert( skc->d.elg.is_protected == 1 ); + assert( skc->d.elg.protect_algo == CIPHER_ALGO_BLOWFISH ); + iobuf_write(a, skc->d.elg.protect.blowfish.iv, 8 ); + mpi_write_csum(a, (byte*)skc->d.elg.x, &skc->d.elg.calc_csum ); + } + else { /* not protected */ + assert( !skc->d.elg.is_protected ); + mpi_encode_csum(a, skc->d.elg.x, &skc->d.elg.calc_csum ); + } + + write_16(a, skc->d.elg.calc_csum ); + } + else if( skc->pubkey_algo == PUBKEY_ALGO_RSA ) { mpi_encode(a, skc->d.rsa.rsa_n ); mpi_encode(a, skc->d.rsa.rsa_e ); iobuf_put(a, skc->d.rsa.protect_algo ); @@ -240,7 +264,11 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ) write_32(a, enc->keyid[0] ); write_32(a, enc->keyid[1] ); iobuf_put(a,enc->pubkey_algo ); - if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) { + if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + mpi_encode(a, enc->d.elg.a ); + mpi_encode(a, enc->d.elg.b ); + } + else if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) { mpi_encode(a, enc->d.rsa.rsa_integer ); } else { @@ -342,7 +370,14 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig ) write_32(a, sig->keyid[0] ); write_32(a, sig->keyid[1] ); iobuf_put(a, sig->pubkey_algo ); - if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) { + if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + iobuf_put(a, sig->d.elg.digest_algo ); + iobuf_put(a, sig->d.elg.digest_start[0] ); + iobuf_put(a, sig->d.elg.digest_start[1] ); + mpi_encode(a, sig->d.elg.a ); + mpi_encode(a, sig->d.elg.b ); + } + else if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) { iobuf_put(a, sig->d.rsa.digest_algo ); iobuf_put(a, sig->d.rsa.digest_start[0] ); iobuf_put(a, sig->d.rsa.digest_start[1] ); diff --git a/g10/checksig.c b/g10/checksig.c deleted file mode 100644 index 7f00d5801..000000000 --- a/g10/checksig.c +++ /dev/null @@ -1,96 +0,0 @@ -/* checksig.c - check a signature - * Copyright (c) 1997 by Werner Koch (dd9jn) - * - * This file is part of G10. - * - * G10 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 2 of the License, or - * (at your option) any later version. - * - * G10 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include -#include - -#include "packet.h" -#include "iobuf.h" -#include "memory.h" -#include "util.h" -#include "cipher.h" - -static void -usage(void) -{ - fprintf(stderr, "usage: checksig textfile sigfile\n"); - exit(1); -} - - -int -main(int argc, char **argv) -{ - IOBUF a; - PACKET pkt; - PKT_signature *sig; - int rc, result, c; - FILE *fp; - MD5HANDLE md5; - - if( argc != 3 ) - usage(); - argc--; argv++; - - - if( !(a = iobuf_open(argv[1])) ) - log_fatal("can't open '%s'\n", argv[1]); - - init_packet(&pkt); - while( (rc=parse_packet(a, &pkt)) != -1 ) { - if( !rc && pkt.pkttype == PKT_SECKEY_ENC ) { - sig = pkt.pkt.signature; - printf("sig: keyid=%08lX%08lX: ", sig->keyid[0], sig->keyid[1] ); - if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) { - if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) { - if( !(fp = fopen(*argv, "rb")) ) - log_fatal("can't open '%s'\n", *argv); - md5 = md5_open(0); - while( (c=getc(fp)) != EOF ) - md5_putchar(md5, c ); - fclose(fp); - result = md5_signature_check( sig, md5 ); - md5_close(md5); - } - else - result = G10ERR_DIGEST_ALGO; - } - else - result = G10ERR_PUBKEY_ALGO; - - if( !result ) - fputs( "signature is good", stdout ); - else if( result == G10ERR_DIGEST_ALGO ) - printf( "Unknown digest algorithm %d", sig->d.rsa.digest_algo); - else if( result == G10ERR_PUBKEY_ALGO ) - printf( "Unknown pubkey algorithm %d", sig->pubkey_algo); - else - fputs( g10_errstr(result), stdout); - putchar('\n'); - } - free_packet(&pkt); - } - - iobuf_close(a); - return 0; -} - - diff --git a/g10/encode.c b/g10/encode.c index 9ef2c1099..eb4875de9 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -226,10 +226,35 @@ encode_crypt( const char *filename, STRLIST remusr ) /* build the pubkey packet */ enc = m_alloc_clear( sizeof *enc ); enc->pubkey_algo = pkc->pubkey_algo; - if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) { + if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + ELG_public_key pkey; + MPI frame; + + enc->d.elg.a = mpi_alloc( mpi_get_nlimbs(pkc->d.elg.p) ); + enc->d.elg.b = mpi_alloc( mpi_get_nlimbs(pkc->d.elg.p) ); + keyid_from_pkc( pkc, enc->keyid ); + frame = encode_session_key( cfx.dek, mpi_get_nbits(pkc->d.elg.p) ); + pkey.p = pkc->d.elg.p; + pkey.g = pkc->d.elg.g; + pkey.y = pkc->d.elg.y; + if( DBG_CIPHER ) + log_mpidump("Plain DEK frame: ", frame); + elg_encipher( enc->d.elg.a, enc->d.elg.b, frame, &pkey); + mpi_free( frame ); + if( DBG_CIPHER ) { + log_mpidump("Encry DEK a: ", enc->d.elg.a ); + log_mpidump(" DEK b: ", enc->d.elg.b ); + } + if( opt.verbose ) { + ustr = get_user_id_string( enc->keyid ); + log_info("ElGamal enciphered for: %s\n", ustr ); + m_free(ustr); + } + } + else if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) { RSA_public_key pkey; - mpi_get_keyid( pkc->d.rsa.rsa_n, enc->keyid ); + keyid_from_pkc( pkc, enc->keyid ); enc->d.rsa.rsa_integer = encode_session_key( cfx.dek, mpi_get_nbits(pkc->d.rsa.rsa_n) ); pkey.n = pkc->d.rsa.rsa_n; diff --git a/g10/free-packet.c b/g10/free-packet.c index 7d6eb4aaa..3103ee49e 100644 --- a/g10/free-packet.c +++ b/g10/free-packet.c @@ -35,22 +35,39 @@ void free_pubkey_enc( PKT_pubkey_enc *enc ) { - mpi_free( enc->d.rsa.rsa_integer ); + if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + mpi_free( enc->d.elg.a ); + mpi_free( enc->d.elg.b ); + } + else if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) + mpi_free( enc->d.rsa.rsa_integer ); m_free(enc); } void free_seckey_enc( PKT_signature *enc ) { - mpi_free( enc->d.rsa.rsa_integer ); + if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + mpi_free( enc->d.elg.a ); + mpi_free( enc->d.elg.b ); + } + else if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) + mpi_free( enc->d.rsa.rsa_integer ); m_free(enc); } void free_pubkey_cert( PKT_pubkey_cert *cert ) { - mpi_free( cert->d.rsa.rsa_n ); - mpi_free( cert->d.rsa.rsa_e ); + if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + mpi_free( cert->d.elg.p ); + mpi_free( cert->d.elg.g ); + mpi_free( cert->d.elg.y ); + } + else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) { + mpi_free( cert->d.rsa.rsa_n ); + mpi_free( cert->d.rsa.rsa_e ); + } md5_close( cert->mfx.md5 ); rmd160_close( cert->mfx.rmd160 ); m_free(cert); @@ -62,8 +79,15 @@ copy_pubkey_cert( PKT_pubkey_cert *d, PKT_pubkey_cert *s ) if( !d ) d = m_alloc(sizeof *d); memcpy( d, s, sizeof *d ); - d->d.rsa.rsa_n = mpi_copy( s->d.rsa.rsa_n ); - d->d.rsa.rsa_e = mpi_copy( s->d.rsa.rsa_e ); + if( s->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + d->d.elg.p = mpi_copy( s->d.elg.p ); + d->d.elg.g = mpi_copy( s->d.elg.g ); + d->d.elg.y = mpi_copy( s->d.elg.y ); + } + else if( s->pubkey_algo == PUBKEY_ALGO_RSA ) { + d->d.rsa.rsa_n = mpi_copy( s->d.rsa.rsa_n ); + d->d.rsa.rsa_e = mpi_copy( s->d.rsa.rsa_e ); + } d->mfx.md5 = NULL; d->mfx.rmd160 =NULL; return d; @@ -72,19 +96,30 @@ copy_pubkey_cert( PKT_pubkey_cert *d, PKT_pubkey_cert *s ) void free_seckey_cert( PKT_seckey_cert *cert ) { - mpi_free( cert->d.rsa.rsa_n ); - mpi_free( cert->d.rsa.rsa_e ); - if( cert->d.rsa.is_protected ) { - m_free( cert->d.rsa.rsa_d ); - m_free( cert->d.rsa.rsa_p ); - m_free( cert->d.rsa.rsa_q ); - m_free( cert->d.rsa.rsa_u ); + if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + mpi_free( cert->d.elg.p ); + mpi_free( cert->d.elg.g ); + mpi_free( cert->d.elg.y ); + if( cert->d.rsa.is_protected ) + m_free( cert->d.elg.x ); + else + mpi_free( cert->d.elg.x ); } - else { - mpi_free( cert->d.rsa.rsa_d ); - mpi_free( cert->d.rsa.rsa_p ); - mpi_free( cert->d.rsa.rsa_q ); - mpi_free( cert->d.rsa.rsa_u ); + else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) { + mpi_free( cert->d.rsa.rsa_n ); + mpi_free( cert->d.rsa.rsa_e ); + if( cert->d.rsa.is_protected ) { + m_free( cert->d.rsa.rsa_d ); + m_free( cert->d.rsa.rsa_p ); + m_free( cert->d.rsa.rsa_q ); + m_free( cert->d.rsa.rsa_u ); + } + else { + mpi_free( cert->d.rsa.rsa_d ); + mpi_free( cert->d.rsa.rsa_p ); + mpi_free( cert->d.rsa.rsa_q ); + mpi_free( cert->d.rsa.rsa_u ); + } } m_free(cert); } @@ -95,12 +130,20 @@ copy_seckey_cert( PKT_seckey_cert *d, PKT_seckey_cert *s ) if( !d ) d = m_alloc(sizeof *d); memcpy( d, s, sizeof *d ); - d->d.rsa.rsa_n = mpi_copy( s->d.rsa.rsa_n ); - d->d.rsa.rsa_e = mpi_copy( s->d.rsa.rsa_e ); - d->d.rsa.rsa_d = mpi_copy( s->d.rsa.rsa_d ); - d->d.rsa.rsa_p = mpi_copy( s->d.rsa.rsa_p ); - d->d.rsa.rsa_q = mpi_copy( s->d.rsa.rsa_q ); - d->d.rsa.rsa_u = mpi_copy( s->d.rsa.rsa_u ); + if( s->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + d->d.elg.p = mpi_copy( s->d.elg.p ); + d->d.elg.g = mpi_copy( s->d.elg.g ); + d->d.elg.y = mpi_copy( s->d.elg.y ); + d->d.elg.x = mpi_copy( s->d.elg.x ); + } + else if( s->pubkey_algo == PUBKEY_ALGO_RSA ) { + d->d.rsa.rsa_n = mpi_copy( s->d.rsa.rsa_n ); + d->d.rsa.rsa_e = mpi_copy( s->d.rsa.rsa_e ); + d->d.rsa.rsa_d = mpi_copy( s->d.rsa.rsa_d ); + d->d.rsa.rsa_p = mpi_copy( s->d.rsa.rsa_p ); + d->d.rsa.rsa_q = mpi_copy( s->d.rsa.rsa_q ); + d->d.rsa.rsa_u = mpi_copy( s->d.rsa.rsa_u ); + } return d; } diff --git a/g10/g10.c b/g10/g10.c index 496fda348..5235d0f6e 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -220,7 +220,7 @@ main( int argc, char **argv ) case aPrimegen: if( argc ) usage(1); - mpi_print( stdout, generate_random_prime( pargs.r.ret_int ), 1); + mpi_print( stdout, generate_public_prime( pargs.r.ret_int ), 1); putchar('\n'); break; diff --git a/g10/getkey.c b/g10/getkey.c index 8ca462210..4aea8e7ca 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -85,8 +85,9 @@ cache_pubkey_cert( PKT_pubkey_cert *pkc ) pkc_cache_entry_t ce; u32 keyid[2]; - if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) { - mpi_get_keyid( pkc->d.rsa.rsa_n, keyid ); + if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL + || pkc->pubkey_algo == PUBKEY_ALGO_RSA ) { + keyid_from_pkc( pkc, keyid ); } else return; /* don't know how to get the keyid */ @@ -252,13 +253,11 @@ get_pubkey_by_name( PKT_pubkey_cert *pkc, const char *name ) * Get a secret key and store it into skey */ int -get_seckey( RSA_secret_key *skey, u32 *keyid ) +get_seckey( PKT_seckey_cert *skc, u32 *keyid ) { int rc=0; - PKT_seckey_cert skc; - memset( &skc, 0, sizeof skc ); - if( !(rc=scan_secret_keyring( &skc, keyid, NULL, "../keys/secring.g10" ) ) ) + if( !(rc=scan_secret_keyring( skc, keyid, NULL, "../keys/secring.g10" ) ) ) goto found; /* fixme: look at other places */ goto leave; @@ -267,22 +266,10 @@ get_seckey( RSA_secret_key *skey, u32 *keyid ) /* get the secret key (this may prompt for a passprase to * unlock the secret key */ - if( (rc = check_secret_key( &skc )) ) + if( (rc = check_secret_key( skc )) ) goto leave; - if( skc.pubkey_algo != PUBKEY_ALGO_RSA ) { - rc = G10ERR_PUBKEY_ALGO; /* unsupport algorithm */ - goto leave; - } - /* copy the stuff to SKEY. skey is then the owner */ - skey->e = skc.d.rsa.rsa_e; - skey->n = skc.d.rsa.rsa_n; - skey->p = skc.d.rsa.rsa_p; - skey->q = skc.d.rsa.rsa_q; - skey->d = skc.d.rsa.rsa_d; - skey->u = skc.d.rsa.rsa_u; leave: - memset( &skc, 0, sizeof skc ); return rc; } @@ -357,8 +344,9 @@ scan_keyring( PKT_pubkey_cert *pkc, u32 *keyid, } else if( keyid && pkt.pkttype == PKT_PUBKEY_CERT ) { switch( pkt.pkt.pubkey_cert->pubkey_algo ) { + case PUBKEY_ALGO_ELGAMAL: case PUBKEY_ALGO_RSA: - mpi_get_keyid( pkt.pkt.pubkey_cert->d.rsa.rsa_n , akeyid ); + keyid_from_pkc( pkt.pkt.pubkey_cert, akeyid ); if( akeyid[0] == keyid[0] && akeyid[1] == keyid[1] ) { copy_pubkey_cert( pkc, pkt.pkt.pubkey_cert ); found++; @@ -406,8 +394,9 @@ scan_keyring( PKT_pubkey_cert *pkc, u32 *keyid, log_error("Ooops: no pubkey for userid '%.*s'\n", pkt.pkt.user_id->len, pkt.pkt.user_id->name); else { - if( last_pk->pubkey_algo == PUBKEY_ALGO_RSA ) { - mpi_get_keyid( last_pk->d.rsa.rsa_n , akeyid ); + if( last_pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL + || last_pk->pubkey_algo == PUBKEY_ALGO_RSA ) { + keyid_from_pkc( last_pk, akeyid ); cache_user_id( pkt.pkt.user_id, akeyid ); } cache_pubkey_cert( last_pk ); @@ -462,8 +451,9 @@ scan_secret_keyring( PKT_seckey_cert *skc, u32 *keyid, } else if( keyid && pkt.pkttype == PKT_SECKEY_CERT ) { switch( pkt.pkt.seckey_cert->pubkey_algo ) { + case PUBKEY_ALGO_ELGAMAL: case PUBKEY_ALGO_RSA: - mpi_get_keyid( pkt.pkt.seckey_cert->d.rsa.rsa_n , akeyid ); + keyid_from_skc( pkt.pkt.seckey_cert, akeyid ); if( akeyid[0] == keyid[0] && akeyid[1] == keyid[1] ) { copy_seckey_cert( skc, pkt.pkt.seckey_cert ); found++; @@ -510,9 +500,10 @@ scan_secret_keyring( PKT_seckey_cert *skc, u32 *keyid, log_error("Ooops: no seckey for userid '%.*s'\n", pkt.pkt.user_id->len, pkt.pkt.user_id->name); else { - if( last_pk->pubkey_algo == PUBKEY_ALGO_RSA ) { - mpi_get_keyid( last_pk->d.rsa.rsa_n , akeyid ); - cache_user_id( pkt.pkt.user_id, akeyid ); + if( last_pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL + || last_pk->pubkey_algo == PUBKEY_ALGO_RSA ) { + keyid_from_skc( last_pk, akeyid ); + cache_user_id( pkt.pkt.user_id, akeyid ); } } } diff --git a/g10/keydb.h b/g10/keydb.h index 62c6abe36..ae3aeb83f 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -22,6 +22,7 @@ #define G10_KEYDB_H #include "types.h" +#include "packet.h" #include "cipher.h" @@ -35,11 +36,13 @@ void cache_pubkey_cert( PKT_pubkey_cert *pkc ); void cache_user_id( PKT_user_id *uid, u32 *keyid ); int get_pubkey( PKT_pubkey_cert *pkc, u32 *keyid ); int get_pubkey_by_name( PKT_pubkey_cert *pkc, const char *name ); -int get_seckey( RSA_secret_key *skey, u32 *keyid ); +int get_seckey( PKT_seckey_cert *skc, u32 *keyid ); int get_seckey_by_name( PKT_seckey_cert *skc, const char *name ); char*get_user_id_string( u32 *keyid ); - +/*-- keyid.c --*/ +u32 keyid_from_skc( PKT_seckey_cert *skc, u32 *keyid ); +u32 keyid_from_pkc( PKT_pubkey_cert *pkc, u32 *keyid ); diff --git a/g10/keygen.c b/g10/keygen.c index 866824c1c..ff3715999 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -31,6 +31,13 @@ #include "ttyio.h" #include "options.h" +#if 0 + #define TEST_ALGO 1 + #define TEST_NBITS 256 + #define TEST_UID "Karl Test" +#endif + + static int answer_is_yes( const char *s ) { @@ -62,6 +69,7 @@ write_uid( IOBUF out, const char *s ) } +#ifdef HAVE_RSA_CIPHER static int gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io) { @@ -114,6 +122,61 @@ gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io) free_packet(&pkt2); return rc; } +#endif /*HAVE_RSA_CIPHER*/ + +static int +gen_elg(unsigned nbits, IOBUF pub_io, IOBUF sec_io) +{ + int rc; + PACKET pkt1, pkt2; + PKT_seckey_cert *skc; + PKT_pubkey_cert *pkc; + ELG_public_key pk; + ELG_secret_key sk; + + elg_generate( &pk, &sk, nbits ); + + skc = m_alloc( sizeof *skc ); + pkc = m_alloc( sizeof *pkc ); + skc->timestamp = pkc->timestamp = make_timestamp(); + skc->valid_days = pkc->valid_days = 0; /* fixme: make it configurable*/ + skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_ELGAMAL; + memset(&pkc->mfx, 0, sizeof pkc->mfx); + pkc->d.elg.p = pk.p; + pkc->d.elg.g = pk.g; + pkc->d.elg.y = pk.y; + skc->d.elg.p = sk.p; + skc->d.elg.g = sk.g; + skc->d.elg.y = sk.y; + skc->d.elg.x = sk.x; + + skc->d.elg.calc_csum = 0; + skc->d.elg.is_protected = 0; /* FIXME!!! */ + skc->d.elg.protect_algo = 0; /* should be blowfish */ + /*memcpy(skc->d.elg.protect.blowfish.iv,"12345678", 8);*/ + + init_packet(&pkt1); + pkt1.pkttype = PKT_PUBKEY_CERT; + pkt1.pkt.pubkey_cert = pkc; + init_packet(&pkt2); + pkt2.pkttype = PKT_SECKEY_CERT; + pkt2.pkt.seckey_cert = skc; + + if( (rc = build_packet( pub_io, &pkt1 )) ) { + log_error("build pubkey_cert packet failed: %s\n", g10_errstr(rc) ); + goto leave; + } + if( (rc = build_packet( sec_io, &pkt2 )) ) { + log_error("build seckey_cert packet failed: %s\n", g10_errstr(rc) ); + goto leave; + } + + leave: + free_packet(&pkt1); + free_packet(&pkt2); + return rc; +} + /**************** @@ -130,19 +193,62 @@ generate_keypair() IOBUF pub_io = NULL; IOBUF sec_io = NULL; int rc; + int algo; + const char *algo_name; + #ifndef TEST_ALGO if( opt.batch || opt.answer_yes || opt.answer_no ) log_fatal("Key generation can only be used in interactive mode\n"); - tty_printf("About to generate a new keypair:\n" + tty_printf("Please select the algorithm to use:\n" + " (1) ElGamal is the suggested one.\n" + #ifdef HAVE_RSA_CIPHER + " (2) RSA cannot be used inthe U.S.\n" + #endif + ); + #endif + + for(;;) { + #ifdef TEST_ALGO + algo = TEST_ALGO; + #else + answer = tty_get("Your selection? (1,2) "); + tty_kill_prompt(); + algo = *answer? atoi(answer): 1; + m_free(answer); + #endif + if( algo == 1 ) { + algo = PUBKEY_ALGO_ELGAMAL; + algo_name = "ElGamal"; + break; + } + #ifdef HAVE_RSA_CIPHER + else if( algo == 2 ) { + algo = PUBKEY_ALGO_RSA; + algo_name = "RSA"; + break; + } + #endif + } + + + + tty_printf("About to generate a new %s keypair.\n" + #ifndef TEST_NBITS " minimum keysize is 768 bits\n" " default keysize is 1024 bits\n" - " highest suggested keysize is 2048 bits\n" ); + " highest suggested keysize is 2048 bits\n" + #endif + , algo_name ); for(;;) { - answer = tty_get("What keysize do you want? (256) "); + #ifdef TEST_NBITS + nbits = TEST_NBITS; + #else + answer = tty_get("What keysize do you want? (1024) "); tty_kill_prompt(); - nbits = *answer? atoi(answer): 256; + nbits = *answer? atoi(answer): 1024; m_free(answer); + #endif if( nbits < 128 ) /* FIXME: change this to 768 */ tty_printf("keysize too small; please select a larger one\n"); else if( nbits > 2048 ) { @@ -167,6 +273,11 @@ generate_keypair() nbits = ((nbits + 31) / 32) * 32; tty_printf("rounded up to %u bits\n", nbits ); } + + #ifdef TEST_UID + uid = m_alloc(strlen(TEST_UID)+1); + strcpy(uid, TEST_UID); + #else tty_printf( "\nYou need a User-ID to identify your key; please use your name and your\n" "email address in this suggested format:\n" " \"Heinrich Heine \n" ); @@ -189,6 +300,7 @@ generate_keypair() m_free(answer); } } + #endif /* now check wether we a are allowed to write the keyrings */ if( !(rc=overwrite_filep( pub_fname )) ) { if( !(pub_io = iobuf_create( pub_fname )) ) @@ -226,7 +338,14 @@ generate_keypair() write_comment( pub_io, "#public key created by G10 pre-release " VERSION ); write_comment( sec_io, "#secret key created by G10 pre-release " VERSION ); - gen_rsa(nbits, pub_io, sec_io); + if( algo == PUBKEY_ALGO_ELGAMAL ) + gen_elg(nbits, pub_io, sec_io); + #ifdef HAVE_RSA_CIPHER + else if( algo == PUBKEY_ALGO_RSA ) + gen_rsa(nbits, pub_io, sec_io); + #endif + else + log_bug(NULL); write_uid(pub_io, uid ); write_uid(sec_io, uid ); m_free(uid); diff --git a/g10/keyid.c b/g10/keyid.c new file mode 100644 index 000000000..0e2dad93b --- /dev/null +++ b/g10/keyid.c @@ -0,0 +1,88 @@ +/* keyid.c - jeyid and fingerprint handling + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 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 2 of the License, or + * (at your option) any later version. + * + * G10 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include +#include +#include +#include +#include "util.h" +#include "main.h" +#include "packet.h" +#include "options.h" +#include "mpi.h" +#include "keydb.h" + + + + +/**************** + * Get the keyid from the secret key certificate and put it into keyid + * if this is not NULL. Return the 32 low bits of the keyid. + */ +u32 +keyid_from_skc( PKT_seckey_cert *skc, u32 *keyid ) +{ + u32 lowbits; + u32 dummy_keyid[2]; + + if( !keyid ) + keyid = dummy_keyid; + + if( skc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + lowbits = mpi_get_keyid( skc->d.elg.y, keyid ); + } + else if( skc->pubkey_algo == PUBKEY_ALGO_RSA ) { + lowbits = mpi_get_keyid( skc->d.rsa.rsa_n, keyid ); + } + else + log_bug(NULL); + + return lowbits; +} + + +/**************** + * Get the keyid from the public key certificate and put it into keyid + * if this is not NULL. Return the 32 low bits of the keyid. + */ +u32 +keyid_from_pkc( PKT_pubkey_cert *pkc, u32 *keyid ) +{ + u32 lowbits; + u32 dummy_keyid[2]; + + if( !keyid ) + keyid = dummy_keyid; + + if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + lowbits = mpi_get_keyid( pkc->d.elg.y, keyid ); + } + else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) { + lowbits = mpi_get_keyid( pkc->d.rsa.rsa_n, keyid ); + } + else + log_bug(NULL); + + return lowbits; +} + + diff --git a/g10/main.h b/g10/main.h index 9d0f07a89..708563427 100644 --- a/g10/main.h +++ b/g10/main.h @@ -21,6 +21,11 @@ #define G10_MAIN_H #include "types.h" #include "iobuf.h" +#include "cipher.h" + +#define DEFAULT_CIPHER_ALGO CIPHER_ALGO_BLOWFISH +#define DEFAULT_PUBKEY_ALGO PUBKEY_ALGO_ELGAMAL +#define DEFAULT_DIGEST_ALGO DIGEST_ALGO_RMD160 /*-- encode.c --*/ int encode_symmetric( const char *filename ); @@ -37,4 +42,11 @@ void generate_keypair(void); int overwrite_filep( const char *fname ); IOBUF open_outfile( const char *fname ); +/*-- seskey.c --*/ +void make_session_key( DEK *dek ); +MPI encode_session_key( DEK *dek, unsigned nbits ); +MPI encode_rmd160_value( byte *md, unsigned len, unsigned nbits ); +MPI encode_md5_value( byte *md, unsigned len, unsigned nbits ); + + #endif /*G10_MAIN_H*/ diff --git a/g10/mainproc.c b/g10/mainproc.c index 45cb8fbbd..6c7e32f3c 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -30,6 +30,7 @@ #include "cipher.h" #include "keydb.h" #include "filter.h" +#include "main.h" static int opt_list=1; /* and list the data packets to stdout */ @@ -122,8 +123,9 @@ proc_packets( IOBUF a ) puts(" (orphaned)"); } if( pkt->pkc_parent ) { - if( pkt->pkc_parent->pubkey_algo == PUBKEY_ALGO_RSA ) { - mpi_get_keyid( pkt->pkc_parent->d.rsa.rsa_n, keyid ); + if( pkt->pkc_parent->pubkey_algo == PUBKEY_ALGO_ELGAMAL + || pkt->pkc_parent->pubkey_algo == PUBKEY_ALGO_RSA ) { + keyid_from_pkc( pkt->pkc_parent, keyid ); cache_user_id( pkt->pkt.user_id, keyid ); } } @@ -158,6 +160,30 @@ proc_packets( IOBUF a ) result = -1; printstr(lvl0, "sig: from %s\n", ustr ); } + else if(sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + md_handle.algo = sig->d.elg.digest_algo; + if( sig->d.elg.digest_algo == DIGEST_ALGO_RMD160 ) { + if( sig->sig_class == 0x00 ) + md_handle.u.rmd = rmd160_copy( mfx.rmd160 ); + else { + md_handle.u.rmd = rmd160_copy(pkt->pkc_parent->mfx.rmd160); + rmd160_write(md_handle.u.rmd, pkt->user_parent->name, + pkt->user_parent->len); + } + result = signature_check( sig, md_handle ); + rmd160_close(md_handle.u.rmd); + } + else if( sig->d.elg.digest_algo == DIGEST_ALGO_MD5 + && sig->sig_class != 0x00 ) { + md_handle.u.md5 = md5_copy(pkt->pkc_parent->mfx.md5); + md5_write(md_handle.u.md5, pkt->user_parent->name, + pkt->user_parent->len); + result = signature_check( sig, md_handle ); + md5_close(md_handle.u.md5); + } + else + result = G10ERR_DIGEST_ALGO; + } else if(sig->pubkey_algo == PUBKEY_ALGO_RSA ) { md_handle.algo = sig->d.rsa.digest_algo; if( sig->d.rsa.digest_algo == DIGEST_ALGO_RMD160 ) { @@ -204,7 +230,8 @@ proc_packets( IOBUF a ) enc = pkt->pkt.pubkey_enc; printf("enc: encrypted by a pubkey with keyid %08lX\n", enc->keyid[1] ); - if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) { + if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL + || enc->pubkey_algo == PUBKEY_ALGO_RSA ) { m_free(dek ); /* paranoid: delete a pending DEK */ dek = m_alloc_secure( sizeof *dek ); if( (result = get_session_key( enc, dek )) ) { diff --git a/g10/packet.h b/g10/packet.h index f57dce172..480fb54db 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -28,16 +28,22 @@ #include "filter.h" -#define PKT_PUBKEY_ENC 1 /* public key encrypted packet */ -#define PKT_SIGNATURE 2 /* secret key encrypted packet */ -#define PKT_SECKEY_CERT 5 /* secret key certificate */ -#define PKT_PUBKEY_CERT 6 /* public key certificate */ -#define PKT_COMPR_DATA 8 /* compressed data packet */ -#define PKT_ENCR_DATA 9 /* conventional encrypted data */ -#define PKT_PLAINTEXT 11 /* plaintext data with filename and mode */ -#define PKT_RING_TRUST 12 /* keyring trust packet */ -#define PKT_USER_ID 13 /* user id packet */ -#define PKT_COMMENT 14 /* comment packet */ +#define PKT_PUBKEY_ENC 1 /* public key encrypted packet */ +#define PKT_SIGNATURE 2 /* secret key encrypted packet */ +#define PKT_SESSION_KEY 3 /* session key packet (OpenPGP)*/ +#define PKT_ONEPASS_SIG 4 /* one pass sig packet (OpenPGP)*/ +#define PKT_SECKEY_CERT 5 /* secret key certificate */ +#define PKT_PUBKEY_CERT 6 /* public key certificate */ +#define PKT_SECKEY_SUBCERT 7 /* secret subkey certificate (OpenPGP) */ +#define PKT_COMPR_DATA 8 /* compressed data packet */ +#define PKT_ENCR_DATA 9 /* conventional encrypted data */ +#define PKT_MARKER 10 /* marker packet (OpenPGP) */ +#define PKT_PLAINTEXT 11 /* plaintext data with filename and mode */ +#define PKT_RING_TRUST 12 /* keyring trust packet */ +#define PKT_USER_ID 13 /* user id packet */ +#define PKT_COMMENT 14 /* comment packet */ +#define PKT_PUBKEY_SUBCERT 14 /* subkey certificate (OpenPGP) */ +#define PKT_NEW_COMMENT 16 /* new comment packet (OpenPGP) */ typedef struct packet_struct PACKET; @@ -48,6 +54,9 @@ typedef struct { struct { MPI rsa_integer; /* integer containing the DEK */ } rsa; + struct { + MPI a, b; /* integers with the enciphered DEK */ + } elg; } d; } PKT_pubkey_enc; @@ -60,10 +69,15 @@ typedef struct { /* (PUBKEY_ALGO_xxx) */ union { struct { - byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */ + byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */ byte digest_start[2]; /* first 2 byte of the digest */ - MPI rsa_integer; /* the encrypted digest */ + MPI rsa_integer; /* the encrypted digest */ } rsa; + struct { + byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */ + byte digest_start[2]; /* first 2 byte of the digest */ + MPI a, b; /* integers with the digest */ + } elg; } d; } PKT_signature; @@ -78,6 +92,11 @@ typedef struct { MPI rsa_n; /* public modulus */ MPI rsa_e; /* public exponent */ } rsa; + struct { + MPI p; /* prime */ + MPI g; /* group generator */ + MPI y; /* g^x mod p */ + } elg; } d; } PKT_pubkey_cert; @@ -106,6 +125,24 @@ typedef struct { } blowfish; } protect; } rsa; + struct { + MPI p; /* prime */ + MPI g; /* group generator */ + MPI y; /* g^x mod p */ + MPI x; /* secret exponent */ + u16 csum; /* checksum */ + u16 calc_csum; /* and a place to store the calculated csum */ + byte is_protected; /* The above infos are protected and must */ + /* be deciphered before use */ + byte protect_algo; /* cipher used to protect the secret informations*/ + union { /* information for the protection */ + struct { + byte iv[8]; /* initialization vector for CFB mode */ + /* when protected, the MPIs above are pointers + * to plain storage */ + } blowfish; + } protect; + } elg; } d; } PKT_seckey_cert; diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 35fc6d766..569657c29 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -148,6 +148,7 @@ parse_packet( IOBUF inp, PACKET *pkt ) rc = parse_certificate(inp, pkttype, pktlen, hdr, hdrlen, pkt ); break; case PKT_SECKEY_CERT: + case PKT_SECKEY_SUBCERT: pkt->pkt.seckey_cert = m_alloc_clear(sizeof *pkt->pkt.seckey_cert ); rc = parse_certificate(inp, pkttype, pktlen, hdr, hdrlen, pkt ); break; @@ -230,7 +231,19 @@ parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) if( list_mode ) printf(":public key packet: keyid %08lX%08lX\n", k->keyid[0], k->keyid[1]); - if( k->pubkey_algo == PUBKEY_ALGO_RSA ) { + if( k->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + n = pktlen; + k->d.elg.a = mpi_decode(inp, &n ); pktlen -=n; + k->d.elg.b = mpi_decode(inp, &n ); pktlen -=n; + if( list_mode ) { + printf("\telg a: "); + mpi_print(stdout, k->d.elg.a, mpi_print_mode ); + printf("\n\telg b: "); + mpi_print(stdout, k->d.elg.b, mpi_print_mode ); + putchar('\n'); + } + } + else if( k->pubkey_algo == PUBKEY_ALGO_RSA ) { n = pktlen; k->d.rsa.rsa_integer = mpi_decode(inp, &n ); pktlen -=n; if( list_mode ) { @@ -276,7 +289,29 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, "\tversion %d, created %lu, md5len %d, sigclass %02x\n", sig->keyid[0], sig->keyid[1], version, sig->timestamp, md5_len, sig->sig_class ); - if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) { + if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + if( pktlen < 5 ) { + log_error("packet(%d) too short\n", pkttype); + goto leave; + } + sig->d.elg.digest_algo = iobuf_get_noeof(inp); pktlen--; + sig->d.elg.digest_start[0] = iobuf_get_noeof(inp); pktlen--; + sig->d.elg.digest_start[1] = iobuf_get_noeof(inp); pktlen--; + n = pktlen; + sig->d.elg.a = mpi_decode(inp, &n ); pktlen -=n; + sig->d.elg.b = mpi_decode(inp, &n ); pktlen -=n; + if( list_mode ) { + printf("\tdigest algo %d, begin of digest %02x %02x\n", + sig->d.elg.digest_algo, + sig->d.elg.digest_start[0], sig->d.elg.digest_start[1] ); + printf("\telg a: "); + mpi_print(stdout, sig->d.elg.a, mpi_print_mode ); + printf("\n\telg b: "); + mpi_print(stdout, sig->d.elg.a, mpi_print_mode ); + putchar('\n'); + } + } + else if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) { if( pktlen < 5 ) { log_error("packet(%d) too short\n", pkttype); goto leave; @@ -315,7 +350,7 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, unsigned n; unsigned long timestamp; unsigned short valid_period; - MPI rsa_pub_mod, rsa_pub_exp; + int is_v4=0; if( pkttype == PKT_PUBKEY_CERT ) { pkt->pkt.pubkey_cert->mfx.md5 = md5_open(0); @@ -331,13 +366,18 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, goto leave; } version = iobuf_get_noeof(inp); pktlen--; - if( version != 2 && version != 3 ) { + if( version == 4 ) + is_v4=1; + else if( version != 2 && version != 3 ) { log_error("packet(%d) with unknown version %d\n", pkttype, version); goto leave; } timestamp = read_32(inp); pktlen -= 4; - valid_period = read_16(inp); pktlen -= 2; + if( is_v4 ) + valid_period = 0; + else + valid_period = read_16(inp); pktlen -= 2; algorithm = iobuf_get_noeof(inp); pktlen--; if( list_mode ) printf(":%s key certification packet:\n" @@ -355,7 +395,76 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, pkt->pkt.pubkey_cert->pubkey_algo = algorithm; } - if( algorithm == PUBKEY_ALGO_RSA ) { + if( algorithm == PUBKEY_ALGO_ELGAMAL ) { + MPI elg_p, elg_g, elg_y; + n = pktlen; elg_p = mpi_decode(inp, &n ); pktlen -=n; + n = pktlen; elg_g = mpi_decode(inp, &n ); pktlen -=n; + n = pktlen; elg_y = mpi_decode(inp, &n ); pktlen -=n; + if( list_mode ) { + printf( "\telg p: "); + mpi_print(stdout, elg_p, mpi_print_mode ); + printf("\n\telg g: "); + mpi_print(stdout, elg_g, mpi_print_mode ); + printf("\n\telg y: "); + mpi_print(stdout, elg_y, mpi_print_mode ); + putchar('\n'); + } + if( pkttype == PKT_PUBKEY_CERT ) { + pkt->pkt.pubkey_cert->d.elg.p = elg_p; + pkt->pkt.pubkey_cert->d.elg.g = elg_g; + pkt->pkt.pubkey_cert->d.elg.y = elg_y; + } + else { + PKT_seckey_cert *cert = pkt->pkt.seckey_cert; + byte temp[8]; + byte *mpibuf; + + pkt->pkt.seckey_cert->d.elg.p = elg_p; + pkt->pkt.seckey_cert->d.elg.g = elg_g; + pkt->pkt.seckey_cert->d.elg.y = elg_y; + cert->d.elg.protect_algo = iobuf_get_noeof(inp); pktlen--; + if( list_mode ) + printf( "\tprotect algo: %d\n", cert->d.elg.protect_algo); + if( cert->d.elg.protect_algo ) { + cert->d.elg.is_protected = 1; + for(i=0; i < 8 && pktlen; i++, pktlen-- ) + temp[i] = iobuf_get_noeof(inp); + if( list_mode ) { + printf( "\tprotect IV: "); + for(i=0; i < 8; i++ ) + printf(" %02x", temp[i] ); + putchar('\n'); + } + if( cert->d.elg.protect_algo == CIPHER_ALGO_BLOWFISH ) + memcpy(cert->d.elg.protect.blowfish.iv, temp, 8 ); + } + else + cert->d.elg.is_protected = 0; + + n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2); + cert->d.elg.x = (MPI)mpibuf; + + cert->d.elg.csum = read_16(inp); pktlen -= 2; + cert->d.elg.calc_csum = 0; + if( list_mode ) { + printf("\t[secret value x is not shown]\n" + "\tchecksum: %04hx\n", cert->d.elg.csum); + } + if( !cert->d.elg.is_protected ) { /* convert buffer to MPIs */ + mpibuf = (byte*)cert->d.elg.x; + cert->d.elg.calc_csum += checksum( mpibuf ); + cert->d.elg.x = mpi_decode_buffer( mpibuf ); + m_free( mpibuf ); + log_mpidump("elg p=", cert->d.elg.p ); + log_mpidump("elg g=", cert->d.elg.g ); + log_mpidump("elg y=", cert->d.elg.y ); + log_mpidump("elg x=", cert->d.elg.x ); + } + } + } + else if( algorithm == PUBKEY_ALGO_RSA ) { + MPI rsa_pub_mod, rsa_pub_exp; + n = pktlen; rsa_pub_mod = mpi_decode(inp, &n ); pktlen -=n; n = pktlen; rsa_pub_exp = mpi_decode(inp, &n ); pktlen -=n; if( list_mode ) { diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 93bdff9da..58da1aef8 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -39,24 +39,50 @@ int get_session_key( PKT_pubkey_enc *k, DEK *dek ) { int i, j, c, rc = 0; - RSA_secret_key *skey = m_alloc_secure( sizeof *skey ); MPI dek_frame = mpi_alloc_secure(40); u16 csum, csum2; + PKT_seckey_cert *skc = m_alloc_clear( sizeof *skc ); - if( k->pubkey_algo != PUBKEY_ALGO_RSA ) { + skc->pubkey_algo = k->pubkey_algo; /* we want a pubkey with this algo*/ + if( (rc = get_seckey( skc, k->keyid )) ) + goto leave; + + if( k->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + ELG_secret_key skey; + + if( DBG_CIPHER ) { + log_mpidump("Encr DEK a:", k->d.elg.a ); + log_mpidump(" DEK b:", k->d.elg.b ); + } + skey.p = skc->d.elg.p; + skey.g = skc->d.elg.g; + skey.y = skc->d.elg.y; + skey.x = skc->d.elg.x; + elg_decipher( dek_frame, k->d.elg.a, k->d.elg.b, &skey ); + memset( &skey, 0, sizeof skey ); + } + else if( k->pubkey_algo == PUBKEY_ALGO_RSA ) { + RSA_secret_key skey; + + if( DBG_CIPHER ) + log_mpidump("Encr DEK frame:", k->d.rsa.rsa_integer ); + + skey.e = skc->d.rsa.rsa_e; + skey.n = skc->d.rsa.rsa_n; + skey.p = skc->d.rsa.rsa_p; + skey.q = skc->d.rsa.rsa_q; + skey.d = skc->d.rsa.rsa_d; + skey.u = skc->d.rsa.rsa_u; + rsa_secret( dek_frame, k->d.rsa.rsa_integer, &skey ); + memset( &skey, 0, sizeof skey ); + } + else { rc = G10ERR_PUBKEY_ALGO; /* unsupported algorithm */ goto leave; } + free_seckey_cert( skc ); skc = NULL; - /* get the secret key for the given public key - * and decode the rsa_integer - */ - if( (rc = get_seckey( skey, k->keyid )) ) - goto leave; - if( DBG_CIPHER ) - log_mpidump("Encr DEK frame:", k->d.rsa.rsa_integer ); - rsa_secret( dek_frame, k->d.rsa.rsa_integer, skey ); /* Now get the DEK (data encryption key) from the dek_frame * * Old versions encode the DEK in in this format (msb is left): @@ -87,7 +113,7 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek ) } if( c != 2 ) /* somethink is wrong */ { rc = G10ERR_WRONG_SECKEY; goto leave; } - /* look for the zeor byte */ + /* look for the zero byte */ for(i--; i > 4 ; i-- ) if( !mpi_getbyte(dek_frame,i) ) break; @@ -95,10 +121,10 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek ) { rc = G10ERR_WRONG_SECKEY; goto leave; } /* next byte indicates the used cipher */ switch( mpi_getbyte(dek_frame, --i ) ) { - case 1: + case CIPHER_ALGO_IDEA: rc = G10ERR_NI_CIPHER; goto leave; - case 42: + case CIPHER_ALGO_BLOWFISH: if( i != 22 ) /* length of blowfish is 20 (+2 bytes checksum) */ { rc = G10ERR_WRONG_SECKEY; goto leave; } dek->algo = CIPHER_ALGO_BLOWFISH; @@ -122,7 +148,8 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek ) leave: mpi_free(dek_frame); - m_free(skey); + if( skc ) + free_seckey_cert( skc ); return rc; } diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index c103de5c7..4e1a384c2 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -30,6 +30,9 @@ #include "keydb.h" #include "cipher.h" +#if BLOWFISH_BLOCKSIZE != 8 + #error unsupportted blocksize +#endif static u16 checksum( byte *p ) @@ -44,11 +47,9 @@ checksum( byte *p ) } -/**************** - * Check the secret key certificate - */ -int -check_secret_key( PKT_seckey_cert *cert ) + +static int +check_elg( PKT_seckey_cert *cert ) { byte iv[8]; byte *mpibuf; @@ -56,13 +57,73 @@ check_secret_key( PKT_seckey_cert *cert ) MPI temp_mpi; int res; u32 keyid[2]; + ELG_secret_key skey; -#if BLOWFISH_BLOCKSIZE != 8 - #error unsupportted blocksize -#endif + if( cert->d.elg.is_protected ) { /* remove the protection */ + DEK *dek = NULL; + BLOWFISH_context *blowfish_ctx=NULL; - if( cert->pubkey_algo != PUBKEY_ALGO_RSA ) - return G10ERR_PUBKEY_ALGO; /* unsupport algorithm */ + switch( cert->d.elg.protect_algo ) { + case CIPHER_ALGO_NONE: log_bug(NULL); break; + case CIPHER_ALGO_BLOWFISH: + keyid_from_skc( cert, keyid ); + dek = get_passphrase_hash( keyid, NULL ); + m_free(dek); /* pw is in secure memory, so m_free() burns it */ + memset( iv, 0, BLOWFISH_BLOCKSIZE ); + blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx ); + blowfish_setiv( blowfish_ctx, iv ); + blowfish_decode_cfb( blowfish_ctx, + cert->d.elg.protect.blowfish.iv, + cert->d.elg.protect.blowfish.iv, 8 ); + cert->d.elg.calc_csum = 0; + mpibuf = (byte*)cert->d.elg.x; + n = ((mpibuf[0] << 8) | mpibuf[1])-2; + blowfish_decode_cfb( blowfish_ctx, mpibuf+4, mpibuf+4, n ); + cert->d.elg.calc_csum += checksum( mpibuf ); + cert->d.elg.x = mpi_decode_buffer( mpibuf ); + m_free( mpibuf ); + m_free( blowfish_ctx ); + cert->d.elg.is_protected = 0; + /* now let's see wether we have used the right passphrase */ + if( cert->d.elg.calc_csum != cert->d.elg.csum ) + return G10ERR_BAD_PASS; + + skey.p = cert->d.elg.p; + skey.g = cert->d.elg.g; + skey.y = cert->d.elg.y; + skey.x = cert->d.elg.x; + res = elg_check_secret_key( &skey ); + memset( &skey, 0, sizeof skey ); + if( !res ) + return G10ERR_BAD_PASS; + break; + + default: + return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */ + } + } + /* must check the checksum here, because we didn't do it when + * parsing an unprotected certificate */ + if( cert->d.elg.calc_csum != cert->d.elg.csum ) { + log_error("checksum in secret key certificate is wrong\n"); + log_debug("stored csum=%04hx calculated csum=%04hx\n", + cert->d.elg.csum, cert->d.elg.calc_csum ); + return G10ERR_CHECKSUM; + } + return 0; +} + + +#ifdef HAVE_RSA_CIPHER +static int +check_rsa( PKT_seckey_cert *cert ) +{ + byte iv[8]; + byte *mpibuf; + u16 n; + MPI temp_mpi; + int res; + u32 keyid[2]; if( cert->d.rsa.is_protected ) { /* remove the protection */ DEK *dek = NULL; @@ -73,7 +134,7 @@ check_secret_key( PKT_seckey_cert *cert ) log_bug("unprotect seckey_cert is flagged protected\n"); break; case CIPHER_ALGO_BLOWFISH: - mpi_get_keyid( cert->d.rsa.rsa_n , keyid ); + keyid_from_skc( cert, keyid ); dek = get_passphrase_hash( keyid, NULL ); m_free(dek); /* pw is in secure memory, so m_free() burns it */ @@ -133,5 +194,24 @@ check_secret_key( PKT_seckey_cert *cert ) } return 0; } +#endif /*HAVE_RSA_CIPHER*/ + + +/**************** + * Check the secret key certificate + */ +int +check_secret_key( PKT_seckey_cert *cert ) +{ + if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) + return check_elg( cert ); + #ifdef HAVE_RSA_CIPHER + else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) + return check_rsa( cert ); + #endif + else + return G10ERR_PUBKEY_ALGO; +} + diff --git a/g10/seskey.c b/g10/seskey.c index 317623ec8..5e944760d 100644 --- a/g10/seskey.c +++ b/g10/seskey.c @@ -26,6 +26,7 @@ #include "util.h" #include "cipher.h" #include "mpi.h" +#include "main.h" @@ -73,7 +74,7 @@ encode_session_key( DEK *dek, unsigned nbits ) * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes) * * RND are non-zero random bytes. - * A is the cipher algorithm ( 42 for Blowfish ) + * A is the cipher algorithm * DEK is the encryption key (session key) length k depends on the * cipher algorithm (20 is used with blowfish). * CSUM is the 16 bit checksum over the DEK @@ -106,7 +107,7 @@ encode_session_key( DEK *dek, unsigned nbits ) MPI encode_rmd160_value( byte *md, unsigned len, unsigned nbits ) { - static byte asn[18] = /* stored reverse FIXME: need other values*/ + static byte asn[18] = /* FIXME: need other values*/ { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; int nframe = (nbits+7) / 8; @@ -119,7 +120,7 @@ encode_rmd160_value( byte *md, unsigned len, unsigned nbits ) /* We encode the MD in this way: * - * 0 42 PAD(n bytes) 0 ASN(18 bytes) MD(20 bytes) + * 0 A PAD(n bytes) 0 ASN(18 bytes) MD(20 bytes) * * PAD consists of FF bytes. */ @@ -138,3 +139,43 @@ encode_rmd160_value( byte *md, unsigned len, unsigned nbits ) return frame; } + +/**************** + * Encode a md5 message digest of LEN bytes into NBITS. + * returns: A mpi with the session key (caller must free) + */ +MPI +encode_md5_value( byte *md, unsigned len, unsigned nbits ) +{ + static byte asn[18] = + { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,0x48, + 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; + int nframe = (nbits+7) / 8; + byte *p; + MPI frame; + int i,n,c; + + if( (nbits % BITS_PER_MPI_LIMB) || nframe < 38 || len != 16 ) + log_bug("can't encode a %d bit MD into a %d bits frame\n",len*8, nbits); + + /* We encode the MD in this way: + * + * 0 A PAD(n bytes) 0 ASN(18 bytes) MD(16 bytes) + * + * PAD consists of FF bytes. + */ + frame = mpi_alloc_secure( nframe / BYTES_PER_MPI_LIMB ); + n = 0; + for(i=16-1; i >= 0; i--, n++ ) + mpi_putbyte(frame, n, md[i] ); + for( i=18-1; i >= 0; i--, n++ ) + mpi_putbyte(frame, n, asn[i] ); + mpi_putbyte(frame, n++, 0 ); + while( n < nframe-2 ) + mpi_putbyte(frame, n++, 0xff ); + mpi_putbyte(frame, n++, DIGEST_ALGO_MD5 ); + mpi_putbyte(frame, n++, 0 ); + assert( n == nframe ); + return frame; +} + diff --git a/g10/sig-check.c b/g10/sig-check.c index 75e800693..ff212585c 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -29,6 +29,7 @@ #include "mpi.h" #include "keydb.h" #include "cipher.h" +#include "main.h" /**************** @@ -40,7 +41,7 @@ int signature_check( PKT_signature *sig, MD_HANDLE digest ) { PKT_pubkey_cert *pkc = m_alloc_clear( sizeof *pkc ); - MPI result = mpi_alloc(35); + MPI result = NULL; int rc=0, i, j, c, old_enc; byte *dp; @@ -50,11 +51,168 @@ signature_check( PKT_signature *sig, MD_HANDLE digest ) goto leave; } - if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) { + if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + ELG_public_key pkey; + + if( sig->d.elg.digest_algo == DIGEST_ALGO_RMD160 ) { + /* complete the digest */ + rmd160_putchar( digest.u.rmd, sig->sig_class ); + { u32 a = sig->timestamp; + rmd160_putchar( digest.u.rmd, (a >> 24) & 0xff ); + rmd160_putchar( digest.u.rmd, (a >> 16) & 0xff ); + rmd160_putchar( digest.u.rmd, (a >> 8) & 0xff ); + rmd160_putchar( digest.u.rmd, a & 0xff ); + } + dp = rmd160_final( digest.u.rmd ); + result = encode_rmd160_value( dp, 20, mpi_get_nbits(pkc->d.elg.p)); + } + else if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) { + md5_putchar( digest.u.md5, sig->sig_class ); + { u32 a = sig->timestamp; + md5_putchar( digest.u.md5, (a >> 24) & 0xff ); + md5_putchar( digest.u.md5, (a >> 16) & 0xff ); + md5_putchar( digest.u.md5, (a >> 8) & 0xff ); + md5_putchar( digest.u.md5, a & 0xff ); + } + md5_final( digest.u.md5 ); + dp = md5_read( digest.u.md5 ); + result = encode_md5_value( dp, 16, mpi_get_nbits(pkc->d.elg.p)); + } + else { + rc = G10ERR_DIGEST_ALGO; + goto leave; + } + + pkey.p = pkc->d.elg.p; + pkey.g = pkc->d.elg.g; + pkey.y = pkc->d.elg.y; + if( !elg_verify( sig->d.elg.a, sig->d.elg.b, result, &pkey ) ) + rc = G10ERR_BAD_SIGN; + } + else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) { RSA_public_key pkey; + + result = mpi_alloc(40); pkey.n = pkc->d.rsa.rsa_n; pkey.e = pkc->d.rsa.rsa_e; rsa_public( result, sig->d.rsa.rsa_integer, &pkey ); + + old_enc = 0; + for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) { + if( !j ) { + if( !i && c != 1 ) + break; + else if( i && c == 0xff ) + ; /* skip the padding */ + else if( i && !c ) + j++; + else + break; + } + else if( ++j == 18 && c != 1 ) + break; + else if( j == 19 && c == 0 ) { + old_enc++; + break; + } + } + if( old_enc ) { + log_error("old encoding scheme is not supported\n"); + rc = G10ERR_GENERAL; + goto leave; + } + + if( sig->d.rsa.digest_algo == DIGEST_ALGO_RMD160 ) { + static byte asn[18] = /* stored reverse FIXME: need other values*/ + { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d, 0xf7, 0x86, + 0x48, 0x86, 0x2a, 0x08, 0x06, 0x0c, 0x30, 0x20, 0x30 }; + + for(i=20,j=0; (c=mpi_getbyte(result, i)) != -1 && j < 18; i++, j++ ) + if( asn[j] != c ) + break; + if( j != 18 || c ) { /* ASN is wrong */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + for(i++; (c=mpi_getbyte(result, i)) != -1; i++ ) + if( c != 0xff ) + break; + i++; + if( c != DIGEST_ALGO_RMD160 || mpi_getbyte(result, i) ) { + /* Padding or leading bytes in signature is wrong */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + if( mpi_getbyte(result, 19) != sig->d.rsa.digest_start[0] + || mpi_getbyte(result, 18) != sig->d.rsa.digest_start[1] ) { + /* Wrong key used to check the signature */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + + /* complete the digest */ + rmd160_putchar( digest.u.rmd, sig->sig_class ); + { u32 a = sig->timestamp; + rmd160_putchar( digest.u.rmd, (a >> 24) & 0xff ); + rmd160_putchar( digest.u.rmd, (a >> 16) & 0xff ); + rmd160_putchar( digest.u.rmd, (a >> 8) & 0xff ); + rmd160_putchar( digest.u.rmd, a & 0xff ); + } + dp = rmd160_final( digest.u.rmd ); + for(i=19; i >= 0; i--, dp++ ) + if( mpi_getbyte( result, i ) != *dp ) { + rc = G10ERR_BAD_SIGN; + goto leave; + } + } + else if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) { + static byte asn[18] = /* stored reverse */ + { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d, 0xf7, 0x86, + 0x48, 0x86, 0x2a, 0x08, 0x06, 0x0c, 0x30, 0x20, 0x30 }; + + for(i=16,j=0; j < 18 && (c=mpi_getbyte(result, i)) != -1; i++, j++ ) + if( asn[j] != c ) + break; + if( j != 18 || c ) { /* ASN is wrong */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + for(i++; (c=mpi_getbyte(result, i)) != -1; i++ ) + if( c != 0xff ) + break; + i++; + if( c != DIGEST_ALGO_MD5 || mpi_getbyte(result, i) ) { + /* Padding or leading bytes in signature is wrong */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + if( mpi_getbyte(result, 15) != sig->d.rsa.digest_start[0] + || mpi_getbyte(result, 14) != sig->d.rsa.digest_start[1] ) { + /* Wrong key used to check the signature */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + + /* complete the digest */ + md5_putchar( digest.u.md5, sig->sig_class ); + { u32 a = sig->timestamp; + md5_putchar( digest.u.md5, (a >> 24) & 0xff ); + md5_putchar( digest.u.md5, (a >> 16) & 0xff ); + md5_putchar( digest.u.md5, (a >> 8) & 0xff ); + md5_putchar( digest.u.md5, a & 0xff ); + } + md5_final( digest.u.md5 ); + dp = md5_read( digest.u.md5 ); + for(i=15; i >= 0; i--, dp++ ) + if( mpi_getbyte( result, i ) != *dp ) { + rc = G10ERR_BAD_SIGN; + goto leave; + } + } + else { + rc = G10ERR_DIGEST_ALGO; + goto leave; + } } else { log_debug("signature_check: unsupported pubkey algo %d\n", @@ -64,148 +222,10 @@ signature_check( PKT_signature *sig, MD_HANDLE digest ) } - /* Now RESULT contains the deciphered session key. - * - * The session key is stored in different ways: - * - * Old versions encodes the digest in in this format (msb is left): - * - * 0 1 MD5(16 bytes) 0 PAD(n bytes) 1 - * - * Later versions encodes the digest like this: - * - * 0 1 PAD(n bytes) 0 ASN(18 bytes) MD(16 bytes) - * - * RIPE MD 160 digests are encoded like this: - * - * 0 42 PAD(n bytes) 0 ASN(18 bytes) MD(20 bytes) - * - * FIXME: we should use another ASN! - * - * PAD consists of FF bytes. - * ASN is here the constant: 3020300c06082a864886f70d020505000410 - */ - old_enc = 0; - for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) { - if( !j ) { - if( !i && c != 1 ) - break; - else if( i && c == 0xff ) - ; /* skip the padding */ - else if( i && !c ) - j++; - else - break; - } - else if( ++j == 18 && c != 1 ) - break; - else if( j == 19 && c == 0 ) { - old_enc++; - break; - } - } - if( old_enc ) { - log_error("old encoding scheme is not supported\n"); - rc = G10ERR_GENERAL; - goto leave; - } - - if( sig->d.rsa.digest_algo == DIGEST_ALGO_RMD160 ) { - static byte asn[18] = /* stored reverse FIXME: need other values*/ - { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d, 0xf7, 0x86, - 0x48, 0x86, 0x2a, 0x08, 0x06, 0x0c, 0x30, 0x20, 0x30 }; - - for(i=20,j=0; (c=mpi_getbyte(result, i)) != -1 && j < 18; i++, j++ ) - if( asn[j] != c ) - break; - if( j != 18 || c ) { /* ASN is wrong */ - rc = G10ERR_BAD_PUBKEY; - goto leave; - } - for(i++; (c=mpi_getbyte(result, i)) != -1; i++ ) - if( c != 0xff ) - break; - i++; - if( c != DIGEST_ALGO_RMD160 || mpi_getbyte(result, i) ) { - /* Padding or leading bytes in signature is wrong */ - rc = G10ERR_BAD_PUBKEY; - goto leave; - } - if( mpi_getbyte(result, 19) != sig->d.rsa.digest_start[0] - || mpi_getbyte(result, 18) != sig->d.rsa.digest_start[1] ) { - /* Wrong key used to check the signature */ - rc = G10ERR_BAD_PUBKEY; - goto leave; - } - - /* complete the digest */ - rmd160_putchar( digest.u.rmd, sig->sig_class ); - { u32 a = sig->timestamp; - rmd160_putchar( digest.u.rmd, (a >> 24) & 0xff ); - rmd160_putchar( digest.u.rmd, (a >> 16) & 0xff ); - rmd160_putchar( digest.u.rmd, (a >> 8) & 0xff ); - rmd160_putchar( digest.u.rmd, a & 0xff ); - } - dp = rmd160_final( digest.u.rmd ); - for(i=19; i >= 0; i--, dp++ ) - if( mpi_getbyte( result, i ) != *dp ) { - rc = G10ERR_BAD_SIGN; - goto leave; - } - } - else if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) { - static byte asn[18] = /* stored reverse */ - { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d, 0xf7, 0x86, - 0x48, 0x86, 0x2a, 0x08, 0x06, 0x0c, 0x30, 0x20, 0x30 }; - - for(i=16,j=0; j < 18 && (c=mpi_getbyte(result, i)) != -1; i++, j++ ) - if( asn[j] != c ) - break; - if( j != 18 || c ) { /* ASN is wrong */ - rc = G10ERR_BAD_PUBKEY; - goto leave; - } - for(i++; (c=mpi_getbyte(result, i)) != -1; i++ ) - if( c != 0xff ) - break; - i++; - if( c != DIGEST_ALGO_MD5 || mpi_getbyte(result, i) ) { - /* Padding or leading bytes in signature is wrong */ - rc = G10ERR_BAD_PUBKEY; - goto leave; - } - if( mpi_getbyte(result, 15) != sig->d.rsa.digest_start[0] - || mpi_getbyte(result, 14) != sig->d.rsa.digest_start[1] ) { - /* Wrong key used to check the signature */ - rc = G10ERR_BAD_PUBKEY; - goto leave; - } - - /* complete the digest */ - md5_putchar( digest.u.md5, sig->sig_class ); - { u32 a = sig->timestamp; - md5_putchar( digest.u.md5, (a >> 24) & 0xff ); - md5_putchar( digest.u.md5, (a >> 16) & 0xff ); - md5_putchar( digest.u.md5, (a >> 8) & 0xff ); - md5_putchar( digest.u.md5, a & 0xff ); - } - md5_final( digest.u.md5 ); - dp = md5_read( digest.u.md5 ); - for(i=15; i >= 0; i--, dp++ ) - if( mpi_getbyte( result, i ) != *dp ) { - rc = G10ERR_BAD_SIGN; - goto leave; - } - } - else { - rc = G10ERR_DIGEST_ALGO; - goto leave; - } - leave: - mpi_free( result ); if( pkc ) free_pubkey_cert( pkc ); + mpi_free( result ); return rc; } diff --git a/include/cipher.h b/include/cipher.h index e178b5f4e..e3280428f 100644 --- a/include/cipher.h +++ b/include/cipher.h @@ -38,20 +38,27 @@ #include "../cipher/elgamal.h" -#define CIPHER_ALGO_NONE 0 -#define CIPHER_ALGO_IDEA 1 /* used only for documentation */ -#define CIPHER_ALGO_BLOWFISH 42 -#define CIPHER_ALGO_GOST 43 +#define CIPHER_ALGO_NONE 0 +#define CIPHER_ALGO_IDEA 1 +#define CIPHER_ALGO_3DES 2 +#define CIPHER_ALGO_CAST 3 +#define CIPHER_ALGO_BLOWFISH128 4 /* blowfish 128 bit key */ +#define CIPHER_ALGO_ROT_N 5 +#define CIPHER_ALGO_SAFER_SK128 6 +#define CIPHER_ALGO_DES_SK 7 +#define CIPHER_ALGO_BLOWFISH 42 /* blowfish 160 bit key (not in OpenPGP)*/ +#define CIPHER_ALGO_GOST 43 /* (Not in OpenPGP) */ #define PUBKEY_ALGO_RSA 1 -#define PUBKEY_ALGO_ELGAMAL 42 +#define PUBKEY_ALGO_RSA_E 2 /* RSA encrypt only */ +#define PUBKEY_ALGO_RSA_S 3 /* RSA sign only */ +#define PUBKEY_ALGO_ELGAMAL 16 +#define PUBKEY_ALGO_DSA 17 #define DIGEST_ALGO_MD5 1 -#define DIGEST_ALGO_RMD160 42 +#define DIGEST_ALGO_SHA1 2 +#define DIGEST_ALGO_RMD160 3 -#define DEFAULT_CIPHER_ALGO CIPHER_ALGO_BLOWFISH -#define DEFAULT_PUBKEY_ALGO PUBKEY_ALGO_RSA -#define DEFAULT_DIGEST_ALGO DIGEST_ALGO_RMD160 typedef struct { int algo; @@ -78,12 +85,8 @@ byte get_random_byte( int level ); extern ushort small_prime_numbers[]; /*-- primegen.c --*/ -MPI generate_random_prime( unsigned nbits ); - -/*-- seskey.c --*/ -void make_session_key( DEK *dek ); -MPI encode_session_key( DEK *dek, unsigned nbits ); -MPI encode_rmd160_value( byte *md, unsigned len, unsigned nbits ); +MPI generate_secret_prime( unsigned nbits ); +MPI generate_public_prime( unsigned nbits ); #endif /*G10_CIPHER_H*/ diff --git a/include/mpi.h b/include/mpi.h index 096cffec9..25fa696c4 100644 --- a/include/mpi.h +++ b/include/mpi.h @@ -51,6 +51,7 @@ typedef struct mpi_struct { #define MPI_NULL NULL #define mpi_get_nlimbs(a) ((a)->nlimbs) +#define mpi_is_neg(a) ((a)->sign) /*-- mpiutil.c --*/ @@ -101,13 +102,16 @@ u32 mpi_get_keyid( MPI a, u32 *keyid ); /*-- mpi-add.c --*/ void mpi_add_ui(MPI w, MPI u, ulong v ); void mpi_add(MPI w, MPI u, MPI v); +void mpi_addm(MPI w, MPI u, MPI v, MPI m); void mpi_sub_ui(MPI w, MPI u, ulong v ); void mpi_sub( MPI w, MPI u, MPI v); +void mpi_subm( MPI w, MPI u, MPI v, MPI m); /*-- mpi-mul.c --*/ void mpi_mul_ui(MPI w, MPI u, ulong v ); void mpi_mul_2exp( MPI w, MPI u, ulong cnt); void mpi_mul( MPI w, MPI u, MPI v); +void mpi_mulm( MPI w, MPI u, MPI v, MPI m); /*-- mpi-div.c --*/ ulong mpi_fdiv_r_ui( MPI rem, MPI dividend, ulong divisor ); @@ -142,7 +146,7 @@ void mpi_set_bytes( MPI a, unsigned nbits, byte (*fnc)(int), int opaque ); void mpi_rshift( MPI x, MPI a, unsigned n ); /*-- mpi-inv.c --*/ -void mpi_inv_mod( MPI x, MPI u, MPI v ); +void mpi_invm( MPI x, MPI u, MPI v ); #endif /*G10_MPI_H*/ diff --git a/mpi/mpi-add.c b/mpi/mpi-add.c index 2c1aa6c61..b9c69af44 100644 --- a/mpi/mpi-add.c +++ b/mpi/mpi-add.c @@ -222,3 +222,17 @@ mpi_sub(MPI w, MPI u, MPI v) } +void +mpi_addm( MPI w, MPI u, MPI v, MPI m) +{ + mpi_add(w, u, v); + mpi_fdiv_r( w, w, m ); +} + +void +mpi_subm( MPI w, MPI u, MPI v, MPI m) +{ + mpi_sub(w, u, v); + mpi_fdiv_r( w, w, m ); +} + diff --git a/mpi/mpi-inv.c b/mpi/mpi-inv.c index f37f4e511..28cde00b6 100644 --- a/mpi/mpi-inv.c +++ b/mpi/mpi-inv.c @@ -30,7 +30,7 @@ * 1 = (a*x) mod n */ void -mpi_inv_mod( MPI x, MPI a, MPI n ) +mpi_invm( MPI x, MPI a, MPI n ) { #if 0 MPI u, v, u1, u2, u3, v1, v2, v3, q, t1, t2, t3; diff --git a/mpi/mpi-mul.c b/mpi/mpi-mul.c index 03f2b4b44..aa5beb73b 100644 --- a/mpi/mpi-mul.c +++ b/mpi/mpi-mul.c @@ -176,3 +176,10 @@ mpi_mul( MPI w, MPI u, MPI v) } +void +mpi_mulm( MPI w, MPI u, MPI v, MPI m) +{ + mpi_mul(w, u, v); + mpi_fdiv_r( w, w, m ); +} + diff --git a/tools/mpicalc.c b/tools/mpicalc.c index 828b475b3..28c498548 100644 --- a/tools/mpicalc.c +++ b/tools/mpicalc.c @@ -159,7 +159,7 @@ do_inv(void) fputs("stack underflow\n", stderr); return; } - mpi_inv_mod( a, stack[stackidx-2], stack[stackidx-1] ); + mpi_invm( a, stack[stackidx-2], stack[stackidx-1] ); mpi_set(stack[stackidx-2],a); mpi_free(a); stackidx--; diff --git a/util/logger.c b/util/logger.c index 9c1b86b23..8993ba43d 100644 --- a/util/logger.c +++ b/util/logger.c @@ -110,9 +110,13 @@ log_bug( const char *fmt, ... ) va_list arg_ptr ; fprintf(stderr, "\nInternal Error%s: ", pidstring ) ; - va_start( arg_ptr, fmt ) ; - vfprintf(stderr,fmt,arg_ptr) ; - va_end(arg_ptr); + if( fmt ) { + va_start( arg_ptr, fmt ) ; + vfprintf(stderr,fmt,arg_ptr) ; + va_end(arg_ptr); + } + else + fputs("Ohhh jeeee ...\n", stderr); fflush(stderr); abort(); }