~ubuntu-branches/ubuntu/lucid/openssl/lucid-proposed

« back to all changes in this revision

Viewing changes to demos/jpake/jpakedemo.c

  • Committer: Bazaar Package Importer
  • Author(s): Kurt Roeckx
  • Date: 2009-06-13 18:15:46 UTC
  • mto: (11.1.5 squeeze)
  • mto: This revision was merged to the branch mainline in revision 34.
  • Revision ID: james.westby@ubuntu.com-20090613181546-vbfntai3b009dl1u
Tags: upstream-0.9.8k
ImportĀ upstreamĀ versionĀ 0.9.8k

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "openssl/bn.h"
 
2
#include "openssl/sha.h"
 
3
#include <assert.h>
 
4
#include <string.h>
 
5
#include <stdlib.h>
 
6
 
 
7
/* Copyright (C) 2008 Ben Laurie (ben@links.org) */
 
8
 
 
9
/*
 
10
 * Implement J-PAKE, as described in
 
11
 * http://grouper.ieee.org/groups/1363/Research/contributions/hao-ryan-2008.pdf
 
12
 * 
 
13
 * With hints from http://www.cl.cam.ac.uk/~fh240/software/JPAKE2.java.
 
14
 */
 
15
 
 
16
static void showbn(const char *name, const BIGNUM *bn)
 
17
    {
 
18
    fputs(name, stdout);
 
19
    fputs(" = ", stdout);
 
20
    BN_print_fp(stdout, bn);
 
21
    putc('\n', stdout);
 
22
    }
 
23
 
 
24
typedef struct
 
25
    {
 
26
    BN_CTX *ctx;  // Perhaps not the best place for this?
 
27
    BIGNUM *p;
 
28
    BIGNUM *q;
 
29
    BIGNUM *g;
 
30
    } JPakeParameters;
 
31
 
 
32
static void JPakeParametersInit(JPakeParameters *params)
 
33
    {
 
34
    params->ctx = BN_CTX_new();
 
35
 
 
36
    // For now use p, q, g from Java sample code. Later, generate them.
 
37
    params->p = NULL;
 
38
    BN_hex2bn(&params->p, "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7");
 
39
    params->q = NULL;
 
40
    BN_hex2bn(&params->q, "9760508f15230bccb292b982a2eb840bf0581cf5");
 
41
    params->g = NULL;
 
42
    BN_hex2bn(&params->g, "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d0782675159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a");
 
43
 
 
44
    showbn("p", params->p);
 
45
    showbn("q", params->q);
 
46
    showbn("g", params->g);
 
47
    }
 
48
 
 
49
typedef struct
 
50
    {
 
51
    BIGNUM *gr;  // g^r (r random)
 
52
    BIGNUM *b;   // b = r - x*h, h=hash(g, g^r, g^x, name)
 
53
    } JPakeZKP;
 
54
 
 
55
typedef struct
 
56
    {
 
57
    BIGNUM *gx;       // g^x
 
58
    JPakeZKP zkpx;    // ZKP(x)
 
59
    } JPakeStep1;
 
60
 
 
61
typedef struct
 
62
    {
 
63
    BIGNUM *X;        // g^(xa + xc + xd) * xb * s
 
64
    JPakeZKP zkpxbs;  // ZKP(xb * s)
 
65
    } JPakeStep2;
 
66
 
 
67
typedef struct
 
68
    {
 
69
    const char *name;  // Must be unique
 
70
    int base;          // 1 for Alice, 3 for Bob. Only used for printing stuff.
 
71
    JPakeStep1 s1c;    // Alice's g^x3, ZKP(x3) or Bob's g^x1, ZKP(x1)
 
72
    JPakeStep1 s1d;    // Alice's g^x4, ZKP(x4) or Bob's g^x2, ZKP(x2)
 
73
    JPakeStep2 s2;     // Alice's A, ZKP(x2 * s) or Bob's B, ZKP(x4 * s)
 
74
    } JPakeUserPublic;
 
75
 
 
76
/*
 
77
 * The user structure. In the definition, (xa, xb, xc, xd) are Alice's
 
78
 * (x1, x2, x3, x4) or Bob's (x3, x4, x1, x2). If you see what I mean.
 
79
 */
 
80
typedef struct
 
