add DSA key generation
authorWerner Koch <wk@gnupg.org>
Tue, 5 May 1998 20:34:20 +0000 (20:34 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 5 May 1998 20:34:20 +0000 (20:34 +0000)
17 files changed:
THANKS
TODO
VERSION
cipher/ChangeLog
cipher/dsa.c
cipher/dsa.h
cipher/elgamal.c
cipher/primegen.c
cipher/tiger.c
g10/ChangeLog
g10/build-packet.c
g10/g10.c
g10/keyedit.c
g10/keygen.c
g10/main.h
include/cipher.h
zlib/Makefile

diff --git a/THANKS b/THANKS
index 7bff6b5..5078c65 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -24,6 +24,8 @@ Ulf M
 Walter Koch            walterk@ddorf.rhein-ruhr.de
 Werner Koch            werner.koch@guug.de
 Wim Vandeputte         bunbun@reptile.rug.ac.be
+                       tzeruch@ceddec.com
+
 
 Thanks to the German Unix User Group for providing FTP space and
 Martin Hamilton for hosting the mailing list.
diff --git a/TODO b/TODO
index bc81767..78f6a14 100644 (file)
--- a/TODO
+++ b/TODO
@@ -47,3 +47,5 @@
 
     * add readline support (but how can we allcoate it in secure memory?)
 
+    * add a testcase for --print-mds
+
diff --git a/VERSION b/VERSION
index 0fcb3bb..fc15b1b 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.2.17
+0.2.17a
index a44abae..ae96007 100644 (file)
@@ -1,3 +1,13 @@
+Tue May  5 21:28:55 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * elgamal.c (elg_generate): choosing x was not correct, could
+       yield 6 bytes which are not from the random pool, tsss, tsss..
+
+Tue May  5 14:09:06 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * primegen.c (generate_elg_prime): Add arg mode, changed all
+       callers and implemented mode 1.
+
 Mon Apr 27 14:41:58 1998  Werner Koch  (wk@isil.d.shuttle.de)
 
        * cipher.c (cipher_get_keylen): New.
index f32fee6..d1c15c4 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <assert.h>
 #include "util.h"
 #include "mpi.h"
 #include "cipher.h"
@@ -74,6 +75,123 @@ dsa_free_secret_key( DSA_secret_key *sk )
 }
 
 
