ElGamal funktioniert und ist default

This commit is contained in:
Werner Koch 1997-11-24 22:24:04 +00:00
parent a51cca90b6
commit 46900fbd43
31 changed files with 1273 additions and 409 deletions

View File

@ -28,34 +28,279 @@
#include <string.h>
#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;
}

View File

@ -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*/

View File

@ -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(;;) {

View File

@ -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 );

7
doc/DETAILS Normal file
View File

@ -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

View File

@ -21,6 +21,7 @@ g10_SOURCES = g10.c \
cipher.c \
options.h \
openfile.c \
keyid.c \
packet.h \
parse-packet.c \
passphrase.c \

View File

@ -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)

View File

@ -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] );

View File

@ -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 <config.h>
#include <stdio.h>
#include <stdlib.h>
#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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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 );
}
}
}

View File

@ -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 );

View File

@ -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 <heinrichh@uni-duesseldorf.de>\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);

88
g10/keyid.c Normal file
View File

@ -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 <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#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;
}

View File

@ -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*/

View File

@ -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 )) ) {

View File

@ -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;

View File

@ -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 ) {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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*/

View File

@ -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*/

View File

@ -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 );
}

View File

@ -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;

View File

@ -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 );
}

View File

@ -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--;

View File

@ -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();
}