Example #1
0
static int
do_public_key( IOBUF out, int ctb, PKT_public_key *pk )
{
    int rc = 0;
    int n, i;
    IOBUF a = iobuf_temp();

    if( !pk->version )
	iobuf_put( a, 3 );
    else
	iobuf_put( a, pk->version );
    write_32(a, pk->timestamp );
    if( pk->version < 4 ) {
	u16 ndays;
	if( pk->expiredate )
	    ndays = (u16)((pk->expiredate - pk->timestamp) / 86400L);
	else
	    ndays = 0;
	write_16(a, ndays );
    }
    iobuf_put(a, pk->pubkey_algo );
    n = pubkey_get_npkey( pk->pubkey_algo );
    if( !n )
	write_fake_data( a, pk->pkey[0] );
    for(i=0; i < n; i++ )
	mpi_write(a, pk->pkey[i] );

    write_header2(out, ctb, iobuf_get_temp_length(a), pk->hdrbytes, 1 );
    if( iobuf_write_temp( out, a ) )
	rc = G10ERR_WRITE_FILE;

    iobuf_close(a);
    return rc;
}
Example #2
0
/****************
 * This is the interface to the public key encryption.
 * Encrypt DATA with PKEY and put it into RESARR which
 * should be an array of MPIs of size PUBKEY_MAX_NENC (or less if the
 * algorithm allows this - check with pubkey_get_nenc() )
 */
int
pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
{
    int i, rc;

    if( DBG_CIPHER ) {
	log_debug("pubkey_encrypt: algo=%d\n", algo );
	for(i=0; i < pubkey_get_npkey(algo); i++ )
	    log_mpidump("  pkey:", pkey[i] );
	log_mpidump("  data:", data );
    }

    do {
	for(i=0; pubkey_table[i].name; i++ )
	    if( pubkey_table[i].algo == algo ) {
		rc = (*pubkey_table[i].encrypt)( algo, resarr, data, pkey );
		goto ready;
	    }
    } while( load_pubkey_modules() );
    rc = G10ERR_PUBKEY_ALGO;
  ready:
    if( !rc && DBG_CIPHER ) {
	for(i=0; i < pubkey_get_nenc(algo); i++ )
	    log_mpidump("  encr:", resarr[i] );
    }
    return rc;
}
Example #3
0
static void
print_key_data( PKT_public_key *pk, u32 *keyid )
{
    int n = pk ? pubkey_get_npkey( pk->pubkey_algo ) : 0;
    int i;

    for(i=0; i < n; i++ ) {
	printf("pkd:%d:%u:", i, mpi_get_nbits( pk->pkey[i] ) );
	mpi_print(stdout, pk->pkey[i], 1 );
	putchar(':');
	putchar('\n');
    }
}
static int
do_public_key( IOBUF out, int ctb, PKT_public_key *pk )
{
  int rc = 0;
  int n, i;
  IOBUF a = iobuf_temp();

  if ( !pk->version )
    iobuf_put( a, 3 );
  else
    iobuf_put( a, pk->version );
  write_32(a, pk->timestamp );

  if ( pk->version < 4 )
    {
      u16 ndays;
      if ( pk->expiredate )
        ndays = (u16)((pk->expiredate - pk->timestamp) / 86400L);
      else
        ndays = 0;
      write_16(a, ndays );
    }
  iobuf_put (a, pk->pubkey_algo );



  if ( pk->pubkey_algo == PUBKEY_ALGO_NTRU){

    rc = sexp_write(a, pk->ntru_pkey);
  }
  else
  {
	  n = pubkey_get_npkey ( pk->pubkey_algo );

	  if ( !n )
	    write_fake_data( a, pk->pkey[0] );
  }

  if (!rc)
    {
      write_header2 (out, ctb, iobuf_get_temp_length(a), pk->hdrbytes);
      printf("write output\n");
      rc = iobuf_write_temp ( out, a );
    }
  printf("finished writing\n");
  iobuf_close(a);
  return rc;
}
/* This function is useful for v4 fingerprints and v3 or v4 key
   signing. */