+static void
+test_keys( DSA_public_key *pk, DSA_secret_key *sk, unsigned qbits )
+{
+    MPI test = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
+    MPI out1_a = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
+    MPI out1_b = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
+
+    mpi_set_bytes( test, qbits, get_random_byte, 0 );
+
+    dsa_sign( out1_a, out1_b, test, sk );
+    if( !dsa_verify( out1_a, out1_b, test, pk ) )
+       log_fatal("DSA:: sign, verify failed\n");
+
+    mpi_free( test );
+    mpi_free( out1_a );
+    mpi_free( out1_b );
+}
+
+
+
+/****************
+ * Generate a DSA key pair with a key of size NBITS
+ * Returns: 2 structures filled with all needed values
+ *         and an array with the n-1 factors of (p-1)
+ */
+void
+dsa_generate( DSA_public_key *pk, DSA_secret_key *sk,
+             unsigned nbits, MPI **ret_factors )
+{
+    MPI p;    /* the prime */
+    MPI q;    /* the 160 bit prime factor */
+    MPI g;    /* the generator */
+    MPI y;    /* g^x mod p */
+    MPI x;    /* the secret exponent */
+    MPI h, e;  /* helper */
+    unsigned qbits;
+    byte *rndbuf;
+
+    assert( nbits >= 512 && nbits <= 1024 );
+
+    qbits = 160;
+    p = generate_elg_prime( 1, nbits, qbits, NULL, ret_factors );
+    /* get q out of factors */
+    q = mpi_copy((*ret_factors)[0]);
+    if( mpi_get_nbits(q) != qbits )
+       BUG();
+
+    /* find a generator g (h and e are helpers)*/
+    /* e = (p-1)/q */
+    e = mpi_alloc( mpi_get_nlimbs(p) );
+    mpi_sub_ui( e, p, 1 );
+    mpi_fdiv_q( e, e, q );
+    g = mpi_alloc( mpi_get_nlimbs(p) );
+    h = mpi_alloc_set_ui( 1 ); /* we start with 2 */
+    do {
+       mpi_add_ui( h, h, 1 );
+       /* g = h^e mod p */
+       mpi_powm( g, h, e, p );
+    } while( !mpi_cmp_ui( g, 1 ) );  /* continue until g != 1 */
+
+    /* select a random number which has these properties:
+     *  0 < x < q-1
+     * This must be a very good random number because this
+     * is the secret part. */
+    if( DBG_CIPHER )
+       log_debug("choosing a random x ");
+    assert( qbits >= 16 );
+    x = mpi_alloc_secure( mpi_get_nlimbs(q) );
+    mpi_sub_ui( h, q, 1 );  /* put q-1 into h */
+    rndbuf = NULL;
+    do {
+       if( DBG_CIPHER )
+           fputc('.', stderr);
+       if( !rndbuf )
+           rndbuf = get_random_bits( qbits, 2, 1 );
+       else { /* change only some of the higher bits (= 2 bytes)*/
+           char *r = get_random_bits( 16, 2, 1 );
+           memcpy(rndbuf, r, 16/8 );
+           m_free(r);
+       }
+       mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 );
+       mpi_clear_highbit( x, qbits+1 );
+    } while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) );
+    m_free(rndbuf);
+    mpi_free( e );
+    mpi_free( h );
+
+    /* y = g^x mod p */
+    y = mpi_alloc( mpi_get_nlimbs(p) );
+    mpi_powm( y, g, x, p );
+
+    if( DBG_CIPHER ) {
+       fputc('\n', stderr);
+       log_mpidump("dsa  p= ", p );
+       log_mpidump("dsa  q= ", q );
+       log_mpidump("dsa  g= ", g );
+       log_mpidump("dsa  y= ", y );
+       log_mpidump("dsa  x= ", x );
+    }
+
+    /* copy the stuff to the key structures */
+    pk->p = mpi_copy(p);
+    pk->q = mpi_copy(q);
+    pk->g = mpi_copy(g);
+    pk->y = mpi_copy(y);
+    sk->p = p;
+    sk->q = q;
+    sk->g = g;
+    sk->y = y;
+    sk->x = x;
+
+    /* now we can test our keys (this should never fail!) */
+    test_keys( pk, sk, qbits );
+}
+
+
+
 /****************
  * Test whether the secret key is valid.
  * Returns: if this is a valid key.
index 07a41ae..2d38a73 100644 (file)
@@ -41,8 +41,9 @@ typedef struct {
 
 void dsa_free_public_key( DSA_public_key *pk );
 void dsa_free_secret_key( DSA_secret_key *sk );
-void dsa_generate( DSA_public_key *pk, DSA_secret_key *sk, unsigned nbits );
 int  dsa_check_secret_key( DSA_secret_key *sk );
+void dsa_generate( DSA_public_key *pk, DSA_secret_key *sk,
+                  unsigned nbits, MPI **ret_factors );
 void dsa_sign(MPI r, MPI s, MPI input, DSA_secret_key *skey);
 int  dsa_verify(MPI r, MPI s, MPI input, DSA_public_key *pkey);
 
index ac02bde..7fad35c 100644 (file)
@@ -139,7 +139,7 @@ elg_generate( ELG_public_key *pk, ELG_secret_key *sk,
     else
        qbits = 240;
     g = mpi_alloc(1);
-    p = generate_elg_prime( nbits, qbits, g, ret_factors );
+    p = generate_elg_prime( 0, nbits, qbits, g, ret_factors );
     mpi_sub_ui(p_min1, p, 1);
 
 
@@ -163,7 +163,7 @@ elg_generate( ELG_public_key *pk, ELG_secret_key *sk,
            }
            else {
                char *r = get_random_bits( 16, 2, 1 );
-               memcpy(rndbuf, r, 16 );
+               memcpy(rndbuf, r, 16/8 );
                m_free(r);
            }
        }
index 6ebaffe..26d21ac 100644 (file)
@@ -63,37 +63,49 @@ generate_public_prime( unsigned  nbits )
  * security from it - The prime number is public and we could also
  * offer the factors for those who are willing to check that it is
  * indeed a strong prime.
+ *
+ * mode 0: Standard
+ *     1: Make sure that at least one factor is of size qbits.
  */
 MPI
