/*
* Implement J-PAKE, as described in
* http://grouper.ieee.org/groups/1363/Research/contributions/hao-ryan-2008.pdf
- *
+ *
* With hints from http://www.cl.cam.ac.uk/~fh240/software/JPAKE2.java.
*/
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; // Perhaps not the best place for this?
+typedef struct {
+ BN_CTX *ctx; // Perhaps not the best place for this?
BIGNUM *p;
BIGNUM *q;
BIGNUM *g;
- } JPakeParameters;
+} JPakeParameters;
-static void JPakeParametersInit(JPakeParameters *params)
- {
+static void JPakeParametersInit(JPakeParameters * params)
+{
params->ctx = BN_CTX_new();
// For now use p, q, g from Java sample code. Later, generate them.
params->p = NULL;
- BN_hex2bn(¶ms->p, "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7");
+ BN_hex2bn(¶ms->p,
+ "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7");
params->q = NULL;
BN_hex2bn(¶ms->q, "9760508f15230bccb292b982a2eb840bf0581cf5");
params->g = NULL;
- BN_hex2bn(¶ms->g, "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d0782675159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a");
+ BN_hex2bn(¶ms->g,
+ "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d0782675159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a");
showbn("p", params->p);
showbn("q", params->q);
showbn("g", params->g);
- }
-
-typedef struct
- {
- BIGNUM *gr; // g^r (r random)
- BIGNUM *b; // b = r - x*h, h=hash(g, g^r, g^x, name)
- } JPakeZKP;
-
-typedef struct
- {
- BIGNUM *gx; // g^x
- JPakeZKP zkpx; // ZKP(x)
- } JPakeStep1;
-
-typedef struct
- {
- BIGNUM *X; // g^(xa + xc + xd) * xb * s
- JPakeZKP zkpxbs; // ZKP(xb * s)
- } JPakeStep2;
-
-typedef struct
- {
- const char *name; // Must be unique
- int base; // 1 for Alice, 3 for Bob. Only used for printing stuff.
- JPakeStep1 s1c; // Alice's g^x3, ZKP(x3) or Bob's g^x1, ZKP(x1)
- JPakeStep1 s1d; // Alice's g^x4, ZKP(x4) or Bob's g^x2, ZKP(x2)
- JPakeStep2 s2; // Alice's A, ZKP(x2 * s) or Bob's B, ZKP(x4 * s)
- } JPakeUserPublic;
+}
+
+typedef struct {
+ BIGNUM *gr; // g^r (r random)
+ BIGNUM *b; // b = r - x*h, h=hash(g, g^r, g^x, name)
+} JPakeZKP;
+
+typedef struct {
+ BIGNUM *gx; // g^x
+ JPakeZKP zkpx; // ZKP(x)
+} JPakeStep1;
+
+typedef struct {
+ BIGNUM *X; // g^(xa + xc + xd) * xb * s
+ JPakeZKP zkpxbs; // ZKP(xb * s)
+} JPakeStep2;
+
+typedef struct {
+ const char *name; // Must be unique
+ int base; // 1 for Alice, 3 for Bob. Only used for
+ // printing stuff.
+ JPakeStep1 s1c; // Alice's g^x3, ZKP(x3) or Bob's g^x1,
+ // ZKP(x1)
+ JPakeStep1 s1d; // Alice's g^x4, ZKP(x4) or Bob's g^x2,
+ // ZKP(x2)
+ JPakeStep2 s2; // Alice's A, ZKP(x2 * s) or Bob's B, ZKP(x4
+ // * s)
+} JPakeUserPublic;
/*
* The user structure. In the definition, (xa, xb, xc, xd) are Alice's
* (x1, x2, x3, x4) or Bob's (x3, x4, x1, x2). If you see what I mean.
*/
-typedef struct
- {
+typedef struct {
JPakeUserPublic p;
- BIGNUM *secret; // The shared secret
- BIGNUM *key; // The calculated (shared) key
- BIGNUM *xa; // Alice's x1 or Bob's x3
- BIGNUM *xb; // Alice's x2 or Bob's x4
- } JPakeUser;
+ BIGNUM *secret; // The shared secret
+ BIGNUM *key; // The calculated (shared) key
+ BIGNUM *xa; // Alice's x1 or Bob's x3
+ BIGNUM *xb; // Alice's x2 or Bob's x4
+} JPakeUser;
// Generate each party's random numbers. xa is in [0, q), xb is in [1, q).
-static void genrand(JPakeUser *user, const JPakeParameters *params)
- {
+static void genrand(JPakeUser * user, const JPakeParameters * params)
+{
BIGNUM *qm1;
// xa in [0, q)
// Show
printf("x%d", user->p.base);
showbn("", user->xa);
- printf("x%d", user->p.base+1);
+ 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;
+ 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);
- }
+}
// h=hash(g, g^r, g^x, name)
-static void zkpHash(BIGNUM *h, const JPakeZKP *zkp, const BIGNUM *gx,
- const JPakeUserPublic *from, const JPakeParameters *params)
- {
+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;
hashstring(&sha, from->name);
SHA1_Final(md, &sha);
BN_bin2bn(md, SHA_DIGEST_LENGTH, h);
- }
+}
// Prove knowledge of x
// Note that we don't send g^x because, as it happens, we've always
// sent it elsewhere. Also note that because of that, we could avoid
// calculating it here, but we don't, for clarity...
-static void CreateZKP(JPakeZKP *zkp, const BIGNUM *x, const JPakeUser *us,
- const BIGNUM *zkpg, const JPakeParameters *params,
- int n, const char *suffix)
- {
+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();
// h=hash...
zkpHash(h, zkp, gx, &us->p, params);
-
+
// b = r - x*h
BN_mod_mul(t, x, h, params->q, params->ctx);
zkp->b = BN_new();
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)
- {
+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();
showbn(" g^r'", t3);
// verify t3 == g^r
- if(BN_cmp(t3, zkp->gr) == 0)
- ret = 1;
+ if (BN_cmp(t3, zkp->gr) == 0)
+ ret = 1;
// cleanup
BN_free(t3);
BN_free(t1);
BN_free(h);
- if(ret)
- puts(" OK");
+ if (ret)
+ puts(" OK");
else
- puts(" FAIL");
+ puts(" FAIL");
return ret;
- }
+}
-static void sendstep1_substep(JPakeStep1 *s1, const BIGNUM *x,
- const JPakeUser *us,
- const JPakeParameters *params, int n)
- {
+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)
- {
+static void sendstep1(const JPakeUser * us, JPakeUserPublic * them,
+ const JPakeParameters * params)
+{
printf("\n%s sends %s:\n\n", us->p.name, them->name);
// from's g^xa (which becomes to's g^xc) and ZKP(xa)
sendstep1_substep(&them->s1c, us->xa, us, params, us->p.base);
// from's g^xb (which becomes to's g^xd) and ZKP(xb)
- sendstep1_substep(&them->s1d, us->xb, us, params, us->p.base+1);
- }
+ sendstep1_substep(&them->s1d, us->xb, us, params, us->p.base + 1);
+}
-static int verifystep1(const JPakeUser *us, const JPakeUserPublic *them,
- const JPakeParameters *params)
- {
+static int verifystep1(const JPakeUser * us, const JPakeUserPublic * them,
+ const JPakeParameters * params)
+{
printf("\n%s verifies %s:\n\n", us->p.name, them->name);
// verify their ZKP(xc)
- if(!VerifyZKP(&us->p.s1c.zkpx, us->p.s1c.gx, them, params->g, params,
- them->base, ""))
- return 0;
+ if (!VerifyZKP(&us->p.s1c.zkpx, us->p.s1c.gx, them, params->g, params,
+ them->base, ""))
+ return 0;
// verify their ZKP(xd)
- if(!VerifyZKP(&us->p.s1d.zkpx, us->p.s1d.gx, them, params->g, params,
- them->base+1, ""))
- return 0;
+ if (!VerifyZKP(&us->p.s1d.zkpx, us->p.s1d.gx, them, params->g, params,
+ them->base + 1, ""))
+ return 0;
// g^xd != 1
- printf(" g^{x%d} != 1: ", them->base+1);
- if(BN_is_one(us->p.s1d.gx))
- {
- puts("FAIL");
- 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)
- {
+static void sendstep2(const JPakeUser * us, JPakeUserPublic * them,
+ const JPakeParameters * params)
+{
BIGNUM *t1 = BN_new();
BIGNUM *t2 = BN_new();
// Show
printf(" g^{(x%d + x%d + x%d) * x%d * s)", us->p.base, them->base,
- them->base+1, us->p.base+1);
+ them->base + 1, us->p.base + 1);
showbn("", them->s2.X);
// ZKP(xb * s)
// g' = g^{xa + xc + xd}
//
// as the generator, which means X is g'^{xb * s}
- CreateZKP(&them->s2.zkpxbs, t2, us, t1, params, us->p.base+1, " * s");
+ CreateZKP(&them->s2.zkpxbs, t2, us, t1, params, us->p.base + 1, " * s");
// cleanup
BN_free(t1);
BN_free(t2);
- }
+}
-static int verifystep2(const JPakeUser *us, const JPakeUserPublic *them,
- const JPakeParameters *params)
- {
+static int verifystep2(const JPakeUser * us, const JPakeUserPublic * them,
+ const JPakeParameters * params)
+{
BIGNUM *t1 = BN_new();
BIGNUM *t2 = BN_new();
int ret = 0;
// t1 = g^{xc} * t2 = g^{xc + xa + xb}
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;
+ if (VerifyZKP
+ (&us->p.s2.zkpxbs, us->p.s2.X, them, t1, params, them->base + 1,
+ " * s"))
+ ret = 1;
// cleanup
BN_free(t2);
BN_free(t1);
return ret;
- }
+}
-static void computekey(JPakeUser *us, const JPakeParameters *params)
- {
+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);
// K = (X/g^{xb * xd * s})^{xb}
- // = (g^{(xc + xa + xb) * xd * s - xb * xd *s})^{xb}
- // = (g^{(xa + xc) * xd * s})^{xb}
- // = g^{(xa + xc) * xb * xd * s}
+ // = (g^{(xc + xa + xb) * xd * s - xb * xd *s})^{xb}
+ // = (g^{(xa + xc) * xd * s})^{xb}
+ // = g^{(xa + xc) * xb * xd * s}
// [which is the same regardless of who calculates it]
// t1 = (g^{xd})^{xb} = g^{xb * xd}
BN_free(t3);
BN_free(t2);
BN_free(t1);
- }
+}
int main(int argc, char **argv)
- {
+{
JPakeParameters params;
JPakeUser alice, bob;
sendstep1(&bob, &alice.p, ¶ms);
// And verify what each other sent
- if(!verifystep1(&alice, &bob.p, ¶ms))
- return 1;
- if(!verifystep1(&bob, &alice.p, ¶ms))
- return 2;
+ if (!verifystep1(&alice, &bob.p, ¶ms))
+ return 1;
+ if (!verifystep1(&bob, &alice.p, ¶ms))
+ return 2;
// Second send
sendstep2(&alice, &bob.p, ¶ms);
sendstep2(&bob, &alice.p, ¶ms);
// And second verify
- if(!verifystep2(&alice, &bob.p, ¶ms))
- return 3;
- if(!verifystep2(&bob, &alice.p, ¶ms))
- return 4;
+ if (!verifystep2(&alice, &bob.p, ¶ms))
+ return 3;
+ if (!verifystep2(&bob, &alice.p, ¶ms))
+ return 4;
// Compute common key
computekey(&alice, ¶ms);
// real system, Alice sends Bob H(H(K)), Bob checks it, then sends
// back H(K), which Alice checks, or something equivalent.
puts("\nAlice and Bob check keys are the same:");
- if(BN_cmp(alice.key, bob.key) == 0)
- puts(" OK");
- else
- {
- puts(" FAIL");
- return 5;
- }
+ if (BN_cmp(alice.key, bob.key) == 0)
+ puts(" OK");
+ else {
+ puts(" FAIL");
+ return 5;
+ }
return 0;
- }
+}