81
    {
 
82
    JPakeUserPublic p;
 
83
    BIGNUM *secret;    // The shared secret
 
84
    BIGNUM *key;       // The calculated (shared) key
 
85
    BIGNUM *xa;        // Alice's x1 or Bob's x3
 
86
    BIGNUM *xb;        // Alice's x2 or Bob's x4
 
87
    } JPakeUser;
 
88
 
 
89
// Generate each party's random numbers. xa is in [0, q), xb is in [1, q).
 
90
static void genrand(JPakeUser *user, const JPakeParameters *params)
 
91
    {
 
92
    BIGNUM *qm1;
 
93
 
 
94
    // xa in [0, q)
 
95
    user->xa = BN_new();
 
96
    BN_rand_range(user->xa, params->q);
 
97
 
 
98
    // q-1
 
99
    qm1 = BN_new();
 
100
    BN_copy(qm1, params->q);
 
101
    BN_sub_word(qm1, 1);
 
102
 
 
103
    // ... and xb in [0, q-1)
 
104
    user->xb = BN_new();
 
105
    BN_rand_range(user->xb, qm1);
 
106
    // [1, q)
 
107
    BN_add_word(user->xb, 1);
 
108
 
 
109
    // cleanup
 
110
    BN_free(qm1);
 
111
 
 
112
    // Show
 
113
    printf("x%d", user->p.base);
 
114
    showbn("", user->xa);
 
115
    printf("x%d", user->p.base+1);
 
116
    showbn("", user->xb);
 
117
    }
 
118
 
 
119
static void hashlength(SHA_CTX *sha, size_t l)
 
120
    {
 
121
    unsigned char b[2];
 
122
 
 
123
    assert(l <= 0xffff);
 
124
    b[0] = l >> 8;
 
125
    b[1] = l&0xff;
 
126
    SHA1_Update(sha, b, 2);
 
127
    }
 
128
 
 
129
static void hashstring(SHA_CTX *sha, const char *string)
 
130
    {
 
131
    size_t l = strlen(string);
 
132
 
 
133
    hashlength(sha, l);
 
134
    SHA1_Update(sha, string, l);
 
135
    }
 
136
 
 
137
static void hashbn(SHA_CTX *sha, const BIGNUM *bn)
 
138
    {
 
139
    size_t l = BN_num_bytes(bn);
 
140
    unsigned char *bin = alloca(l);
 
141
 
 
142
    hashlength(sha, l);
 
143
    BN_bn2bin(bn, bin);
 
144
    SHA1_Update(sha, bin, l);
 
145
    }
 
146
 
 
147
// h=hash(g, g^r, g^x, name)
 
148
static void zkpHash(BIGNUM *h, const JPakeZKP *zkp, const BIGNUM *gx,
 
149
                    const JPakeUserPublic *from, const JPakeParameters *params)
 
150
    {
 
151
    unsigned char md[SHA_DIGEST_LENGTH];
 
152
    SHA_CTX sha;
 
153
 
 
154
    // XXX: hash should not allow moving of the boundaries - Java code
 
155
    // is flawed in this respect. Length encoding seems simplest.
 
156
    SHA1_Init(&sha);
 
157
    hashbn(&sha, params->g);
 
158
    hashbn(&sha, zkp->gr);
 
159
    hashbn(&sha, gx);
 
160
    hashstring(&sha, from->name);
 
161
    SHA1_Final(md, &sha);
 
162
    BN_bin2bn(md, SHA_DIGEST_LENGTH, h);
 
163
    }
 
164
 
 
165
// Prove knowledge of x
 
166
// Note that we don't send g^x because, as it happens, we've always
 
167
// sent it elsewhere. Also note that because of that, we could avoid
 
168
// calculating it here, but we don't, for clarity...
 
169
static void CreateZKP(JPakeZKP *zkp, const BIGNUM *x, const JPakeUser *us,
 
170
                      const BIGNUM *zkpg, const JPakeParameters *params,
 
171
                      int n, const char *suffix)
 