-generate_elg_prime( unsigned pbits, unsigned qbits, MPI g, MPI **ret_factors )
+generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
+                   MPI g, MPI **ret_factors )
 {
     int n;  /* number of factors */
     int m;  /* number of primes in pool */
     unsigned fbits; /* length of prime factors */
     MPI *factors; /* current factors */
     MPI *pool; /* pool of primes */
-    MPI q;     /* first prime factor */
+    MPI q;     /* first prime factor (variable)*/
     MPI prime; /* prime test value */
+    MPI q_factor; /* used for mode 1 */
     byte *perms = NULL;
     int i, j;
     int count1, count2;
     unsigned nprime;
+    unsigned req_qbits = qbits; /* the requested q bits size */
 
     /* find number of needed prime factors */
     for(n=1; (pbits - qbits - 1) / n  >= qbits; n++ )
        ;
     n--;
-    if( !n )
+    if( !n || (mode==1 && n < 2) )
        log_fatal("can't gen prime with pbits=%u qbits=%u\n", pbits, qbits );
-    fbits = (pbits - qbits -1) / n;
-    while( qbits + n*fbits < pbits )
-       qbits++;
+    if( mode == 1 ) {
+       n--;
+       fbits = (pbits - 2*req_qbits -1) / n;
+       qbits =  pbits - req_qbits - n*fbits;
+    }
+    else {
+       fbits = (pbits - req_qbits -1) / n;
+       qbits = pbits - n*fbits;
+    }
     if( DBG_CIPHER )
-       log_debug("gen prime: pbits=%u qbits=%u fbits=%u n=%d\n",
-                   pbits, qbits, fbits, n  );
-
+       log_debug("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n",
+                   pbits, req_qbits, qbits, fbits, n  );
     prime = mpi_alloc( (pbits + BITS_PER_MPI_LIMB - 1) /  BITS_PER_MPI_LIMB );
     q = gen_prime( qbits, 0, 1 );
+    q_factor = mode==1? gen_prime( req_qbits, 0, 1 ) : NULL;
 
     /* allocate an array to hold the factors + 2 for later usage */
     factors = m_alloc_clear( (n+2) * sizeof *factors );
@@ -139,6 +151,8 @@ generate_elg_prime( unsigned pbits, unsigned qbits, MPI g, MPI **ret_factors )
 
        mpi_set( prime, q );
        mpi_mul_ui( prime, prime, 2 );
+       if( mode == 1 )
+           mpi_mul( prime, prime, q_factor );
        for(i=0; i < n; i++ )
            mpi_mul( prime, prime, factors[i] );
        mpi_add_ui( prime, prime, 1 );
@@ -171,18 +185,30 @@ generate_elg_prime( unsigned pbits, unsigned qbits, MPI g, MPI **ret_factors )
        putc('\n', stderr);
        log_mpidump( "prime    : ", prime );
        log_mpidump( "factor  q: ", q );
+       if( mode == 1 )
+           log_mpidump( "factor q0: ", q_factor );
        for(i=0; i < n; i++ )
            log_mpidump( "factor pi: ", factors[i] );
        log_debug("bit sizes: prime=%u, q=%u", mpi_get_nbits(prime), mpi_get_nbits(q) );
+       if( mode == 1 )
+           fprintf(stderr, ", q0=%u", mpi_get_nbits(q_factor) );
        for(i=0; i < n; i++ )
            fprintf(stderr, ", p%d=%u", i, mpi_get_nbits(factors[i]) );
        putc('\n', stderr);
     }
 
     if( ret_factors ) { /* caller wants the factors */
-       *ret_factors = m_alloc_clear( (n+1) * sizeof **ret_factors );
-       for(i=0; i < n; i++ )
-           (*ret_factors)[i] = mpi_copy( factors[i] );
+       *ret_factors = m_alloc_clear( (n+2) * sizeof **ret_factors);
+       if( mode == 1 ) {
+           i = 0;
+           (*ret_factors)[i++] = mpi_copy( q_factor );
+           for(; i <= n; i++ )
+               (*ret_factors)[i] = mpi_copy( factors[i] );
+       }
+       else {
+           for(; i < n; i++ )
+               (*ret_factors)[i] = mpi_copy( factors[i] );
+       }
     }
 
     if( g ) { /* create a generator (start with 3)*/
@@ -190,6 +216,8 @@ generate_elg_prime( unsigned pbits, unsigned qbits, MPI g, MPI **ret_factors )
        MPI b     = mpi_alloc( mpi_get_nlimbs(prime) );
        MPI pmin1 = mpi_alloc( mpi_get_nlimbs(prime) );
 
+       if( mode == 1 )
+           BUG(); /* not yet implemented */
        factors[n] = q;
        factors[n+1] = mpi_alloc_set_ui(2);
        mpi_sub_ui( pmin1, prime, 1 );
@@ -230,6 +258,7 @@ generate_elg_prime( unsigned pbits, unsigned qbits, MPI g, MPI **ret_factors )
 }
 
 