void
hash_public_key( MD_HANDLE md, PKT_public_key *pk )
{
  unsigned n=6;
  unsigned nb[PUBKEY_MAX_NPKEY];
  unsigned nn[PUBKEY_MAX_NPKEY];
  byte *pp[PUBKEY_MAX_NPKEY];
  int i;
  int npkey = pubkey_get_npkey( pk->pubkey_algo );

  /* Two extra bytes for the expiration date in v3 */
  if(pk->version<4)
    n+=2;

  if(npkey==0 && pk->pkey[0] && mpi_is_opaque(pk->pkey[0]))
    {
      pp[0]=mpi_get_opaque(pk->pkey[0],&nn[0]);
      n+=nn[0];
    }
  else
    for(i=0; i < npkey; i++ )
      {
	nb[i] = mpi_get_nbits(pk->pkey[i]);
	pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL );
	n += 2 + nn[i];
      }

  md_putc( md, 0x99 );     /* ctb */
  /* What does it mean if n is greater than than 0xFFFF ? */
  md_putc( md, n >> 8 );   /* 2 byte length header */
  md_putc( md, n );
  md_putc( md, pk->version );

  md_putc( md, pk->timestamp >> 24 );
  md_putc( md, pk->timestamp >> 16 );
  md_putc( md, pk->timestamp >>  8 );
  md_putc( md, pk->timestamp       );

  if(pk->version<4)
    {
      u16 days=0;
      if(pk->expiredate)
	days=(u16)((pk->expiredate - pk->timestamp) / 86400L);
 
      md_putc( md, days >> 8 );
      md_putc( md, days );
    }
Example #6
0
static MD_HANDLE
do_fingerprint_md( PKT_public_key *pk )
{
    MD_HANDLE md;
    unsigned n;
    unsigned nb[PUBKEY_MAX_NPKEY];
    unsigned nn[PUBKEY_MAX_NPKEY];
    byte *pp[PUBKEY_MAX_NPKEY];
    int i;
    int npkey = pubkey_get_npkey( pk->pubkey_algo );

    md = md_open( pk->version < 4 ? DIGEST_ALGO_RMD160 : DIGEST_ALGO_SHA1, 0);
    n = pk->version < 4 ? 8 : 6;
    for(i=0; i < npkey; i++ ) {
	nb[i] = mpi_get_nbits(pk->pkey[i]);
	pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL );
	n += 2 + nn[i];
    }

    md_putc( md, 0x99 );     /* ctb */
    md_putc( md, n >> 8 );   /* 2 byte length header */
    md_putc( md, n );
    if( pk->version < 4 )
	md_putc( md, 3 );
    else
	md_putc( md, 4 );

    {	u32 a = pk->timestamp;
	md_putc( md, a >> 24 );
	md_putc( md, a >> 16 );
	md_putc( md, a >>  8 );
	md_putc( md, a	     );
    }
    if( pk->version < 4 ) {
	u16 a;

	if( pk->expiredate )
	    a = (u16)((pk->expiredate - pk->timestamp) / 86400L);
	else
	    a = 0;
	md_putc( md, a >> 8 );
	md_putc( md, a	    );
    }