172
    {
 
173
    BIGNUM *r = BN_new();
 
174
    BIGNUM *gx = BN_new();
 
175
    BIGNUM *h = BN_new();
 
176
    BIGNUM *t = BN_new();
 
177
 
 
178
    // r in [0,q)
 
179
    // XXX: Java chooses r in [0, 2^160) - i.e. distribution not uniform
 
180
    BN_rand_range(r, params->q);
 
181
    // g^r
 
182
    zkp->gr = BN_new();
 
183
    BN_mod_exp(zkp->gr, zkpg, r, params->p, params->ctx);
 
184
    // g^x
 
185
    BN_mod_exp(gx, zkpg, x, params->p, params->ctx);
 
186
 
 
187
    // h=hash...
 
188
    zkpHash(h, zkp, gx, &us->p, params);
 
189
    
 
190
    // b = r - x*h
 
191
    BN_mod_mul(t, x, h, params->q, params->ctx);
 
192
    zkp->b = BN_new();
 
193
    BN_mod_sub(zkp->b, r, t, params->q, params->ctx);
 
194
 
 
195
    // show
 
196
    printf("  ZKP(x%d%s)\n", n, suffix);
 
197
    showbn("   zkpg", zkpg);
 
198
    showbn("    g^x", gx);
 
199
    showbn("    g^r", zkp->gr);
 
200
    showbn("      b", zkp->b);
 
201
 
 
202
    // cleanup
 
203
    BN_free(t);
 
204
    BN_free(h);
 
205
    BN_free(gx);
 
206
    BN_free(r);
 
207
    }
 
208
 
 
209
static int VerifyZKP(const JPakeZKP *zkp, BIGNUM *gx,
 
210
                     const JPakeUserPublic *them, const BIGNUM *zkpg,
 
211
                     const JPakeParameters *params, int n, const char *suffix)
 
212
    {
 
213
    BIGNUM *h = BN_new();
 
214
    BIGNUM *t1 = BN_new();
 
215
    BIGNUM *t2 = BN_new();
 
216
    BIGNUM *t3 = BN_new();
 
217
    int ret = 0;
 
218
 
 
219
    zkpHash(h, zkp, gx, them, params);
 
220
 
 
221
    // t1 = g^b
 
222
    BN_mod_exp(t1, zkpg, zkp->b, params->p, params->ctx);
 
223
    // t2 = (g^x)^h = g^{hx}
 
224
    BN_mod_exp(t2, gx, h, params->p, params->ctx);
 
225
    // t3 = t1 * t2 = g^{hx} * g^b = g^{hx+b} = g^r (allegedly)
 
226
    BN_mod_mul(t3, t1, t2, params->p, params->ctx);
 
227
 
 
228
    printf("  ZKP(x%d%s)\n", n, suffix);
 
229
    showbn("    zkpg", zkpg);
 
230
    showbn("    g^r'", t3);
 
231
 
 
232
    // verify t3 == g^r
 
233
    if(BN_cmp(t3, zkp->gr) == 0)
 
234
        ret = 1;
 
235
 
 
236
    // cleanup
 
237
    BN_free(t3);
 
238
    BN_free(t2);
 
239
    BN_free(t1);
 
240
    BN_free(h);
 
241
 
 
242
    if(ret)
 
243
        puts("    OK");
 
244
    else
 
245
        puts("    FAIL");
 
246
 
 
247
    return ret;
 
248
    }    
 
249
 
 
250
static void sendstep1_substep(JPakeStep1 *s1, const BIGNUM *x,
 
251
                              const JPakeUser *us,
 
252
                              const JPakeParameters *params, int n)
 
253
    {
 
254
    s1->gx = BN_new();
 
255
    BN_mod_exp(s1->gx, params->g, x, params->p, params->ctx);
 
256
    printf("  g^{x%d}", n);
 
257
    showbn("", s1->gx);
 
258
 
 
259
    CreateZKP(&s1->zkpx, x, us, params->g, params, n, "");
 
260
    }
 
261
 
 
262
static void sendstep1(const JPakeUser *us, JPakeUserPublic *them,
 
263
                      const JPakeParameters *params)
 
264
    {
 
265
    printf("\n%s sends %s:\n\n", us->p.name, them->name);
 
266
 
 
267
    // from's g^xa (which becomes to's g^xc) and ZKP(xa)
 
268
    sendstep1_substep(&them->s1c, us->xa, us, params, us->p.base);
 
269
    // from's g^xb (which becomes to's g^xd) and ZKP(xb)
 
270
    sendstep1_substep(&them->s1d, us->xb, us, params, us->p.base+1);
 
271
    }
 
272
 
 
273
static int verifystep1(const JPakeUser *us, const JPakeUserPublic *them,
 
274
                       const JPakeParameters *params)
 