+
 static MPI
 gen_prime( unsigned  nbits, int secret, int randomlevel )
 {
index 3ceeb9f..6977025 100644 (file)
@@ -702,10 +702,11 @@ transform( TIGER_CONTEXT *hd, byte *data )
     u64 a,b,c,aa,bb,cc;
     u64 x[8];
   #ifdef BIG_ENDIAN_HOST
-    #define MKWORD(d,n) (  (d)[8*(n)+0] << 56 | (d)[8*(n)+1] << 48  \
-                        | (d)[8*(n)+2] << 40 | (d)[8*(n)+3] << 32  \
-                        | (d)[8*(n)+4] << 24 | (d)[8*(n)+5] << 16  \
-                        | (d)[8*(n)+6] << 8  | (d)[8*(n)+7]       )
+    #define MKWORD(d,n) \
+               (  ((u64)(d)[8*(n)+0]) << 56 | ((u64)(d)[8*(n)+1]) << 48  \
+                | ((u64)(d)[8*(n)+2]) << 40 | ((u64)(d)[8*(n)+3]) << 32  \
+                | ((u64)(d)[8*(n)+4]) << 24 | ((u64)(d)[8*(n)+5]) << 16  \
+                | ((u64)(d)[8*(n)+6]) << 8  | ((u64)(d)[8*(n)+7])       )
     x[0] = MKWORD(data, 0);
     x[1] = MKWORD(data, 1);
     x[2] = MKWORD(data, 2);
index b61ea5c..e69f108 100644 (file)
@@ -1,3 +1,8 @@
+Tue May  5 22:11:59 1998  Werner Koch  (wk@isil.d.shuttle.de)
+
+       * keygen.c (gen_dsa): New.
+       * build_packet.c (do_secret_cert): Support for DSA
+
 Mon May  4 19:01:25 1998  Werner Koch  (wk@isil.d.shuttle.de)
 
        * compress.c: doubled buffer sizes
index 07aaf06..da6e413 100644 (file)
@@ -292,6 +292,29 @@ do_secret_cert( IOBUF out, int ctb, PKT_secret_cert *skc )
        mpi_write(a, skc->d.elg.x );
        write_16(a, skc->csum );
     }
+    else if( skc->pubkey_algo == PUBKEY_ALGO_DSA ) {
+       mpi_write(a, skc->d.dsa.p );
+       mpi_write(a, skc->d.dsa.q );
+       mpi_write(a, skc->d.dsa.g );
+       mpi_write(a, skc->d.dsa.y );
+       if( skc->is_protected ) {
+           iobuf_put(a, 0xff );
+           iobuf_put(a, skc->protect.algo );
+           iobuf_put(a, skc->protect.s2k.mode );
+           iobuf_put(a, skc->protect.s2k.hash_algo );
+           if( skc->protect.s2k.mode == 1
+               || skc->protect.s2k.mode == 4 )
+               iobuf_write(a, skc->protect.s2k.salt, 8 );
+           if( skc->protect.s2k.mode == 4 )
+               write_32(a, skc->protect.s2k.count );
+           iobuf_write(a, skc->protect.iv, 8 );
+       }
+       else
+           iobuf_put(a, 0 );
+
+       mpi_write(a, skc->d.dsa.x );
+       write_16(a, skc->csum );
+    }
     else if( is_RSA(skc->pubkey_algo) ) {
        mpi_write(a, skc->d.rsa.n );
        mpi_write(a, skc->d.rsa.e );
index c068b5b..fdcd462 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -72,6 +72,7 @@ static ARGPARSE_OPTS opts[] = {
     { 515, "fingerprint", 0, N_("list keys and fingerprints")},
   #ifdef IS_G10
     { 503, "gen-key",   0, N_("generate a new key pair")},
+    { 554, "add-key",   0, N_("add a subkey to a key pair")},
     { 506, "sign-key"  ,0, N_("make a signature on a key in the keyring")},
     { 505, "delete-key",0, N_("remove key from the public keyring")},
     { 524, "edit-key"  ,0, N_("edit a key signature")},
@@ -171,7 +172,7 @@ enum cmd_values { aNull = 0,
     aSym, aStore, aEncr, aKeygen, aSign, aSignEncr,
     aSignKey, aClearsign, aListPackets, aEditSig, aDeleteKey, aDeleteSecretKey,
     aKMode, aKModeC, aChangePass, aImport, aVerify, aDecrypt, aListKeys,
-    aListSigs,
+    aListSigs, aKeyadd,
     aExport, aCheckKeys, aGenRevoke, aPrimegen, aPrintMDs,
     aListTrustDB, aListTrustPath, aDeArmor, aEnArmor, aGenRandom, aTest,
 aNOP };
@@ -574,6 +575,7 @@ main( int argc, char **argv )
          case 551: set_cmd( &cmd, aListKeys); break;
          case 552: set_cmd( &cmd, aListSigs); break;
          case 553: opt.skip_verify=1; break;
+         case 554: set_cmd( &cmd, aKeyadd); break;
          default : errors++; pargs.err = configfp? 1:2; break;
        }
     }