Example #7
0
static int
do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
{
  int rc = 0;
  int i, nskey, npkey;
  IOBUF a = iobuf_temp(); /* Build in a self-enlarging buffer.  */

  /* Write the version number - if none is specified, use 3 */
  if ( !sk->version )
    iobuf_put ( a, 3 );
  else
    iobuf_put ( a, sk->version );
  write_32 (a, sk->timestamp );

  /* v3 needs the expiration time. */
  if ( sk->version < 4 )
    {
      u16 ndays;
      if ( sk->expiredate )
        ndays = (u16)((sk->expiredate - sk->timestamp) / 86400L);
      else
        ndays = 0;
      write_16(a, ndays);
    }
  
  iobuf_put (a, sk->pubkey_algo );
  
  /* Get number of secret and public parameters.  They are held in one
     array first the public ones, then the secret ones.  */
  nskey = pubkey_get_nskey ( sk->pubkey_algo );
  npkey = pubkey_get_npkey ( sk->pubkey_algo );
  
  /* If we don't have any public parameters - which is the case if we
     don't know the algorithm used - the parameters are stored as one
     blob in a faked (opaque) MPI. */
  if ( !npkey ) 
    {
      write_fake_data( a, sk->skey[0] );
      goto leave;
    }
  assert ( npkey < nskey );

  /* Writing the public parameters is easy. */
  for (i=0; i < npkey; i++ )
    if ((rc = mpi_write (a, sk->skey[i])))
      goto leave;
  
  /* Build the header for protected (encrypted) secret parameters.  */
  if ( sk->is_protected ) 
    {
      if ( is_RSA(sk->pubkey_algo) 
           && sk->version < 4
           && !sk->protect.s2k.mode )
        {
          /* The simple rfc1991 (v3) way. */
          iobuf_put (a, sk->protect.algo );
          iobuf_write (a, sk->protect.iv, sk->protect.ivlen );
	}
      else
        {
          /* OpenPGP protection according to rfc2440. */
          iobuf_put(a, sk->protect.sha1chk? 0xfe : 0xff );
          iobuf_put(a, sk->protect.algo );
          if ( sk->protect.s2k.mode >= 1000 )
            {
              /* These modes are not possible in OpenPGP, we use them
                 to implement our extensions, 101 can be seen as a
                 private/experimental extension (this is not specified
                 in rfc2440 but the same scheme is used for all other
                 algorithm identifiers) */
              iobuf_put(a, 101 ); 
              iobuf_put(a, sk->protect.s2k.hash_algo );
              iobuf_write(a, "GNU", 3 );
              iobuf_put(a, sk->protect.s2k.mode - 1000 );
	    }
          else 
            {
              iobuf_put(a, sk->protect.s2k.mode );
              iobuf_put(a, sk->protect.s2k.hash_algo );
	    }
          if ( sk->protect.s2k.mode == 1
               || sk->protect.s2k.mode == 3 )
            iobuf_write (a, sk->protect.s2k.salt, 8 );

          if ( sk->protect.s2k.mode == 3 )
            iobuf_put (a, sk->protect.s2k.count ); 

          /* For our special modes 1001, 1002 we do not need an IV. */
          if ( sk->protect.s2k.mode != 1001 
               && sk->protect.s2k.mode != 1002 )
            iobuf_write (a, sk->protect.iv, sk->protect.ivlen );
	}
    }
  else
    iobuf_put (a, 0 );

  if ( sk->protect.s2k.mode == 1001 )
    ; /* GnuPG extension - don't write a secret key at all. */ 
  else if ( sk->protect.s2k.mode == 1002 )
    { 
      /* GnuPG extension - divert to OpenPGP smartcard. */ 
      iobuf_put(a, sk->protect.ivlen ); /* Length of the serial number
                                           or 0 for no serial
                                           number. */
      /* The serial number gets stored in the IV field. */
      iobuf_write(a, sk->protect.iv, sk->protect.ivlen);
    }
  else if ( sk->is_protected && sk->version >= 4 )
    {
      /* The secret key is protected - write it out as it is.  */
      byte *p;
      unsigned int ndatabits;
      
      assert (gcry_mpi_get_flag (sk->skey[npkey], GCRYMPI_FLAG_OPAQUE));
      p = gcry_mpi_get_opaque (sk->skey[npkey], &ndatabits );
      iobuf_write (a, p, (ndatabits+7)/8 );
    }
  else if ( sk->is_protected ) 
    {
      /* The secret key is protected the old v4 way. */
      for ( ; i < nskey; i++ ) 
        {
          byte *p;
          unsigned int ndatabits;
          
          assert (gcry_mpi_get_flag (sk->skey[i], GCRYMPI_FLAG_OPAQUE));
          p = gcry_mpi_get_opaque (sk->skey[i], &ndatabits);
          iobuf_write (a, p, (ndatabits+7)/8);
        }
      write_16(a, sk->csum );
    }
  else
    {
      /* Non-protected key. */
      for ( ; i < nskey; i++ )
        if ( (rc = mpi_write (a, sk->skey[i])))
          goto leave;
      write_16 (a, sk->csum );
    }

 leave:
  if (!rc)
    {
      /* Build the header of the packet - which we must do after
         writing all the other stuff, so that we know the length of
         the packet */
      write_header2(out, ctb, iobuf_get_temp_length(a), sk->hdrbytes);
      /* And finally write it out the real stream */
      rc = iobuf_write_temp( out, a );
    }

  iobuf_close(a); /* Close the remporary buffer */
  return rc;
}
Example #8
0
static int
xxxx_do_check( PKT_secret_key *sk, const char *tryagain_text, int mode,
               int *canceled )
{
    gpg_error_t err;
    byte *buffer;
    u16 csum=0;
    int i, res;
    size_t nbytes;

    if( sk->is_protected ) { /* remove the protection */
	DEK *dek = NULL;
	u32 keyid[4]; /* 4! because we need two of them */
	gcry_cipher_hd_t cipher_hd=NULL;
	PKT_secret_key *save_sk;

	if( sk->protect.s2k.mode == 1001 ) {
	    log_info(_("secret key parts are not available\n"));
	    return GPG_ERR_UNUSABLE_SECKEY;
	}
	if( sk->protect.algo == CIPHER_ALGO_NONE )
	    BUG();
	if( openpgp_cipher_test_algo( sk->protect.algo ) ) {
	    log_info(_("protection algorithm %d%s is not supported\n"),
			sk->protect.algo,sk->protect.algo==1?" (IDEA)":"" );
	    return GPG_ERR_CIPHER_ALGO;
	}
	if(gcry_md_test_algo (sk->protect.s2k.hash_algo))
	  {
	    log_info(_("protection digest %d is not supported\n"),
		     sk->protect.s2k.hash_algo);
	    return GPG_ERR_DIGEST_ALGO;
	  }
	keyid_from_sk( sk, keyid );
	keyid[2] = keyid[3] = 0;
	if (!sk->flags.primary)
          {
            keyid[2] = sk->main_keyid[0];
            keyid[3] = sk->main_keyid[1];
          }
	dek = passphrase_to_dek( keyid, sk->pubkey_algo, sk->protect.algo,
				 &sk->protect.s2k, mode,
                                 tryagain_text, canceled );
        if (!dek && canceled && *canceled)
	    return GPG_ERR_CANCELED;


	err = openpgp_cipher_open (&cipher_hd, sk->protect.algo,
				   GCRY_CIPHER_MODE_CFB,
				   (GCRY_CIPHER_SECURE
				    | (sk->protect.algo >= 100 ?
				       0 : GCRY_CIPHER_ENABLE_SYNC)));
        if (err)
          log_fatal ("cipher open failed: %s\n", gpg_strerror (err) );

	err = gcry_cipher_setkey (cipher_hd, dek->key, dek->keylen);
        if (err)
          log_fatal ("set key failed: %s\n", gpg_strerror (err) );

	xfree(dek);
	save_sk = copy_secret_key( NULL, sk );

	gcry_cipher_setiv ( cipher_hd, sk->protect.iv, sk->protect.ivlen );

	csum = 0;
	if( sk->version >= 4 ) {
            int ndata;
	    unsigned int ndatabits;
	    byte *p, *data;
            u16 csumc = 0;

	    i = pubkey_get_npkey(sk->pubkey_algo);

            assert ( gcry_mpi_get_flag (sk->skey[i], GCRYMPI_FLAG_OPAQUE ));
            p = gcry_mpi_get_opaque ( sk->skey[i], &ndatabits );
            ndata = (ndatabits+7)/8;

            if ( ndata > 1 )
              csumc = buf16_to_u16 (p+ndata-2);
	    data = xmalloc_secure ( ndata );
	    gcry_cipher_decrypt ( cipher_hd, data, ndata, p, ndata );
	    gcry_mpi_release (sk->skey[i]); sk->skey[i] = NULL ;

	    p = data;
            if (sk->protect.sha1chk) {
                /* This is the new SHA1 checksum method to detect
                   tampering with the key as used by the Klima/Rosa
                   attack */
                sk->csum = 0;
                csum = 1;
                if( ndata < 20 )
                    log_error("not enough bytes for SHA-1 checksum\n");
                else {
                    gcry_md_hd_t h;

                    if ( gcry_md_open (&h, DIGEST_ALGO_SHA1, 1))
                        BUG(); /* Algo not available. */
                    gcry_md_write (h, data, ndata - 20);
                    gcry_md_final (h);
                    if (!memcmp (gcry_md_read (h, DIGEST_ALGO_SHA1),
                                 data + ndata - 20, 20) )
                      {
                        /* Digest does match.  We have to keep the old
                           style checksum in sk->csum, so that the
                           test used for unprotected keys does work.
                           This test gets used when we are adding new
                           keys. */
                        sk->csum = csum = checksum (data, ndata-20);
                      }
                    gcry_md_close (h);
                }
            }
            else {
                if( ndata < 2 ) {
                    log_error("not enough bytes for checksum\n");
                    sk->csum = 0;
                    csum = 1;
                }
                else {
                    csum = checksum( data, ndata-2);
                    sk->csum = data[ndata-2] << 8 | data[ndata-1];
                    if ( sk->csum != csum ) {
                        /* This is a PGP 7.0.0 workaround */
                        sk->csum = csumc; /* take the encrypted one */
                    }
                }
            }

            /* Must check it here otherwise the mpi_read_xx would fail
               because the length may have an arbitrary value */
            if( sk->csum == csum ) {
                for( ; i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
                    if ( gcry_mpi_scan( &sk->skey[i], GCRYMPI_FMT_PGP,
                                        p, ndata, &nbytes))
                      {
                        /* Checksum was okay, but not correctly
                           decrypted.  */
                        sk->csum = 0;
                        csum = 1;
                        break;
                      }
                    ndata -= nbytes;
                    p += nbytes;
                }
                /* Note: at this point ndata should be 2 for a simple
                   checksum or 20 for the sha1 digest */
            }
	    xfree(data);
	}
	else {
	    for(i=pubkey_get_npkey(sk->pubkey_algo);
		    i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
                byte *p;
                size_t ndata;
                unsigned int ndatabits;

                assert (gcry_mpi_get_flag (sk->skey[i], GCRYMPI_FLAG_OPAQUE));
                p = gcry_mpi_get_opaque (sk->skey[i], &ndatabits);
                ndata = (ndatabits+7)/8;
                assert (ndata >= 2);
                assert (ndata == ((p[0] << 8 | p[1]) + 7)/8 + 2);
                buffer = xmalloc_secure (ndata);
		gcry_cipher_sync (cipher_hd);
                buffer[0] = p[0];
                buffer[1] = p[1];
                gcry_cipher_decrypt (cipher_hd, buffer+2, ndata-2,
                                     p+2, ndata-2);
                csum += checksum (buffer, ndata);
                gcry_mpi_release (sk->skey[i]);

		err = gcry_mpi_scan( &sk->skey[i], GCRYMPI_FMT_PGP,
				     buffer, ndata, &ndata );
		xfree (buffer);
                if (err)
                  {
                    /* Checksum was okay, but not correctly
                       decrypted.  */
                    sk->csum = 0;
                    csum = 1;
                    break;
                  }
/*  		csum += checksum_mpi (sk->skey[i]); */
	    }
	}
	gcry_cipher_close ( cipher_hd );

	/* Now let's see whether we have used the correct passphrase. */
	if( csum != sk->csum ) {
	    copy_secret_key( sk, save_sk );
            passphrase_clear_cache ( keyid, NULL, sk->pubkey_algo );
	    free_secret_key( save_sk );
	    return gpg_error (GPG_ERR_BAD_PASSPHRASE);
	}

	/* The checksum may fail, so we also check the key itself. */
	res = pk_check_secret_key ( sk->pubkey_algo, sk->skey );
	if( res ) {
	    copy_secret_key( sk, save_sk );
            passphrase_clear_cache ( keyid, NULL, sk->pubkey_algo );
	    free_secret_key( save_sk );
	    return gpg_error (GPG_ERR_BAD_PASSPHRASE);
	}
	free_secret_key( save_sk );
	sk->is_protected = 0;
    }
    else { /* not protected, assume it is okay if the checksum is okay */
	csum = 0;
	for(i=pubkey_get_npkey(sk->pubkey_algo);
		i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
	    csum += checksum_mpi( sk->skey[i] );
	}
	if( csum != sk->csum )
	    return GPG_ERR_CHECKSUM;
    }

    return 0;
}
Example #9
0
/* Return information about the given algorithm

   WHAT selects the kind of information returned:

    GCRYCTL_TEST_ALGO:
        Returns 0 when the specified algorithm is available for use.
        Buffer must be NULL, nbytes  may have the address of a variable
        with the required usage of the algorithm. It may be 0 for don't
        care or a combination of the GCRY_PK_USAGE_xxx flags;

    GCRYCTL_GET_ALGO_USAGE:
        Return the usage flags for the given algo.  An invalid algo
        returns 0.  Disabled algos are ignored here because we
        only want to know whether the algo is at all capable of
        the usage.

   Note: Because this function is in most cases used to return an
   integer value, we can make it easier for the caller to just look at
   the return value.  The caller will in all cases consult the value
   and thereby detecting whether a error occurred or not (i.e. while
   checking the block size) */