275
    {
 
276
    printf("\n%s verifies %s:\n\n", us->p.name, them->name);
 
277
 
 
278
    // verify their ZKP(xc)
 
279
    if(!VerifyZKP(&us->p.s1c.zkpx, us->p.s1c.gx, them, params->g, params,
 
280
                  them->base, ""))
 
281
        return 0;
 
282
 
 
283
    // verify their ZKP(xd)
 
284
    if(!VerifyZKP(&us->p.s1d.zkpx, us->p.s1d.gx, them, params->g, params,
 
285
                  them->base+1, ""))
 
286
        return 0;
 
287
 
 
288
    // g^xd != 1
 
289
    printf("  g^{x%d} != 1: ", them->base+1);
 
290
    if(BN_is_one(us->p.s1d.gx))
 
291
        {
 
292
        puts("FAIL");
 
293
        return 0;
 
294
        }
 
295
    puts("OK");
 
296
 
 
297
    return 1;
 
298
    }
 
299
 
 
300
static void sendstep2(const JPakeUser *us, JPakeUserPublic *them,
 
301
                      const JPakeParameters *params)
 
302
    {
 
303
    BIGNUM *t1 = BN_new();
 
304
    BIGNUM *t2 = BN_new();
 
305
 
 
306
    printf("\n%s sends %s:\n\n", us->p.name, them->name);
 
307
 
 
308
    // X = g^{(xa + xc + xd) * xb * s}
 
309
    // t1 = g^xa
 
310
    BN_mod_exp(t1, params->g, us->xa, params->p, params->ctx);
 
311
    // t2 = t1 * g^{xc} = g^{xa} * g^{xc} = g^{xa + xc}
 
312
    BN_mod_mul(t2, t1, us->p.s1c.gx, params->p, params->ctx);
 
313
    // t1 = t2 * g^{xd} = g^{xa + xc + xd}
 
314
    BN_mod_mul(t1, t2, us->p.s1d.gx, params->p, params->ctx);
 
315
    // t2 = xb * s
 
316
    BN_mod_mul(t2, us->xb, us->secret, params->q, params->ctx);
 
317
    // X = t1^{t2} = t1^{xb * s} = g^{(xa + xc + xd) * xb * s}
 
318
    them->s2.X = BN_new();
 
319
    BN_mod_exp(them->s2.X, t1, t2, params->p, params->ctx);
 
320
 
 
321
    // Show
 
322
    printf("  g^{(x%d + x%d + x%d) * x%d * s)", us->p.base, them->base,
 
323
           them->base+1, us->p.base+1);
 
324
    showbn("", them->s2.X);
 
325
 
 
326
    // ZKP(xb * s)
 
327
    // XXX: this is kinda funky, because we're using
 
328
    //
 
329
    // g' = g^{xa + xc + xd}
 
330
    //
 
331
    // as the generator, which means X is g'^{xb * s}
 
332
    CreateZKP(&them->s2.zkpxbs, t2, us, t1, params, us->p.base+1, " * s");
 
333
 
 
334
    // cleanup
 
335
    BN_free(t1);
 
336
    BN_free(t2);
 
337
    }
 
338
 
 
339
static int verifystep2(const JPakeUser *us, const JPakeUserPublic *them,
 
340
                       const JPakeParameters *params)
 
341
    {
 
342
    BIGNUM *t1 = BN_new();
 
343
    BIGNUM *t2 = BN_new();
 
344
    int ret = 0;
 
345
 
 
346
    printf("\n%s verifies %s:\n\n", us->p.name, them->name);
 
347
 
 
348
    // g' = g^{xc + xa + xb} [from our POV]
 
349
    // t1 = xa + xb
 
350
    BN_mod_add(t1, us->xa, us->xb, params->q, params->ctx);
 
351
    // t2 = g^{t1} = g^{xa+xb}
 
352
    BN_mod_exp(t2, params->g, t1, params->p, params->ctx);
 
353
    // t1 = g^{xc} * t2 = g^{xc + xa + xb}
 
354
    BN_mod_mul(t1, us->p.s1c.gx, t2, params->p, params->ctx);
 
355
 
 
356
    if(VerifyZKP(&us->p.s2.zkpxbs, us->p.s2.X, them, t1, params, them->base+1,
 
357
                  " * s"))
 
358
        ret = 1;
 
359
 
 
360
    // cleanup
 
361
    BN_free(t2);
 
362
    BN_free(t1);
 
363
 
 
364
    return ret;
 
365
    }
 
366
 
 
367
static void computekey(JPakeUser *us, const JPakeParameters *params)
 