@@ -817,6 +819,11 @@ main( int argc, char **argv )
            wrong_args("--gen-key");
        generate_keypair();
        break;
+      case aKeyadd: /* add a subkey (interactive) */
+       if( argc != 1 )
+           wrong_args("--add-key userid");
+       generate_subkeypair(*argv);
+       break;
     #endif
 
       case aImport:
@@ -873,19 +880,24 @@ main( int argc, char **argv )
            putchar('\n');
        }
        else if( argc == 2 ) {
-           mpi_print( stdout, generate_elg_prime( atoi(argv[0]),
+           mpi_print( stdout, generate_elg_prime( 0, atoi(argv[0]),
                                                   atoi(argv[1]), NULL,NULL ), 1);
            putchar('\n');
        }
        else if( argc == 3 ) {
            MPI g = mpi_alloc(1);
-           mpi_print( stdout, generate_elg_prime( atoi(argv[0]),
+           mpi_print( stdout, generate_elg_prime( 0, atoi(argv[0]),
                                                   atoi(argv[1]), g, NULL ), 1);
            printf("\nGenerator: ");
            mpi_print( stdout, g, 1 );
            putchar('\n');
            mpi_free(g);
        }
+       else if( argc == 4 ) {
+           mpi_print( stdout, generate_elg_prime( 1, atoi(argv[0]),
+                                                  atoi(argv[1]), NULL,NULL ), 1);
+           putchar('\n');
+       }
        else
            usage(1);
        break;
index 0a4afbf..a475ed8 100644 (file)
@@ -621,6 +621,8 @@ change_passphrase( const char *username )
        break;
     }
 
+    /* fixme: unprotect all subkeys */
+
     if( rc )
        tty_printf("Can't edit this key: %s\n", g10_errstr(rc));
     else {
@@ -648,6 +650,7 @@ change_passphrase( const char *username )
                break;
            }
            else { /* okay */
+               /* fixme: protect all subkeys too */
                skc->protect.algo = dek->algo;
                skc->protect.s2k = *s2k;
                rc = protect_secret_key( skc, dek );
index e714c16..771dcb3 100644 (file)
@@ -224,11 +224,84 @@ gen_rsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
 #endif /*ENABLE_RSA_KEYGEN*/
 
 
+/****************
+ * Generate a DSA key
+ */
 static int
 gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
-        STRING2KEY *s2k, PKT_secret_cert **ret_skc, u16 valid_days )
+           STRING2KEY *s2k, PKT_secret_cert **ret_skc, u16 valid_days )
 {
-    return G10ERR_GENERAL;
+    int rc;
+    int i;
+    PACKET *pkt;
+    PKT_secret_cert *skc;
+    PKT_public_cert *pkc;
+    DSA_public_key pk;
+    DSA_secret_key sk;
+    MPI *factors;
+
+    if( nbits > 1024 )
+       nbits = 1024;
+
+    dsa_generate( &pk, &sk, nbits, &factors );
+
+    skc = m_alloc_clear( sizeof *skc );
+    pkc = m_alloc_clear( sizeof *pkc );
+    skc->timestamp = pkc->timestamp = make_timestamp();
+    skc->version = pkc->version = 4;
+    /* valid days are not stored in the packet, but it is
+     * used here to put it into the signature.
+     */
+    skc->valid_days = pkc->valid_days = valid_days;
+    skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_DSA;
+                      pkc->d.dsa.p = pk.p;
+                      pkc->d.dsa.q = pk.q;
+                      pkc->d.dsa.g = pk.g;
+                      pkc->d.dsa.y = pk.y;
+    skc->d.dsa.p = sk.p;
+    skc->d.dsa.q = sk.q;
+    skc->d.dsa.g = sk.g;
+    skc->d.dsa.y = sk.y;
+    skc->d.dsa.x = sk.x;
+    skc->is_protected = 0;
+    skc->protect.algo = 0;
+
+    skc->csum = checksum_mpi( skc->d.dsa.x );
+    /* return an unprotected version of the skc */
+    *ret_skc = copy_secret_cert( NULL, skc );
+
+    if( dek ) {
+       skc->protect.algo = dek->algo;
+       skc->protect.s2k = *s2k;
+       rc = protect_secret_key( skc, dek );
+       if( rc ) {
+           log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
+           free_public_cert(pkc);
+           free_secret_cert(skc);
+           return rc;
+       }
+    }
+
+    pkt = m_alloc_clear(sizeof *pkt);
+    pkt->pkttype = PKT_PUBLIC_CERT;
+    pkt->pkt.public_cert = pkc;
+    add_kbnode(pub_root, new_kbnode( pkt ));
+
+    /* don't know whether it makes sense to have the factors, so for now
+     * we store them in the secret keyring (but they are not secret)
+     * p = 2 * q * f1 * f2 * ... * fn
+     * We store only f1 to f_n-1 - fn can be calculated because p and q
+     * are known.
+     */
+    pkt = m_alloc_clear(sizeof *pkt);
+    pkt->pkttype = PKT_SECRET_CERT;
+    pkt->pkt.secret_cert = skc;
+    add_kbnode(sec_root, new_kbnode( pkt ));
+    for(i=1; factors[i]; i++ ) /* the first one is q */
+       add_kbnode( sec_root,
+                   make_mpi_comment_node("#:DSA_factor:", factors[i] ));
+
+    return 0;
 }
 
 
@@ -312,7 +385,7 @@ generate_keypair()
        else if( algo == 2 ) {
            algo = PUBKEY_ALGO_DSA;
            algo_name = "DSA";
-           tty_printf(_("Sorry; DSA key generation is not yet supported.\n"));
+           break;
        }
       #ifdef ENABLE_RSA_KEYGEN
        else if( algo == 3 ) {
@@ -380,6 +453,10 @@ generate_keypair()
                 "      <n>w = key expires in n weeks\n"
                 "      <n>m = key expires in n months\n"
                 "      <n>y = key expires in n years\n"));
+    /* Note: The elgamal subkey for DSA has no exiration date because
+     * is must be signed with the DSA key and this one has the expiration
+     * date */
+
     answer = NULL;
     for(;;) {
        int mult;
@@ -578,7 +655,7 @@ generate_keypair()
        rc = gen_rsa(nbits, pub_root, sec_root, dek, s2k, &skc, valid_days  );
   #endif
     else if( algo == PUBKEY_ALGO_DSA )
-       rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, &skc, valid_days  );
+       rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, &skc, valid_days);
     else
        BUG();
     if( !rc ) {
@@ -663,3 +740,13 @@ generate_keypair()
     m_free(sec_fname);
 }
 