gcry_err_code_t
_gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes)
{
  gcry_err_code_t rc = 0;

  switch (what)
    {
    case GCRYCTL_TEST_ALGO:
      {
	int use = nbytes ? *nbytes : 0;
	if (buffer)
	  rc = GPG_ERR_INV_ARG;
	else if (check_pubkey_algo (algorithm, use))
	  rc = GPG_ERR_PUBKEY_ALGO;
	break;
      }

    case GCRYCTL_GET_ALGO_USAGE:
      {
	gcry_pk_spec_t *spec;

	spec = spec_from_algo (algorithm);
        *nbytes = spec? spec->use : 0;
	break;
      }

    case GCRYCTL_GET_ALGO_NPKEY:
      {
	/* FIXME?  */
	int npkey = pubkey_get_npkey (algorithm);
	*nbytes = npkey;
	break;
      }
    case GCRYCTL_GET_ALGO_NSKEY:
      {
	/* FIXME?  */
	int nskey = pubkey_get_nskey (algorithm);
	*nbytes = nskey;
	break;
      }
    case GCRYCTL_GET_ALGO_NSIGN:
      {
	/* FIXME?  */
	int nsign = pubkey_get_nsig (algorithm);
	*nbytes = nsign;
	break;
      }
    case GCRYCTL_GET_ALGO_NENCR:
      {
	/* FIXME?  */
	int nencr = pubkey_get_nenc (algorithm);
	*nbytes = nencr;
	break;
      }

    default:
      rc = GPG_ERR_INV_OP;
    }

  return rc;
}
Example #10
0
/****************
 * Protect the secret key with the passphrase from DEK
 */
