#include "openssl/bn.h"
#include "openssl/sha.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
static void showbn(const char *name, const BIGNUM *bn)
{
fputs(name, stdout);
fputs(" = ", stdout);
BN_print_fp(stdout, bn);
putc('\n', stdout);
}
typedef struct
{
BN_CTX *ctx; BIGNUM *p;
BIGNUM *q;
BIGNUM *g;
} JPakeParameters;
static void JPakeParametersInit(JPakeParameters *params)
{
params->ctx = BN_CTX_new();
params->p = NULL;
BN_hex2bn(¶ms->p, "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7");
params->q = NULL;
BN_hex2bn(¶ms->q, "9760508f15230bccb292b982a2eb840bf0581cf5");
params->g = NULL;
BN_hex2bn(¶ms->g, "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d0782675159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a");
showbn("p", params->p);
showbn("q", params->q);
showbn("g", params->g);
}
typedef struct
{
BIGNUM *gr; BIGNUM *b; } JPakeZKP;
typedef struct
{
BIGNUM *gx; JPakeZKP zkpx; } JPakeStep1;
typedef struct
{
BIGNUM *X; JPakeZKP zkpxbs; } JPakeStep2;
typedef struct
{
const char *name; int base; JPakeStep1 s1c; JPakeStep1 s1d; JPakeStep2 s2; } JPakeUserPublic;
typedef struct
{
JPakeUserPublic p;
BIGNUM *secret; BIGNUM *key; BIGNUM *xa; BIGNUM *xb; } JPakeUser;
static void genrand(JPakeUser *user, const JPakeParameters *params)
{
BIGNUM *qm1;
user->xa = BN_new();
BN_rand_range(user->xa, params->q);
qm1 = BN_new();
BN_copy(qm1, params->q);
BN_sub_word(qm1, 1);
user->xb = BN_new();
BN_rand_range(user->xb, qm1);
BN_add_word(user->xb, 1);
BN_free(qm1);
printf("x%d", user->p.base);
showbn("", user->xa);
printf("x%d", user->p.base+1);
showbn("", user->xb);
}
static void hashlength(SHA_CTX *sha, size_t l)
{
unsigned char b[2];
assert(l <= 0xffff);
b[0] = l >> 8;
b[1] = l&0xff;
SHA1_Update(sha, b, 2);
}
static void hashstring(SHA_CTX *sha, const char *string)
{
size_t l = strlen(string);
hashlength(sha, l);
SHA1_Update(sha, string, l);
}
static void hashbn(SHA_CTX *sha, const BIGNUM *bn)
{
size_t l = BN_num_bytes(bn);
unsigned char *bin = alloca(l);
hashlength(sha, l);
BN_bn2bin(bn, bin);
SHA1_Update(sha, bin, l);
}
static void zkpHash(BIGNUM *h, const JPakeZKP *zkp, const BIGNUM *gx,
const JPakeUserPublic *from, const JPakeParameters *params)
{
unsigned char md[SHA_DIGEST_LENGTH];
SHA_CTX sha;
SHA1_Init(&sha);
hashbn(&sha, params->g);
hashbn(&sha, zkp->gr);
hashbn(&sha, gx);
hashstring(&sha, from->name);
SHA1_Final(md, &sha);
BN_bin2bn(md, SHA_DIGEST_LENGTH, h);
}
static void CreateZKP(JPakeZKP *zkp, const BIGNUM *x, const JPakeUser *us,
const BIGNUM *zkpg, const JPakeParameters *params,
int n, const char *suffix)
{
BIGNUM *r = BN_new();
BIGNUM *gx = BN_new();
BIGNUM *h = BN_new();
BIGNUM *t = BN_new();
BN_rand_range(r, params->q);
zkp->gr = BN_new();
BN_mod_exp(zkp->gr, zkpg, r, params->p, params->ctx);
BN_mod_exp(gx, zkpg, x, params->p, params->ctx);
zkpHash(h, zkp, gx, &us->p, params);
BN_mod_mul(t, x, h, params->q, params->ctx);
zkp->b = BN_new();
BN_mod_sub(zkp->b, r, t, params->q, params->ctx);
printf(" ZKP(x%d%s)\n", n, suffix);
showbn(" zkpg", zkpg);
showbn(" g^x", gx);
showbn(" g^r", zkp->gr);
showbn(" b", zkp->b);
BN_free(t);
BN_free(h);
BN_free(gx);
BN_free(r);
}
static int VerifyZKP(const JPakeZKP *zkp, BIGNUM *gx,
const JPakeUserPublic *them, const BIGNUM *zkpg,
const JPakeParameters *params, int n, const char *suffix)
{
BIGNUM *h = BN_new();
BIGNUM *t1 = BN_new();
BIGNUM *t2 = BN_new();
BIGNUM *t3 = BN_new();
int ret = 0;
zkpHash(h, zkp, gx, them, params);
BN_mod_exp(t1, zkpg, zkp->b, params->p, params->ctx);
BN_mod_exp(t2, gx, h, params->p, params->ctx);
BN_mod_mul(t3, t1, t2, params->p, params->ctx);
printf(" ZKP(x%d%s)\n", n, suffix);
showbn(" zkpg", zkpg);
showbn(" g^r'", t3);
if(BN_cmp(t3, zkp->gr) == 0)
ret = 1;
BN_free(t3);
BN_free(t2);
BN_free(t1);
BN_free(h);
if(ret)
puts(" OK");
else
puts(" FAIL");
return ret;
}
static void sendstep1_substep(JPakeStep1 *s1, const BIGNUM *x,
const JPakeUser *us,
const JPakeParameters *params, int n)
{
s1->gx = BN_new();
BN_mod_exp(s1->gx, params->g, x, params->p, params->ctx);
printf(" g^{x%d}", n);
showbn("", s1->gx);
CreateZKP(&s1->zkpx, x, us, params->g, params, n, "");
}
static void sendstep1(const JPakeUser *us, JPakeUserPublic *them,
const JPakeParameters *params)
{
printf("\n%s sends %s:\n\n", us->p.name, them->name);
sendstep1_substep(&them->s1c, us->xa, us, params, us->p.base);
sendstep1_substep(&them->s1d, us->xb, us, params, us->p.base+1);
}
static int verifystep1(const JPakeUser *us, const JPakeUserPublic *them,
const JPakeParameters *params)
{
printf("\n%s verifies %s:\n\n", us->p.name, them->name);
if(!VerifyZKP(&us->p.s1c.zkpx, us->p.s1c.gx, them, params->g, params,
them->base, ""))
return 0;
if(!VerifyZKP(&us->p.s1d.zkpx, us->p.s1d.gx, them, params->g, params,
them->base+1, ""))
return 0;
printf(" g^{x%d} != 1: ", them->base+1);
if(BN_is_one(us->p.s1d.gx))
{
puts("FAIL");
return 0;
}
puts("OK");
return 1;
}
static void sendstep2(const JPakeUser *us, JPakeUserPublic *them,
const JPakeParameters *params)
{
BIGNUM *t1 = BN_new();
BIGNUM *t2 = BN_new();
printf("\n%s sends %s:\n\n", us->p.name, them->name);
BN_mod_exp(t1, params->g, us->xa, params->p, params->ctx);
BN_mod_mul(t2, t1, us->p.s1c.gx, params->p, params->ctx);
BN_mod_mul(t1, t2, us->p.s1d.gx, params->p, params->ctx);
BN_mod_mul(t2, us->xb, us->secret, params->q, params->ctx);
them->s2.X = BN_new();
BN_mod_exp(them->s2.X, t1, t2, params->p, params->ctx);
printf(" g^{(x%d + x%d + x%d) * x%d * s)", us->p.base, them->base,
them->base+1, us->p.base+1);
showbn("", them->s2.X);
CreateZKP(&them->s2.zkpxbs, t2, us, t1, params, us->p.base+1, " * s");
BN_free(t1);
BN_free(t2);
}
static int verifystep2(const JPakeUser *us, const JPakeUserPublic *them,
const JPakeParameters *params)
{
BIGNUM *t1 = BN_new();
BIGNUM *t2 = BN_new();
int ret = 0;
printf("\n%s verifies %s:\n\n", us->p.name, them->name);
BN_mod_add(t1, us->xa, us->xb, params->q, params->ctx);
BN_mod_exp(t2, params->g, t1, params->p, params->ctx);
BN_mod_mul(t1, us->p.s1c.gx, t2, params->p, params->ctx);
if(VerifyZKP(&us->p.s2.zkpxbs, us->p.s2.X, them, t1, params, them->base+1,
" * s"))
ret = 1;
BN_free(t2);
BN_free(t1);
return ret;
}
static void computekey(JPakeUser *us, const JPakeParameters *params)
{
BIGNUM *t1 = BN_new();
BIGNUM *t2 = BN_new();
BIGNUM *t3 = BN_new();
printf("\n%s calculates the shared key:\n\n", us->p.name);
BN_mod_exp(t1, us->p.s1d.gx, us->xb, params->p, params->ctx);
BN_sub(t2, params->q, us->secret);
BN_mod_exp(t3, t1, t2, params->p, params->ctx);
BN_mod_mul(t1, us->p.s2.X, t3, params->p, params->ctx);
us->key = BN_new();
BN_mod_exp(us->key, t1, us->xb, params->p, params->ctx);
showbn(" K", us->key);
BN_free(t3);
BN_free(t2);
BN_free(t1);
}
int main(int argc, char **argv)
{
JPakeParameters params;
JPakeUser alice, bob;
alice.p.name = "Alice";
alice.p.base = 1;
bob.p.name = "Bob";
bob.p.base = 3;
JPakeParametersInit(¶ms);
alice.secret = BN_new();
BN_rand(alice.secret, 32, -1, 0);
bob.secret = alice.secret;
showbn("secret", alice.secret);
assert(BN_cmp(alice.secret, params.q) < 0);
genrand(&alice, ¶ms);
genrand(&bob, ¶ms);
sendstep1(&alice, &bob.p, ¶ms);
sendstep1(&bob, &alice.p, ¶ms);
if(!verifystep1(&alice, &bob.p, ¶ms))
return 1;
if(!verifystep1(&bob, &alice.p, ¶ms))
return 2;
sendstep2(&alice, &bob.p, ¶ms);
sendstep2(&bob, &alice.p, ¶ms);
if(!verifystep2(&alice, &bob.p, ¶ms))
return 3;
if(!verifystep2(&bob, &alice.p, ¶ms))
return 4;
computekey(&alice, ¶ms);
computekey(&bob, ¶ms);
puts("\nAlice and Bob check keys are the same:");
if(BN_cmp(alice.key, bob.key) == 0)
puts(" OK");
else
{
puts(" FAIL");
return 5;
}
return 0;
}