#include "libopgp.h"
#include <rsa.h>
#include <dh.h>

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

int PGP_pkdec(u8_t * dbuf, u8_t * pp)
{
  u8_t *bp;
  int j, ll;
  keyid_t keyid;
  void *deckey;

  /* dbuf[0] should be version - 2, 3, or 4 */
  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 != 16 && j != 20)
    return -2;

  ll = PGP_gtkey(&deckey, pp, &keyid);
  if (ll <= 0)
    return -2;
  if (ll != j)                  /* should retry - dup unlikely for secring */
    return -1;

  if (j == 16 || j == 20) {
    u8_t cbuf[1024];            /* size of key */
    BN_CTX *ctx = BN_CTX_new();
    BIGNUM *a, *b, *c;
    DH *dhkey = deckey;

    a = PGP_mpiBN(&bp);
    b = PGP_mpiBN(&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);
  } else if (j == 1 || j == 2) {
    RSA *rsakey = deckey;
    j = *bp++ << 8, j += *bp++, j = (j + 7) / 8;
    ll = BN_num_bytes(rsakey->n);
    while (j < ll)              /* make the buffer the same size as N */
      memmove(&bp[1], bp, j++), bp[0] = 0;
    j = RSA_private_decrypt(ll, bp, pp, rsakey, RSA_PKCS1_PADDING);
    RSA_free(rsakey);
  } else
    return -1;
  return 0;
}