+
+/****************
+ * add a new subkey to an existing key.
+ */
+void
+generate_subkeypair( const char *userid )
+{
+    log_fatal("To be implemented :-)\n");
+}
+
index 9a1ae4d..03436d0 100644 (file)
@@ -70,6 +70,7 @@ int change_passphrase( const char *username );
 
 /*-- keygen.c --*/
 void generate_keypair(void);
+void generate_subkeypair(const char *userid);
 
 /*-- openfile.c --*/
 int overwrite_filep( const char *fname );
index b64d234..a78426b 100644 (file)
@@ -114,7 +114,8 @@ extern ushort small_prime_numbers[];
 /*-- primegen.c --*/
 MPI generate_secret_prime( unsigned nbits );
 MPI generate_public_prime( unsigned nbits );
-MPI generate_elg_prime( unsigned pbits, unsigned qbits, MPI g, MPI **factors );
+MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
+                                          MPI g, MPI **factors );
 
 
 #endif /*G10_CIPHER_H*/
index 8ae5caf..4add32d 100644 (file)
@@ -93,7 +93,7 @@ POSUB = po
 RANLIB = ranlib
 USE_INCLUDED_LIBINTL = yes
 USE_NLS = yes
-VERSION = 0.2.17
+VERSION = 0.2.17a
 ZLIBS = 
 l =