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

#include "libpgp5.h"

/*--------------------------------------------------*/
/* recover conventional key material */

int pkedec5(unsigned char *dbuf, unsigned char *pp)
{
  unsigned char cbuf[4096], *bp;
  int j, ll;
  unsigned long long keyid;

  /* dbuf[0] should be version, 3 */
  bp = dbuf + 1;                /* keyid */
  for (j = 0; j < 8; j++)
    keyid = (keyid << 8) + *bp++;
  j = *bp++;                    /* alg byte */
  if (j && j != 1 && j != 2 && j != 0x10)
    return -2;
  if (j == 0x10) {
    DH *dhkey = DH_new();
    if (getkey5(&dhkey, NULL, pp, &keyid)) {
      DH_free(dhkey);
      fprintf(stderr, "Bad key or passphrase\n");
      return -1;
    }
    /* get DH a & b, and do decrypt */
    {
      BN_CTX *ctx = BN_CTX_new();
      BIGNUM *a, *b, *c;
      a = pgp2BN5(&bp);
      b = pgp2BN5(&bp);
      BN_mod_exp(a, a, dhkey->priv_key, dhkey->p, ctx);
      c = BN_mod_inverse(a, dhkey->p, ctx);
      BN_mod_mul(a, c, b, dhkey->p, ctx);
      DH_free(dhkey), BN_clear_free(b), BN_clear_free(c), BN_CTX_free(ctx);
      j = BN_bn2bin(a, cbuf);
      BN_clear_free(a);
    }
    bp = cbuf;
    while (*bp++ && --j);       /* find 0, start of real data */
    memcpy(pp, bp, j);
  }
#ifndef NO_RSA
  else if (j == 1 || j == 2) {
    RSA *rsakey = RSA_new();
    if (getkey5((DH **) & rsakey, (DSA **) & rsakey, pp, &keyid)) {
      RSA_free(rsakey);
      return -1;
    }
    j = *bp++ << 8, j += *bp++;
    j = (j + 7) / 8;
    ll = BN_num_bytes(rsakey->n);
    while (j < ll)
      memmove(&bp[1], bp, j++), bp[0] = 0;
    j = RSA_private_decrypt(ll, bp, pp, rsakey, RSA_PKCS1_PADDING);
    RSA_free(rsakey);
  }
#endif
  else
    return -1;
  return 0;
}
