#include <sys/file.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <rpc/rpc.h>
#include <rpc/key_prot.h>
#include "externs.h"
static void adjust(char[HEXKEYBYTES+1], char *);
static BIGNUM *itobn(long i);
static void
getseed(char *seed, int seedsize, unsigned char *pass)
{
int i;
for (i = 0; i < seedsize; i++) {
seed[i] = (arc4random() & 0xff) ^ pass[i % 8];
}
}
static BIGNUM *
itobn(long i)
{
BIGNUM *n = NULL;
if ((n = BN_new()) == NULL)
errx(1, "could not create BIGNUM: %s",
ERR_error_string(ERR_get_error(), 0));
BN_init(n);
if (i > 0)
BN_add_word(n, (u_long)i);
else
BN_sub_word(n, (u_long)(-i));
return(n);
}
void
genkeys(char *public, char *secret, char *pass)
{
#define BASEBITS (8*sizeof (short) - 1)
#define BASE (short)(1 << BASEBITS)
unsigned int i;
short r;
unsigned short seed[KEYSIZE/BASEBITS + 1];
char *xkey;
BN_CTX *ctx;
BIGNUM *pk, *sk, *tmp, *base, *root, *modulus;
pk = itobn(0);
sk = itobn(0);
tmp = itobn(0);
base = itobn(BASE);
root = itobn(PROOT);
modulus = NULL;
if (BN_hex2bn(&modulus, HEXMODULUS) == 0)
errx(1, "could not convert modulus to BIGNUM: %s",
ERR_error_string(ERR_get_error(), 0));
if ((ctx = BN_CTX_new()) == NULL)
errx(1, "could not create BN_CTX: %s",
ERR_error_string(ERR_get_error(), 0));
getseed((char *)seed, sizeof (seed), (u_char *)pass);
for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) {
r = seed[i] % BASE;
BN_zero(tmp);
BN_add_word(tmp, r);
BN_mul(sk, base, sk, ctx);
BN_add(sk, tmp, sk);
}
BN_zero(tmp);
BN_div(tmp, sk, sk, modulus, ctx);
BN_mod_exp(pk, root, sk, modulus, ctx);
if ((xkey = BN_bn2hex(sk)) == NULL)
errx(1, "could convert sk to hex: %s",
ERR_error_string(ERR_get_error(), 0));
adjust(secret, xkey);
OPENSSL_free(xkey);
if ((xkey = BN_bn2hex(pk)) == NULL)
errx(1, "could convert pk to hex: %s",
ERR_error_string(ERR_get_error(), 0));
adjust(public, xkey);
OPENSSL_free(xkey);
BN_free(base);
BN_free(modulus);
BN_free(pk);
BN_free(sk);
BN_free(root);
BN_free(tmp);
}
static void
adjust(char keyout[HEXKEYBYTES+1], char *keyin)
{
char *p;
char *s;
for (p = keyin; *p; p++)
;
for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) {
*s = *p;
}
while (s >= keyout) {
*s-- = '0';
}
}