int
protect_secret_key( PKT_secret_key *sk, DEK *dek )
{
    int i,j, rc = 0;
    byte *buffer;
    size_t nbytes;
    u16 csum;

    if( !dek )
	return 0;
    if( !sk->is_protected ) { /* okay, apply the protection */
	gcry_cipher_hd_t cipher_hd=NULL;
	if ( openpgp_cipher_test_algo ( sk->protect.algo ) ) {
            /* Unsupport protection algorithm. */
            rc = gpg_error (GPG_ERR_CIPHER_ALGO);
        }
	else {

	    print_cipher_algo_note( sk->protect.algo );

	    if ( openpgp_cipher_open (&cipher_hd, sk->protect.algo,
				      GCRY_CIPHER_MODE_CFB,
				      (GCRY_CIPHER_SECURE
				       | (sk->protect.algo >= 100 ?
					  0 : GCRY_CIPHER_ENABLE_SYNC))) )
              BUG();
	    if ( gcry_cipher_setkey ( cipher_hd, dek->key, dek->keylen ) )
		log_info(_("WARNING: Weak key detected"
			   " - please change passphrase again.\n"));
	    sk->protect.ivlen = openpgp_cipher_get_algo_blklen (sk->protect.algo);
	    assert( sk->protect.ivlen <= DIM(sk->protect.iv) );
	    if( sk->protect.ivlen != 8 && sk->protect.ivlen != 16 )
		BUG(); /* yes, we are very careful */
	    gcry_create_nonce (sk->protect.iv, sk->protect.ivlen);
	    gcry_cipher_setiv (cipher_hd, sk->protect.iv, sk->protect.ivlen);

	    if( sk->version >= 4 ) {
                byte *bufarr[PUBKEY_MAX_NSKEY];
		size_t narr[PUBKEY_MAX_NSKEY];
		unsigned int nbits[PUBKEY_MAX_NSKEY];
		int ndata=0;
		byte *p, *data;

		for (j=0, i = pubkey_get_npkey(sk->pubkey_algo);
			i < pubkey_get_nskey(sk->pubkey_algo); i++, j++ )
                  {
		    assert (!gcry_mpi_get_flag (sk->skey[i],
                                                GCRYMPI_FLAG_OPAQUE));
		    if (gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j,
                                         narr+j, sk->skey[i]))
                      BUG();
		    nbits[j] = gcry_mpi_get_nbits (sk->skey[i]);
		    ndata += narr[j] + 2;
                  }
		for ( ; j < PUBKEY_MAX_NSKEY; j++ )
                  bufarr[j] = NULL;

		ndata += opt.simple_sk_checksum? 2 : 20; /* for checksum */

		data = xmalloc_secure( ndata );
		p = data;
		for(j=0; j < PUBKEY_MAX_NSKEY && bufarr[j]; j++ ) {
		    p[0] = nbits[j] >> 8 ;
		    p[1] = nbits[j];
		    p += 2;
		    memcpy(p, bufarr[j], narr[j] );
		    p += narr[j];
		    xfree(bufarr[j]);
		}

                if (opt.simple_sk_checksum) {
                    log_info (_("generating the deprecated 16-bit checksum"
                              " for secret key protection\n"));
                    csum = checksum( data, ndata-2);
                    sk->csum = csum;
                    *p++ =	csum >> 8;
                    *p++ =	csum;
                    sk->protect.sha1chk = 0;
                }
                else {