368
    {
 
369
    BIGNUM *t1 = BN_new();
 
370
    BIGNUM *t2 = BN_new();
 
371
    BIGNUM *t3 = BN_new();
 
372
 
 
373
    printf("\n%s calculates the shared key:\n\n", us->p.name);
 
374
 
 
375
    // K = (X/g^{xb * xd * s})^{xb}
 
376
    //   = (g^{(xc + xa + xb) * xd * s - xb * xd *s})^{xb}
 
377
    //   = (g^{(xa + xc) * xd * s})^{xb}
 
378
    //   = g^{(xa + xc) * xb * xd * s}
 
379
    // [which is the same regardless of who calculates it]
 
380
 
 
381
    // t1 = (g^{xd})^{xb} = g^{xb * xd}
 
382
    BN_mod_exp(t1, us->p.s1d.gx, us->xb, params->p, params->ctx);
 
383
    // t2 = -s = q-s
 
384
    BN_sub(t2, params->q, us->secret);
 
385
    // t3 = t1^t2 = g^{-xb * xd * s}
 
386
    BN_mod_exp(t3, t1, t2, params->p, params->ctx);
 
387
    // t1 = X * t3 = X/g^{xb * xd * s}
 
388
    BN_mod_mul(t1, us->p.s2.X, t3, params->p, params->ctx);
 
389
    // K = t1^{xb}
 
390
    us->key = BN_new();
 
391
    BN_mod_exp(us->key, t1, us->xb, params->p, params->ctx);
 
392
 
 
393
    // show
 
394
    showbn("  K", us->key);
 
395
 
 
396
    // cleanup
 
397
    BN_free(t3);
 
398
    BN_free(t2);
 
399
    BN_free(t1);
 
400
    }
 
401
 
 
402
int main(int argc, char **argv)
 
403
    {
 
404
    JPakeParameters params;
 
405
    JPakeUser alice, bob;
 
406
 
 
407
    alice.p.name = "Alice";
 
408
    alice.p.base = 1;
 
409
    bob.p.name = "Bob";
 
410
    bob.p.base = 3;
 
411
 
 
412
    JPakeParametersInit(&params);
 
413
 
 
414
    // Shared secret
 
415
    alice.secret = BN_new();
 
416
    BN_rand(alice.secret, 32, -1, 0);
 
417
    bob.secret = alice.secret;
 
418
    showbn("secret", alice.secret);
 
419
 
 
420
    assert(BN_cmp(alice.secret, params.q) < 0);
 
421
 
 
422
    // Alice's x1, x2
 
423
    genrand(&alice, &params);
 
424
 
 
425
    // Bob's x3, x4
 
426
    genrand(&bob, &params);
 
427
 
 
428
    // Now send stuff to each other...
 
429
    sendstep1(&alice, &bob.p, &params);
 
430
    sendstep1(&bob, &alice.p, &params);
 
431
 
 
432
    // And verify what each other sent
 
433
    if(!verifystep1(&alice, &bob.p, &params))
 
434
        return 1;
 
435
    if(!verifystep1(&bob, &alice.p, &params))
 
436
        return 2;
 
437
 
 
438
    // Second send
 
439
    sendstep2(&alice, &bob.p, &params);
 
440
    sendstep2(&bob, &alice.p, &params);
 
441
 
 
442
    // And second verify
 
443
    if(!verifystep2(&alice, &bob.p, &params))
 
444
        return 3;
 
445
    if(!verifystep2(&bob, &alice.p, &params))
 
446
        return 4;
 
447
 
 
448
    // Compute common key
 
449
    computekey(&alice, &params);
 
450
    computekey(&bob, &params);
 
451
 
 
452
    // Confirm the common key is identical
 
453
    // XXX: if the two secrets are not the same, everything works up
 
454
    // to this point, so the only way to detect a failure is by the
 
455
    // difference in the calculated keys.
 
456
    // Since we're all the same code, just compare them directly. In a
 
457
    // real system, Alice sends Bob H(H(K)), Bob checks it, then sends
 
458
    // back H(K), which Alice checks, or something equivalent.
 
459
    puts("\nAlice and Bob check keys are the same:");
 
460
    if(BN_cmp(alice.key, bob.key) == 0)
 
461
        puts("  OK");
 
462
    else
 
463
        {
 
464
        puts("  FAIL");
 
465
        return 5;
 
466
        }
 
467
 
 
468
    return 0;
 
469
    }