#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

#include "libpgp5.h"

unsigned char dsasd[20] =
{
  0xd5, 0x01, 0x4e, 0x4b,
  0x60, 0xef, 0x2b, 0xa8,
  0xb6, 0x21, 0x1b, 0x40,
  0x62, 0xba, 0x32, 0x24,
  0xe0, 0x42, 0x7d, 0xbd,
};

/* pubkey to stderr, seckey to stdout */
int main(int argc, char *argv[])
{
  unsigned char *pp = NULL, passwdhash[256], userid[256] = "Unknown User";
  extern char *optarg;
  unsigned long long keyid = 0;
  unsigned long long keyid2 = 0;
  int ch, genflag = 0, genflag2 = 0, rsaflag = 0;
  DSA *dsakey = DSA_new();
  DH *dhkey = DH_new();
  FILE *pk, *sk;

  memset(passwdhash, 0, 16);
  while ((ch = getopt(argc, argv, "K:k:p:u:r:g:R3")) != -1) {
    if (ch == 'p') {            /* password */
      pp = passwdhash;
      strcpy(passwdhash, optarg);
    } else if (ch == 'k')
      sscanf(optarg, "%qx", &keyid);
    else if (ch == 'K')
      sscanf(optarg, "%qx", &keyid2);
    else if (ch == 'u')
      strncpy(userid, optarg, 255);
    else if (ch == 'r')
      setkeyring5(optarg);
    else if (ch == 'R')
      rsaflag = 1;
    else if (ch == '3')
      rsaflag = 2;
    else if (ch == 'g')
      sscanf(optarg, "%d", &genflag);
    else if (ch == 'G')
      sscanf(optarg, "%d", &genflag2);
    else {
      fprintf(stderr, "usage: new5key -K DHkeyid -k DSSkeyid [-r ringfile] "
              "[-u \"user name\"] [-p pp]\n"
              " generates new DH/DSS key using fixed params from given keyid\n"
              " (and ring) with optional inital user name and passphrase\n"
              " You may also specify \"-g numbits\" instead of the keyids\n"
              " and a new set of key parameters will be generated (slow!).\n"
              " Using -G numbits will force the DSA size to that value, and\n"
              " use the given -g, or 2 times the DSA numbits for DH\n"
              " -r will generate an RSA key, and -g can specify bits (defaults"
              " to 1024)\n"
              " Raw new keys are written to secnew.skr and pubnew.pkr\n");
      exit(-1);
    }
  }

  if (!rsaflag && (genflag || genflag2)) {
    BIGNUM *pm1 = BN_new(), *gcd = BN_new();
    BN_CTX *ctx = BN_CTX_new();
    if (genflag2)
      dsakey = DSA_generate_parameters(genflag2, dsasd, 20,
                                       NULL, NULL, NULL, NULL);
    else
      dsakey = DSA_generate_parameters(genflag > 2048 ? 1024 : genflag / 2,
                                       dsasd, 20, NULL, NULL, NULL, NULL);
    if (!genflag)
      genflag = genflag2 * 2;
    do {
      dhkey = DH_generate_parameters(genflag, DH_GENERATOR_5, NULL, NULL);
      BN_sub(pm1, dhkey->p, BN_value_one());
      BN_gcd(gcd, dhkey->g, pm1, ctx);
      fprintf(stderr, "Found with gcd ");
      BN_print_fp(stderr, gcd);
      fprintf(stderr, "\n");
    } while (BN_ucmp(gcd, BN_value_one()));
    BN_clear_free(pm1);
  } else if (!rsaflag) {
    if (getkey5(NULL, &dsakey, NULL, &keyid))
      return -10;
    if (getkey5(&dhkey, NULL, NULL, &keyid2))
      return -11;
  }
  sk = fopen("secnew.skr", "wb");
  pk = fopen("pubnew.pkr", "wb");
  if (rsaflag) {
    RSA *rsakey;
    rsakey = RSA_generate_key(genflag, 17, NULL, NULL);  /* PGP: 17 as E */
    if (rsaflag == 2)
      keyout2(sk, pk, pp, userid, rsakey);
    else
      keyout5(sk, pk, rsakey, 1, 1, pp, userid);
  } else {
    DSA_generate_key(dsakey);
    keyout5(sk, pk, dsakey, 1, 17, pp, userid);
    DH_generate_key(dhkey);
    keyout5(sk, pk, dhkey, 0, 16, pp, userid);
  }
  fclose(sk);
  fclose(pk);
  return 0;
}
