generate_raw_key (int algo, unsigned int nbits, u32 created_at,
                  PKT_secret_key **r_sk_unprotected,
                  PKT_secret_key **r_sk_protected)
{
  int rc;
  DEK *dek = NULL;
  STRING2KEY *s2k = NULL;
  PKT_secret_key *sk = NULL;
  int i;
  size_t nskey, npkey;
  gcry_sexp_t s_parms, s_key;
  int canceled;

  npkey = pubkey_get_npkey (algo);
  nskey = pubkey_get_nskey (algo);
  assert (nskey <= PUBKEY_MAX_NSKEY && npkey < nskey);

  if (nbits < 512)
    {
      nbits = 512;
      log_info (_("keysize invalid; using %u bits\n"), nbits );
    }

  if ((nbits % 32))
    {
      nbits = ((nbits + 31) / 32) * 32;
      log_info(_("keysize rounded up to %u bits\n"), nbits );
    }

  dek = do_ask_passphrase (&s2k, 1, &canceled);
  if (canceled)
    {
      rc = gpg_error (GPG_ERR_CANCELED);
      goto leave;
    }

  sk = xmalloc_clear (sizeof *sk);
  sk->timestamp = created_at;
  sk->version = 4;
  sk->pubkey_algo = algo;

  if ( !is_RSA (algo) )
    {
      log_error ("only RSA is supported for offline generated keys\n");
      rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
      goto leave;
    }
  rc = gcry_sexp_build (&s_parms, NULL,
                        "(genkey(rsa(nbits %d)))",
                        (int)nbits);
  if (rc)
    log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc));
  rc = gcry_pk_genkey (&s_key, s_parms);
  gcry_sexp_release (s_parms);
  if (rc)
    {
      log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) );
      goto leave;
    }
  rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu");
  gcry_sexp_release (s_key);
  if (rc)
    {
      log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
      goto leave;
    }

  for (i=npkey; i < nskey; i++)
    sk->csum += checksum_mpi (sk->skey[i]);

  if (r_sk_unprotected)
    *r_sk_unprotected = copy_secret_key (NULL, sk);

  rc = genhelp_protect (dek, s2k, sk);
  if (rc)
    goto leave;

  if (r_sk_protected)
    {
      *r_sk_protected = sk;
      sk = NULL;
    }

 leave:
  if (sk)
    free_secret_key (sk);
  xfree (dek);
  xfree (s2k);
  return rc;
}
generate_raw_key (int algo, unsigned int nbits, u32 created_at,
                  PKT_secret_key **r_sk_unprotected,
                  PKT_secret_key **r_sk_protected)
{
  int rc;
  DEK *dek = NULL;
  STRING2KEY *s2k = NULL;
  PKT_secret_key *sk = NULL;
  int i;
  size_t nskey, npkey;
  gcry_sexp_t s_parms, s_key;
  int canceled;

  npkey = pubkey_get_npkey (algo);
  nskey = pubkey_get_nskey (algo);
  assert (nskey <= PUBKEY_MAX_NSKEY && npkey < nskey);

  if (nbits < 512)
    {
      nbits = 512;
      log_info (_("keysize invalid; using %u bits\n"), nbits );
    }

  if ((nbits % 32))
    {
      nbits = ((nbits + 31) / 32) * 32;
      log_info(_("keysize rounded up to %u bits\n"), nbits );
    }

  dek = do_ask_passphrase (&s2k, 1, &canceled);
  if (canceled)
    {
      rc = gpg_error (GPG_ERR_CANCELED);
      goto leave;
    }

  sk = xmalloc_clear (sizeof *sk);
  sk->timestamp = created_at;
  sk->version = 4;
  sk->pubkey_algo = algo;

  if ( !is_RSA (algo) )
    {
      log_error ("only RSA is supported for offline generated keys\n");
      rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
      goto leave;
    }
  rc = gcry_sexp_build (&s_parms, NULL,
                        "(genkey(rsa(nbits %d)))",
                        (int)nbits);
  if (rc)
    log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc));
  rc = gcry_pk_genkey (&s_key, s_parms);
  gcry_sexp_release (s_parms);
  if (rc)
    {
      log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) );
      goto leave;
    }
  rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu");
  gcry_sexp_release (s_key);
  if (rc)
    {
      log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
      goto leave;
    }

  for (i=npkey; i < nskey; i++)
    sk->csum += checksum_mpi (sk->skey[i]);

  if (r_sk_unprotected)
    *r_sk_unprotected = copy_secret_key (NULL, sk);

  rc = genhelp_protect (dek, s2k, sk);
  if (rc)
    goto leave;

  if (r_sk_protected)
    {
      *r_sk_protected = sk;
      sk = NULL;
    }

 leave:
  if (sk)
    free_secret_key (sk);
  xfree (dek);
  xfree (s2k);
  return rc;
}