From 5fc5d37330d3535a0f421632694d1e7918fc22d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 8 Apr 2014 11:38:09 +0200 Subject: Compiles correctly: app/build-native + gradle. --- app/openssl/crypto/jpake/jpake.c | 511 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 511 insertions(+) create mode 100644 app/openssl/crypto/jpake/jpake.c (limited to 'app/openssl/crypto/jpake/jpake.c') diff --git a/app/openssl/crypto/jpake/jpake.c b/app/openssl/crypto/jpake/jpake.c new file mode 100644 index 00000000..8e4b633c --- /dev/null +++ b/app/openssl/crypto/jpake/jpake.c @@ -0,0 +1,511 @@ +#include "jpake.h" + +#include +#include +#include +#include + +/* + * 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 + { + char *name; /* Must be unique */ + char *peer_name; + BIGNUM *p; + BIGNUM *g; + BIGNUM *q; + BIGNUM *gxc; /* Alice's g^{x3} or Bob's g^{x1} */ + BIGNUM *gxd; /* Alice's g^{x4} or Bob's g^{x2} */ + } JPAKE_CTX_PUBLIC; + +struct JPAKE_CTX + { + JPAKE_CTX_PUBLIC p; + BIGNUM *secret; /* The shared secret */ + BN_CTX *ctx; + BIGNUM *xa; /* Alice's x1 or Bob's x3 */ + BIGNUM *xb; /* Alice's x2 or Bob's x4 */ + BIGNUM *key; /* The calculated (shared) key */ + }; + +static void JPAKE_ZKP_init(JPAKE_ZKP *zkp) + { + zkp->gr = BN_new(); + zkp->b = BN_new(); + } + +static void JPAKE_ZKP_release(JPAKE_ZKP *zkp) + { + BN_free(zkp->b); + BN_free(zkp->gr); + } + +/* Two birds with one stone - make the global name as expected */ +#define JPAKE_STEP_PART_init JPAKE_STEP2_init +#define JPAKE_STEP_PART_release JPAKE_STEP2_release + +void JPAKE_STEP_PART_init(JPAKE_STEP_PART *p) + { + p->gx = BN_new(); + JPAKE_ZKP_init(&p->zkpx); + } + +void JPAKE_STEP_PART_release(JPAKE_STEP_PART *p) + { + JPAKE_ZKP_release(&p->zkpx); + BN_free(p->gx); + } + +void JPAKE_STEP1_init(JPAKE_STEP1 *s1) + { + JPAKE_STEP_PART_init(&s1->p1); + JPAKE_STEP_PART_init(&s1->p2); + } + +void JPAKE_STEP1_release(JPAKE_STEP1 *s1) + { + JPAKE_STEP_PART_release(&s1->p2); + JPAKE_STEP_PART_release(&s1->p1); + } + +static void JPAKE_CTX_init(JPAKE_CTX *ctx, const char *name, + const char *peer_name, const BIGNUM *p, + const BIGNUM *g, const BIGNUM *q, + const BIGNUM *secret) + { + ctx->p.name = OPENSSL_strdup(name); + ctx->p.peer_name = OPENSSL_strdup(peer_name); + ctx->p.p = BN_dup(p); + ctx->p.g = BN_dup(g); + ctx->p.q = BN_dup(q); + ctx->secret = BN_dup(secret); + + ctx->p.gxc = BN_new(); + ctx->p.gxd = BN_new(); + + ctx->xa = BN_new(); + ctx->xb = BN_new(); + ctx->key = BN_new(); + ctx->ctx = BN_CTX_new(); + } + +static void JPAKE_CTX_release(JPAKE_CTX *ctx) + { + BN_CTX_free(ctx->ctx); + BN_clear_free(ctx->key); + BN_clear_free(ctx->xb); + BN_clear_free(ctx->xa); + + BN_free(ctx->p.gxd); + BN_free(ctx->p.gxc); + + BN_clear_free(ctx->secret); + BN_free(ctx->p.q); + BN_free(ctx->p.g); + BN_free(ctx->p.p); + OPENSSL_free(ctx->p.peer_name); + OPENSSL_free(ctx->p.name); + + memset(ctx, '\0', sizeof *ctx); + } + +JPAKE_CTX *JPAKE_CTX_new(const char *name, const char *peer_name, + const BIGNUM *p, const BIGNUM *g, const BIGNUM *q, + const BIGNUM *secret) + { + JPAKE_CTX *ctx = OPENSSL_malloc(sizeof *ctx); + + JPAKE_CTX_init(ctx, name, peer_name, p, g, q, secret); + + return ctx; + } + +void JPAKE_CTX_free(JPAKE_CTX *ctx) + { + JPAKE_CTX_release(ctx); + OPENSSL_free(ctx); + } + +static void hashlength(SHA_CTX *sha, size_t l) + { + unsigned char b[2]; + + OPENSSL_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 = OPENSSL_malloc(l); + + hashlength(sha, l); + BN_bn2bin(bn, bin); + SHA1_Update(sha, bin, l); + OPENSSL_free(bin); + } + +/* h=hash(g, g^r, g^x, name) */ +static void zkp_hash(BIGNUM *h, const BIGNUM *zkpg, const JPAKE_STEP_PART *p, + const char *proof_name) + { + unsigned char md[SHA_DIGEST_LENGTH]; + SHA_CTX sha; + + /* + * XXX: hash should not allow moving of the boundaries - Java code + * is flawed in this respect. Length encoding seems simplest. + */ + SHA1_Init(&sha); + hashbn(&sha, zkpg); + OPENSSL_assert(!BN_is_zero(p->zkpx.gr)); + hashbn(&sha, p->zkpx.gr); + hashbn(&sha, p->gx); + hashstring(&sha, proof_name); + SHA1_Final(md, &sha); + BN_bin2bn(md, SHA_DIGEST_LENGTH, h); + } + +/* + * Prove knowledge of x + * Note that p->gx has already been calculated + */ +static void generate_zkp(JPAKE_STEP_PART *p, const BIGNUM *x, + const BIGNUM *zkpg, JPAKE_CTX *ctx) + { + BIGNUM *r = BN_new(); + BIGNUM *h = BN_new(); + BIGNUM *t = BN_new(); + + /* + * r in [0,q) + * XXX: Java chooses r in [0, 2^160) - i.e. distribution not uniform + */ + BN_rand_range(r, ctx->p.q); + /* g^r */ + BN_mod_exp(p->zkpx.gr, zkpg, r, ctx->p.p, ctx->ctx); + + /* h=hash... */ + zkp_hash(h, zkpg, p, ctx->p.name); + + /* b = r - x*h */ + BN_mod_mul(t, x, h, ctx->p.q, ctx->ctx); + BN_mod_sub(p->zkpx.b, r, t, ctx->p.q, ctx->ctx); + + /* cleanup */ + BN_free(t); + BN_free(h); + BN_free(r); + } + +static int verify_zkp(const JPAKE_STEP_PART *p, const BIGNUM *zkpg, + JPAKE_CTX *ctx) + { + BIGNUM *h = BN_new(); + BIGNUM *t1 = BN_new(); + BIGNUM *t2 = BN_new(); + BIGNUM *t3 = BN_new(); + int ret = 0; + + zkp_hash(h, zkpg, p, ctx->p.peer_name); + + /* t1 = g^b */ + BN_mod_exp(t1, zkpg, p->zkpx.b, ctx->p.p, ctx->ctx); + /* t2 = (g^x)^h = g^{hx} */ + BN_mod_exp(t2, p->gx, h, ctx->p.p, ctx->ctx); + /* t3 = t1 * t2 = g^{hx} * g^b = g^{hx+b} = g^r (allegedly) */ + BN_mod_mul(t3, t1, t2, ctx->p.p, ctx->ctx); + + /* verify t3 == g^r */ + if(BN_cmp(t3, p->zkpx.gr) == 0) + ret = 1; + else + JPAKEerr(JPAKE_F_VERIFY_ZKP, JPAKE_R_ZKP_VERIFY_FAILED); + + /* cleanup */ + BN_free(t3); + BN_free(t2); + BN_free(t1); + BN_free(h); + + return ret; + } + +static void generate_step_part(JPAKE_STEP_PART *p, const BIGNUM *x, + const BIGNUM *g, JPAKE_CTX *ctx) + { + BN_mod_exp(p->gx, g, x, ctx->p.p, ctx->ctx); + generate_zkp(p, x, g, ctx); + } + +/* Generate each party's random numbers. xa is in [0, q), xb is in [1, q). */ +static void genrand(JPAKE_CTX *ctx) + { + BIGNUM *qm1; + + /* xa in [0, q) */ + BN_rand_range(ctx->xa, ctx->p.q); + + /* q-1 */ + qm1 = BN_new(); + BN_copy(qm1, ctx->p.q); + BN_sub_word(qm1, 1); + + /* ... and xb in [0, q-1) */ + BN_rand_range(ctx->xb, qm1); + /* [1, q) */ + BN_add_word(ctx->xb, 1); + + /* cleanup */ + BN_free(qm1); + } + +int JPAKE_STEP1_generate(JPAKE_STEP1 *send, JPAKE_CTX *ctx) + { + genrand(ctx); + generate_step_part(&send->p1, ctx->xa, ctx->p.g, ctx); + generate_step_part(&send->p2, ctx->xb, ctx->p.g, ctx); + + return 1; + } + +/* g^x is a legal value */ +static int is_legal(const BIGNUM *gx, const JPAKE_CTX *ctx) + { + BIGNUM *t; + int res; + + if(BN_is_negative(gx) || BN_is_zero(gx) || BN_cmp(gx, ctx->p.p) >= 0) + return 0; + + t = BN_new(); + BN_mod_exp(t, gx, ctx->p.q, ctx->p.p, ctx->ctx); + res = BN_is_one(t); + BN_free(t); + + return res; + } + +int JPAKE_STEP1_process(JPAKE_CTX *ctx, const JPAKE_STEP1 *received) + { + if(!is_legal(received->p1.gx, ctx)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_G_TO_THE_X3_IS_NOT_LEGAL); + return 0; + } + + if(!is_legal(received->p2.gx, ctx)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_G_TO_THE_X4_IS_NOT_LEGAL); + return 0; + } + + /* verify their ZKP(xc) */ + if(!verify_zkp(&received->p1, ctx->p.g, ctx)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_VERIFY_X3_FAILED); + return 0; + } + + /* verify their ZKP(xd) */ + if(!verify_zkp(&received->p2, ctx->p.g, ctx)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_VERIFY_X4_FAILED); + return 0; + } + + /* g^xd != 1 */ + if(BN_is_one(received->p2.gx)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_G_TO_THE_X4_IS_ONE); + return 0; + } + + /* Save the bits we need for later */ + BN_copy(ctx->p.gxc, received->p1.gx); + BN_copy(ctx->p.gxd, received->p2.gx); + + return 1; + } + + +int JPAKE_STEP2_generate(JPAKE_STEP2 *send, JPAKE_CTX *ctx) + { + BIGNUM *t1 = BN_new(); + BIGNUM *t2 = BN_new(); + + /* + * X = g^{(xa + xc + xd) * xb * s} + * t1 = g^xa + */ + BN_mod_exp(t1, ctx->p.g, ctx->xa, ctx->p.p, ctx->ctx); + /* t2 = t1 * g^{xc} = g^{xa} * g^{xc} = g^{xa + xc} */ + BN_mod_mul(t2, t1, ctx->p.gxc, ctx->p.p, ctx->ctx); + /* t1 = t2 * g^{xd} = g^{xa + xc + xd} */ + BN_mod_mul(t1, t2, ctx->p.gxd, ctx->p.p, ctx->ctx); + /* t2 = xb * s */ + BN_mod_mul(t2, ctx->xb, ctx->secret, ctx->p.q, ctx->ctx); + + /* + * ZKP(xb * s) + * XXX: this is kinda funky, because we're using + * + * g' = g^{xa + xc + xd} + * + * as the generator, which means X is g'^{xb * s} + * X = t1^{t2} = t1^{xb * s} = g^{(xa + xc + xd) * xb * s} + */ + generate_step_part(send, t2, t1, ctx); + + /* cleanup */ + BN_free(t1); + BN_free(t2); + + return 1; + } + +/* gx = g^{xc + xa + xb} * xd * s */ +static int compute_key(JPAKE_CTX *ctx, const BIGNUM *gx) + { + BIGNUM *t1 = BN_new(); + BIGNUM *t2 = BN_new(); + BIGNUM *t3 = BN_new(); + + /* + * K = (gx/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} + * [which is the same regardless of who calculates it] + */ + + /* t1 = (g^{xd})^{xb} = g^{xb * xd} */ + BN_mod_exp(t1, ctx->p.gxd, ctx->xb, ctx->p.p, ctx->ctx); + /* t2 = -s = q-s */ + BN_sub(t2, ctx->p.q, ctx->secret); + /* t3 = t1^t2 = g^{-xb * xd * s} */ + BN_mod_exp(t3, t1, t2, ctx->p.p, ctx->ctx); + /* t1 = gx * t3 = X/g^{xb * xd * s} */ + BN_mod_mul(t1, gx, t3, ctx->p.p, ctx->ctx); + /* K = t1^{xb} */ + BN_mod_exp(ctx->key, t1, ctx->xb, ctx->p.p, ctx->ctx); + + /* cleanup */ + BN_free(t3); + BN_free(t2); + BN_free(t1); + + return 1; + } + +int JPAKE_STEP2_process(JPAKE_CTX *ctx, const JPAKE_STEP2 *received) + { + BIGNUM *t1 = BN_new(); + BIGNUM *t2 = BN_new(); + int ret = 0; + + /* + * g' = g^{xc + xa + xb} [from our POV] + * t1 = xa + xb + */ + BN_mod_add(t1, ctx->xa, ctx->xb, ctx->p.q, ctx->ctx); + /* t2 = g^{t1} = g^{xa+xb} */ + BN_mod_exp(t2, ctx->p.g, t1, ctx->p.p, ctx->ctx); + /* t1 = g^{xc} * t2 = g^{xc + xa + xb} */ + BN_mod_mul(t1, ctx->p.gxc, t2, ctx->p.p, ctx->ctx); + + if(verify_zkp(received, t1, ctx)) + ret = 1; + else + JPAKEerr(JPAKE_F_JPAKE_STEP2_PROCESS, JPAKE_R_VERIFY_B_FAILED); + + compute_key(ctx, received->gx); + + /* cleanup */ + BN_free(t2); + BN_free(t1); + + return ret; + } + +static void quickhashbn(unsigned char *md, const BIGNUM *bn) + { + SHA_CTX sha; + + SHA1_Init(&sha); + hashbn(&sha, bn); + SHA1_Final(md, &sha); + } + +void JPAKE_STEP3A_init(JPAKE_STEP3A *s3a) + {} + +int JPAKE_STEP3A_generate(JPAKE_STEP3A *send, JPAKE_CTX *ctx) + { + quickhashbn(send->hhk, ctx->key); + SHA1(send->hhk, sizeof send->hhk, send->hhk); + + return 1; + } + +int JPAKE_STEP3A_process(JPAKE_CTX *ctx, const JPAKE_STEP3A *received) + { + unsigned char hhk[SHA_DIGEST_LENGTH]; + + quickhashbn(hhk, ctx->key); + SHA1(hhk, sizeof hhk, hhk); + if(memcmp(hhk, received->hhk, sizeof hhk)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP3A_PROCESS, JPAKE_R_HASH_OF_HASH_OF_KEY_MISMATCH); + return 0; + } + return 1; + } + +void JPAKE_STEP3A_release(JPAKE_STEP3A *s3a) + {} + +void JPAKE_STEP3B_init(JPAKE_STEP3B *s3b) + {} + +int JPAKE_STEP3B_generate(JPAKE_STEP3B *send, JPAKE_CTX *ctx) + { + quickhashbn(send->hk, ctx->key); + + return 1; + } + +int JPAKE_STEP3B_process(JPAKE_CTX *ctx, const JPAKE_STEP3B *received) + { + unsigned char hk[SHA_DIGEST_LENGTH]; + + quickhashbn(hk, ctx->key); + if(memcmp(hk, received->hk, sizeof hk)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP3B_PROCESS, JPAKE_R_HASH_OF_KEY_MISMATCH); + return 0; + } + return 1; + } + +void JPAKE_STEP3B_release(JPAKE_STEP3B *s3b) + {} + +const BIGNUM *JPAKE_get_shared_key(JPAKE_CTX *ctx) + { + return ctx->key; + } + -- cgit v1.2.3 From 3c3421afd8f74a3aa8d1011de07a8c18f9549210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 8 Apr 2014 12:04:17 +0200 Subject: Rename app->bitmask_android This way, gradle commands generate apks correctly named. --- app/openssl/crypto/jpake/jpake.c | 511 --------------------------------------- 1 file changed, 511 deletions(-) delete mode 100644 app/openssl/crypto/jpake/jpake.c (limited to 'app/openssl/crypto/jpake/jpake.c') diff --git a/app/openssl/crypto/jpake/jpake.c b/app/openssl/crypto/jpake/jpake.c deleted file mode 100644 index 8e4b633c..00000000 --- a/app/openssl/crypto/jpake/jpake.c +++ /dev/null @@ -1,511 +0,0 @@ -#include "jpake.h" - -#include -#include -#include -#include - -/* - * 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 - { - char *name; /* Must be unique */ - char *peer_name; - BIGNUM *p; - BIGNUM *g; - BIGNUM *q; - BIGNUM *gxc; /* Alice's g^{x3} or Bob's g^{x1} */ - BIGNUM *gxd; /* Alice's g^{x4} or Bob's g^{x2} */ - } JPAKE_CTX_PUBLIC; - -struct JPAKE_CTX - { - JPAKE_CTX_PUBLIC p; - BIGNUM *secret; /* The shared secret */ - BN_CTX *ctx; - BIGNUM *xa; /* Alice's x1 or Bob's x3 */ - BIGNUM *xb; /* Alice's x2 or Bob's x4 */ - BIGNUM *key; /* The calculated (shared) key */ - }; - -static void JPAKE_ZKP_init(JPAKE_ZKP *zkp) - { - zkp->gr = BN_new(); - zkp->b = BN_new(); - } - -static void JPAKE_ZKP_release(JPAKE_ZKP *zkp) - { - BN_free(zkp->b); - BN_free(zkp->gr); - } - -/* Two birds with one stone - make the global name as expected */ -#define JPAKE_STEP_PART_init JPAKE_STEP2_init -#define JPAKE_STEP_PART_release JPAKE_STEP2_release - -void JPAKE_STEP_PART_init(JPAKE_STEP_PART *p) - { - p->gx = BN_new(); - JPAKE_ZKP_init(&p->zkpx); - } - -void JPAKE_STEP_PART_release(JPAKE_STEP_PART *p) - { - JPAKE_ZKP_release(&p->zkpx); - BN_free(p->gx); - } - -void JPAKE_STEP1_init(JPAKE_STEP1 *s1) - { - JPAKE_STEP_PART_init(&s1->p1); - JPAKE_STEP_PART_init(&s1->p2); - } - -void JPAKE_STEP1_release(JPAKE_STEP1 *s1) - { - JPAKE_STEP_PART_release(&s1->p2); - JPAKE_STEP_PART_release(&s1->p1); - } - -static void JPAKE_CTX_init(JPAKE_CTX *ctx, const char *name, - const char *peer_name, const BIGNUM *p, - const BIGNUM *g, const BIGNUM *q, - const BIGNUM *secret) - { - ctx->p.name = OPENSSL_strdup(name); - ctx->p.peer_name = OPENSSL_strdup(peer_name); - ctx->p.p = BN_dup(p); - ctx->p.g = BN_dup(g); - ctx->p.q = BN_dup(q); - ctx->secret = BN_dup(secret); - - ctx->p.gxc = BN_new(); - ctx->p.gxd = BN_new(); - - ctx->xa = BN_new(); - ctx->xb = BN_new(); - ctx->key = BN_new(); - ctx->ctx = BN_CTX_new(); - } - -static void JPAKE_CTX_release(JPAKE_CTX *ctx) - { - BN_CTX_free(ctx->ctx); - BN_clear_free(ctx->key); - BN_clear_free(ctx->xb); - BN_clear_free(ctx->xa); - - BN_free(ctx->p.gxd); - BN_free(ctx->p.gxc); - - BN_clear_free(ctx->secret); - BN_free(ctx->p.q); - BN_free(ctx->p.g); - BN_free(ctx->p.p); - OPENSSL_free(ctx->p.peer_name); - OPENSSL_free(ctx->p.name); - - memset(ctx, '\0', sizeof *ctx); - } - -JPAKE_CTX *JPAKE_CTX_new(const char *name, const char *peer_name, - const BIGNUM *p, const BIGNUM *g, const BIGNUM *q, - const BIGNUM *secret) - { - JPAKE_CTX *ctx = OPENSSL_malloc(sizeof *ctx); - - JPAKE_CTX_init(ctx, name, peer_name, p, g, q, secret); - - return ctx; - } - -void JPAKE_CTX_free(JPAKE_CTX *ctx) - { - JPAKE_CTX_release(ctx); - OPENSSL_free(ctx); - } - -static void hashlength(SHA_CTX *sha, size_t l) - { - unsigned char b[2]; - - OPENSSL_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 = OPENSSL_malloc(l); - - hashlength(sha, l); - BN_bn2bin(bn, bin); - SHA1_Update(sha, bin, l); - OPENSSL_free(bin); - } - -/* h=hash(g, g^r, g^x, name) */ -static void zkp_hash(BIGNUM *h, const BIGNUM *zkpg, const JPAKE_STEP_PART *p, - const char *proof_name) - { - unsigned char md[SHA_DIGEST_LENGTH]; - SHA_CTX sha; - - /* - * XXX: hash should not allow moving of the boundaries - Java code - * is flawed in this respect. Length encoding seems simplest. - */ - SHA1_Init(&sha); - hashbn(&sha, zkpg); - OPENSSL_assert(!BN_is_zero(p->zkpx.gr)); - hashbn(&sha, p->zkpx.gr); - hashbn(&sha, p->gx); - hashstring(&sha, proof_name); - SHA1_Final(md, &sha); - BN_bin2bn(md, SHA_DIGEST_LENGTH, h); - } - -/* - * Prove knowledge of x - * Note that p->gx has already been calculated - */ -static void generate_zkp(JPAKE_STEP_PART *p, const BIGNUM *x, - const BIGNUM *zkpg, JPAKE_CTX *ctx) - { - BIGNUM *r = BN_new(); - BIGNUM *h = BN_new(); - BIGNUM *t = BN_new(); - - /* - * r in [0,q) - * XXX: Java chooses r in [0, 2^160) - i.e. distribution not uniform - */ - BN_rand_range(r, ctx->p.q); - /* g^r */ - BN_mod_exp(p->zkpx.gr, zkpg, r, ctx->p.p, ctx->ctx); - - /* h=hash... */ - zkp_hash(h, zkpg, p, ctx->p.name); - - /* b = r - x*h */ - BN_mod_mul(t, x, h, ctx->p.q, ctx->ctx); - BN_mod_sub(p->zkpx.b, r, t, ctx->p.q, ctx->ctx); - - /* cleanup */ - BN_free(t); - BN_free(h); - BN_free(r); - } - -static int verify_zkp(const JPAKE_STEP_PART *p, const BIGNUM *zkpg, - JPAKE_CTX *ctx) - { - BIGNUM *h = BN_new(); - BIGNUM *t1 = BN_new(); - BIGNUM *t2 = BN_new(); - BIGNUM *t3 = BN_new(); - int ret = 0; - - zkp_hash(h, zkpg, p, ctx->p.peer_name); - - /* t1 = g^b */ - BN_mod_exp(t1, zkpg, p->zkpx.b, ctx->p.p, ctx->ctx); - /* t2 = (g^x)^h = g^{hx} */ - BN_mod_exp(t2, p->gx, h, ctx->p.p, ctx->ctx); - /* t3 = t1 * t2 = g^{hx} * g^b = g^{hx+b} = g^r (allegedly) */ - BN_mod_mul(t3, t1, t2, ctx->p.p, ctx->ctx); - - /* verify t3 == g^r */ - if(BN_cmp(t3, p->zkpx.gr) == 0) - ret = 1; - else - JPAKEerr(JPAKE_F_VERIFY_ZKP, JPAKE_R_ZKP_VERIFY_FAILED); - - /* cleanup */ - BN_free(t3); - BN_free(t2); - BN_free(t1); - BN_free(h); - - return ret; - } - -static void generate_step_part(JPAKE_STEP_PART *p, const BIGNUM *x, - const BIGNUM *g, JPAKE_CTX *ctx) - { - BN_mod_exp(p->gx, g, x, ctx->p.p, ctx->ctx); - generate_zkp(p, x, g, ctx); - } - -/* Generate each party's random numbers. xa is in [0, q), xb is in [1, q). */ -static void genrand(JPAKE_CTX *ctx) - { - BIGNUM *qm1; - - /* xa in [0, q) */ - BN_rand_range(ctx->xa, ctx->p.q); - - /* q-1 */ - qm1 = BN_new(); - BN_copy(qm1, ctx->p.q); - BN_sub_word(qm1, 1); - - /* ... and xb in [0, q-1) */ - BN_rand_range(ctx->xb, qm1); - /* [1, q) */ - BN_add_word(ctx->xb, 1); - - /* cleanup */ - BN_free(qm1); - } - -int JPAKE_STEP1_generate(JPAKE_STEP1 *send, JPAKE_CTX *ctx) - { - genrand(ctx); - generate_step_part(&send->p1, ctx->xa, ctx->p.g, ctx); - generate_step_part(&send->p2, ctx->xb, ctx->p.g, ctx); - - return 1; - } - -/* g^x is a legal value */ -static int is_legal(const BIGNUM *gx, const JPAKE_CTX *ctx) - { - BIGNUM *t; - int res; - - if(BN_is_negative(gx) || BN_is_zero(gx) || BN_cmp(gx, ctx->p.p) >= 0) - return 0; - - t = BN_new(); - BN_mod_exp(t, gx, ctx->p.q, ctx->p.p, ctx->ctx); - res = BN_is_one(t); - BN_free(t); - - return res; - } - -int JPAKE_STEP1_process(JPAKE_CTX *ctx, const JPAKE_STEP1 *received) - { - if(!is_legal(received->p1.gx, ctx)) - { - JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_G_TO_THE_X3_IS_NOT_LEGAL); - return 0; - } - - if(!is_legal(received->p2.gx, ctx)) - { - JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_G_TO_THE_X4_IS_NOT_LEGAL); - return 0; - } - - /* verify their ZKP(xc) */ - if(!verify_zkp(&received->p1, ctx->p.g, ctx)) - { - JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_VERIFY_X3_FAILED); - return 0; - } - - /* verify their ZKP(xd) */ - if(!verify_zkp(&received->p2, ctx->p.g, ctx)) - { - JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_VERIFY_X4_FAILED); - return 0; - } - - /* g^xd != 1 */ - if(BN_is_one(received->p2.gx)) - { - JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_G_TO_THE_X4_IS_ONE); - return 0; - } - - /* Save the bits we need for later */ - BN_copy(ctx->p.gxc, received->p1.gx); - BN_copy(ctx->p.gxd, received->p2.gx); - - return 1; - } - - -int JPAKE_STEP2_generate(JPAKE_STEP2 *send, JPAKE_CTX *ctx) - { - BIGNUM *t1 = BN_new(); - BIGNUM *t2 = BN_new(); - - /* - * X = g^{(xa + xc + xd) * xb * s} - * t1 = g^xa - */ - BN_mod_exp(t1, ctx->p.g, ctx->xa, ctx->p.p, ctx->ctx); - /* t2 = t1 * g^{xc} = g^{xa} * g^{xc} = g^{xa + xc} */ - BN_mod_mul(t2, t1, ctx->p.gxc, ctx->p.p, ctx->ctx); - /* t1 = t2 * g^{xd} = g^{xa + xc + xd} */ - BN_mod_mul(t1, t2, ctx->p.gxd, ctx->p.p, ctx->ctx); - /* t2 = xb * s */ - BN_mod_mul(t2, ctx->xb, ctx->secret, ctx->p.q, ctx->ctx); - - /* - * ZKP(xb * s) - * XXX: this is kinda funky, because we're using - * - * g' = g^{xa + xc + xd} - * - * as the generator, which means X is g'^{xb * s} - * X = t1^{t2} = t1^{xb * s} = g^{(xa + xc + xd) * xb * s} - */ - generate_step_part(send, t2, t1, ctx); - - /* cleanup */ - BN_free(t1); - BN_free(t2); - - return 1; - } - -/* gx = g^{xc + xa + xb} * xd * s */ -static int compute_key(JPAKE_CTX *ctx, const BIGNUM *gx) - { - BIGNUM *t1 = BN_new(); - BIGNUM *t2 = BN_new(); - BIGNUM *t3 = BN_new(); - - /* - * K = (gx/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} - * [which is the same regardless of who calculates it] - */ - - /* t1 = (g^{xd})^{xb} = g^{xb * xd} */ - BN_mod_exp(t1, ctx->p.gxd, ctx->xb, ctx->p.p, ctx->ctx); - /* t2 = -s = q-s */ - BN_sub(t2, ctx->p.q, ctx->secret); - /* t3 = t1^t2 = g^{-xb * xd * s} */ - BN_mod_exp(t3, t1, t2, ctx->p.p, ctx->ctx); - /* t1 = gx * t3 = X/g^{xb * xd * s} */ - BN_mod_mul(t1, gx, t3, ctx->p.p, ctx->ctx); - /* K = t1^{xb} */ - BN_mod_exp(ctx->key, t1, ctx->xb, ctx->p.p, ctx->ctx); - - /* cleanup */ - BN_free(t3); - BN_free(t2); - BN_free(t1); - - return 1; - } - -int JPAKE_STEP2_process(JPAKE_CTX *ctx, const JPAKE_STEP2 *received) - { - BIGNUM *t1 = BN_new(); - BIGNUM *t2 = BN_new(); - int ret = 0; - - /* - * g' = g^{xc + xa + xb} [from our POV] - * t1 = xa + xb - */ - BN_mod_add(t1, ctx->xa, ctx->xb, ctx->p.q, ctx->ctx); - /* t2 = g^{t1} = g^{xa+xb} */ - BN_mod_exp(t2, ctx->p.g, t1, ctx->p.p, ctx->ctx); - /* t1 = g^{xc} * t2 = g^{xc + xa + xb} */ - BN_mod_mul(t1, ctx->p.gxc, t2, ctx->p.p, ctx->ctx); - - if(verify_zkp(received, t1, ctx)) - ret = 1; - else - JPAKEerr(JPAKE_F_JPAKE_STEP2_PROCESS, JPAKE_R_VERIFY_B_FAILED); - - compute_key(ctx, received->gx); - - /* cleanup */ - BN_free(t2); - BN_free(t1); - - return ret; - } - -static void quickhashbn(unsigned char *md, const BIGNUM *bn) - { - SHA_CTX sha; - - SHA1_Init(&sha); - hashbn(&sha, bn); - SHA1_Final(md, &sha); - } - -void JPAKE_STEP3A_init(JPAKE_STEP3A *s3a) - {} - -int JPAKE_STEP3A_generate(JPAKE_STEP3A *send, JPAKE_CTX *ctx) - { - quickhashbn(send->hhk, ctx->key); - SHA1(send->hhk, sizeof send->hhk, send->hhk); - - return 1; - } - -int JPAKE_STEP3A_process(JPAKE_CTX *ctx, const JPAKE_STEP3A *received) - { - unsigned char hhk[SHA_DIGEST_LENGTH]; - - quickhashbn(hhk, ctx->key); - SHA1(hhk, sizeof hhk, hhk); - if(memcmp(hhk, received->hhk, sizeof hhk)) - { - JPAKEerr(JPAKE_F_JPAKE_STEP3A_PROCESS, JPAKE_R_HASH_OF_HASH_OF_KEY_MISMATCH); - return 0; - } - return 1; - } - -void JPAKE_STEP3A_release(JPAKE_STEP3A *s3a) - {} - -void JPAKE_STEP3B_init(JPAKE_STEP3B *s3b) - {} - -int JPAKE_STEP3B_generate(JPAKE_STEP3B *send, JPAKE_CTX *ctx) - { - quickhashbn(send->hk, ctx->key); - - return 1; - } - -int JPAKE_STEP3B_process(JPAKE_CTX *ctx, const JPAKE_STEP3B *received) - { - unsigned char hk[SHA_DIGEST_LENGTH]; - - quickhashbn(hk, ctx->key); - if(memcmp(hk, received->hk, sizeof hk)) - { - JPAKEerr(JPAKE_F_JPAKE_STEP3B_PROCESS, JPAKE_R_HASH_OF_KEY_MISMATCH); - return 0; - } - return 1; - } - -void JPAKE_STEP3B_release(JPAKE_STEP3B *s3b) - {} - -const BIGNUM *JPAKE_get_shared_key(JPAKE_CTX *ctx) - { - return ctx->key; - } - -- cgit v1.2.3 From 1684c8f398922065a97e7da4dac4ac6a33cc5218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 9 Apr 2014 16:03:55 +0200 Subject: Back to the standard "app" module. This return to "app" instead of "bitmask_android" is due to this reading: https://developer.android.com/sdk/installing/studio-build.html#projectStructure I'll have to tweak the final apk name in build.gradle. --- app/openssl/crypto/jpake/jpake.c | 511 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 511 insertions(+) create mode 100644 app/openssl/crypto/jpake/jpake.c (limited to 'app/openssl/crypto/jpake/jpake.c') diff --git a/app/openssl/crypto/jpake/jpake.c b/app/openssl/crypto/jpake/jpake.c new file mode 100644 index 00000000..8e4b633c --- /dev/null +++ b/app/openssl/crypto/jpake/jpake.c @@ -0,0 +1,511 @@ +#include "jpake.h" + +#include +#include +#include +#include + +/* + * 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 + { + char *name; /* Must be unique */ + char *peer_name; + BIGNUM *p; + BIGNUM *g; + BIGNUM *q; + BIGNUM *gxc; /* Alice's g^{x3} or Bob's g^{x1} */ + BIGNUM *gxd; /* Alice's g^{x4} or Bob's g^{x2} */ + } JPAKE_CTX_PUBLIC; + +struct JPAKE_CTX + { + JPAKE_CTX_PUBLIC p; + BIGNUM *secret; /* The shared secret */ + BN_CTX *ctx; + BIGNUM *xa; /* Alice's x1 or Bob's x3 */ + BIGNUM *xb; /* Alice's x2 or Bob's x4 */ + BIGNUM *key; /* The calculated (shared) key */ + }; + +static void JPAKE_ZKP_init(JPAKE_ZKP *zkp) + { + zkp->gr = BN_new(); + zkp->b = BN_new(); + } + +static void JPAKE_ZKP_release(JPAKE_ZKP *zkp) + { + BN_free(zkp->b); + BN_free(zkp->gr); + } + +/* Two birds with one stone - make the global name as expected */ +#define JPAKE_STEP_PART_init JPAKE_STEP2_init +#define JPAKE_STEP_PART_release JPAKE_STEP2_release + +void JPAKE_STEP_PART_init(JPAKE_STEP_PART *p) + { + p->gx = BN_new(); + JPAKE_ZKP_init(&p->zkpx); + } + +void JPAKE_STEP_PART_release(JPAKE_STEP_PART *p) + { + JPAKE_ZKP_release(&p->zkpx); + BN_free(p->gx); + } + +void JPAKE_STEP1_init(JPAKE_STEP1 *s1) + { + JPAKE_STEP_PART_init(&s1->p1); + JPAKE_STEP_PART_init(&s1->p2); + } + +void JPAKE_STEP1_release(JPAKE_STEP1 *s1) + { + JPAKE_STEP_PART_release(&s1->p2); + JPAKE_STEP_PART_release(&s1->p1); + } + +static void JPAKE_CTX_init(JPAKE_CTX *ctx, const char *name, + const char *peer_name, const BIGNUM *p, + const BIGNUM *g, const BIGNUM *q, + const BIGNUM *secret) + { + ctx->p.name = OPENSSL_strdup(name); + ctx->p.peer_name = OPENSSL_strdup(peer_name); + ctx->p.p = BN_dup(p); + ctx->p.g = BN_dup(g); + ctx->p.q = BN_dup(q); + ctx->secret = BN_dup(secret); + + ctx->p.gxc = BN_new(); + ctx->p.gxd = BN_new(); + + ctx->xa = BN_new(); + ctx->xb = BN_new(); + ctx->key = BN_new(); + ctx->ctx = BN_CTX_new(); + } + +static void JPAKE_CTX_release(JPAKE_CTX *ctx) + { + BN_CTX_free(ctx->ctx); + BN_clear_free(ctx->key); + BN_clear_free(ctx->xb); + BN_clear_free(ctx->xa); + + BN_free(ctx->p.gxd); + BN_free(ctx->p.gxc); + + BN_clear_free(ctx->secret); + BN_free(ctx->p.q); + BN_free(ctx->p.g); + BN_free(ctx->p.p); + OPENSSL_free(ctx->p.peer_name); + OPENSSL_free(ctx->p.name); + + memset(ctx, '\0', sizeof *ctx); + } + +JPAKE_CTX *JPAKE_CTX_new(const char *name, const char *peer_name, + const BIGNUM *p, const BIGNUM *g, const BIGNUM *q, + const BIGNUM *secret) + { + JPAKE_CTX *ctx = OPENSSL_malloc(sizeof *ctx); + + JPAKE_CTX_init(ctx, name, peer_name, p, g, q, secret); + + return ctx; + } + +void JPAKE_CTX_free(JPAKE_CTX *ctx) + { + JPAKE_CTX_release(ctx); + OPENSSL_free(ctx); + } + +static void hashlength(SHA_CTX *sha, size_t l) + { + unsigned char b[2]; + + OPENSSL_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 = OPENSSL_malloc(l); + + hashlength(sha, l); + BN_bn2bin(bn, bin); + SHA1_Update(sha, bin, l); + OPENSSL_free(bin); + } + +/* h=hash(g, g^r, g^x, name) */ +static void zkp_hash(BIGNUM *h, const BIGNUM *zkpg, const JPAKE_STEP_PART *p, + const char *proof_name) + { + unsigned char md[SHA_DIGEST_LENGTH]; + SHA_CTX sha; + + /* + * XXX: hash should not allow moving of the boundaries - Java code + * is flawed in this respect. Length encoding seems simplest. + */ + SHA1_Init(&sha); + hashbn(&sha, zkpg); + OPENSSL_assert(!BN_is_zero(p->zkpx.gr)); + hashbn(&sha, p->zkpx.gr); + hashbn(&sha, p->gx); + hashstring(&sha, proof_name); + SHA1_Final(md, &sha); + BN_bin2bn(md, SHA_DIGEST_LENGTH, h); + } + +/* + * Prove knowledge of x + * Note that p->gx has already been calculated + */ +static void generate_zkp(JPAKE_STEP_PART *p, const BIGNUM *x, + const BIGNUM *zkpg, JPAKE_CTX *ctx) + { + BIGNUM *r = BN_new(); + BIGNUM *h = BN_new(); + BIGNUM *t = BN_new(); + + /* + * r in [0,q) + * XXX: Java chooses r in [0, 2^160) - i.e. distribution not uniform + */ + BN_rand_range(r, ctx->p.q); + /* g^r */ + BN_mod_exp(p->zkpx.gr, zkpg, r, ctx->p.p, ctx->ctx); + + /* h=hash... */ + zkp_hash(h, zkpg, p, ctx->p.name); + + /* b = r - x*h */ + BN_mod_mul(t, x, h, ctx->p.q, ctx->ctx); + BN_mod_sub(p->zkpx.b, r, t, ctx->p.q, ctx->ctx); + + /* cleanup */ + BN_free(t); + BN_free(h); + BN_free(r); + } + +static int verify_zkp(const JPAKE_STEP_PART *p, const BIGNUM *zkpg, + JPAKE_CTX *ctx) + { + BIGNUM *h = BN_new(); + BIGNUM *t1 = BN_new(); + BIGNUM *t2 = BN_new(); + BIGNUM *t3 = BN_new(); + int ret = 0; + + zkp_hash(h, zkpg, p, ctx->p.peer_name); + + /* t1 = g^b */ + BN_mod_exp(t1, zkpg, p->zkpx.b, ctx->p.p, ctx->ctx); + /* t2 = (g^x)^h = g^{hx} */ + BN_mod_exp(t2, p->gx, h, ctx->p.p, ctx->ctx); + /* t3 = t1 * t2 = g^{hx} * g^b = g^{hx+b} = g^r (allegedly) */ + BN_mod_mul(t3, t1, t2, ctx->p.p, ctx->ctx); + + /* verify t3 == g^r */ + if(BN_cmp(t3, p->zkpx.gr) == 0) + ret = 1; + else + JPAKEerr(JPAKE_F_VERIFY_ZKP, JPAKE_R_ZKP_VERIFY_FAILED); + + /* cleanup */ + BN_free(t3); + BN_free(t2); + BN_free(t1); + BN_free(h); + + return ret; + } + +static void generate_step_part(JPAKE_STEP_PART *p, const BIGNUM *x, + const BIGNUM *g, JPAKE_CTX *ctx) + { + BN_mod_exp(p->gx, g, x, ctx->p.p, ctx->ctx); + generate_zkp(p, x, g, ctx); + } + +/* Generate each party's random numbers. xa is in [0, q), xb is in [1, q). */ +static void genrand(JPAKE_CTX *ctx) + { + BIGNUM *qm1; + + /* xa in [0, q) */ + BN_rand_range(ctx->xa, ctx->p.q); + + /* q-1 */ + qm1 = BN_new(); + BN_copy(qm1, ctx->p.q); + BN_sub_word(qm1, 1); + + /* ... and xb in [0, q-1) */ + BN_rand_range(ctx->xb, qm1); + /* [1, q) */ + BN_add_word(ctx->xb, 1); + + /* cleanup */ + BN_free(qm1); + } + +int JPAKE_STEP1_generate(JPAKE_STEP1 *send, JPAKE_CTX *ctx) + { + genrand(ctx); + generate_step_part(&send->p1, ctx->xa, ctx->p.g, ctx); + generate_step_part(&send->p2, ctx->xb, ctx->p.g, ctx); + + return 1; + } + +/* g^x is a legal value */ +static int is_legal(const BIGNUM *gx, const JPAKE_CTX *ctx) + { + BIGNUM *t; + int res; + + if(BN_is_negative(gx) || BN_is_zero(gx) || BN_cmp(gx, ctx->p.p) >= 0) + return 0; + + t = BN_new(); + BN_mod_exp(t, gx, ctx->p.q, ctx->p.p, ctx->ctx); + res = BN_is_one(t); + BN_free(t); + + return res; + } + +int JPAKE_STEP1_process(JPAKE_CTX *ctx, const JPAKE_STEP1 *received) + { + if(!is_legal(received->p1.gx, ctx)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_G_TO_THE_X3_IS_NOT_LEGAL); + return 0; + } + + if(!is_legal(received->p2.gx, ctx)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_G_TO_THE_X4_IS_NOT_LEGAL); + return 0; + } + + /* verify their ZKP(xc) */ + if(!verify_zkp(&received->p1, ctx->p.g, ctx)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_VERIFY_X3_FAILED); + return 0; + } + + /* verify their ZKP(xd) */ + if(!verify_zkp(&received->p2, ctx->p.g, ctx)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_VERIFY_X4_FAILED); + return 0; + } + + /* g^xd != 1 */ + if(BN_is_one(received->p2.gx)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP1_PROCESS, JPAKE_R_G_TO_THE_X4_IS_ONE); + return 0; + } + + /* Save the bits we need for later */ + BN_copy(ctx->p.gxc, received->p1.gx); + BN_copy(ctx->p.gxd, received->p2.gx); + + return 1; + } + + +int JPAKE_STEP2_generate(JPAKE_STEP2 *send, JPAKE_CTX *ctx) + { + BIGNUM *t1 = BN_new(); + BIGNUM *t2 = BN_new(); + + /* + * X = g^{(xa + xc + xd) * xb * s} + * t1 = g^xa + */ + BN_mod_exp(t1, ctx->p.g, ctx->xa, ctx->p.p, ctx->ctx); + /* t2 = t1 * g^{xc} = g^{xa} * g^{xc} = g^{xa + xc} */ + BN_mod_mul(t2, t1, ctx->p.gxc, ctx->p.p, ctx->ctx); + /* t1 = t2 * g^{xd} = g^{xa + xc + xd} */ + BN_mod_mul(t1, t2, ctx->p.gxd, ctx->p.p, ctx->ctx); + /* t2 = xb * s */ + BN_mod_mul(t2, ctx->xb, ctx->secret, ctx->p.q, ctx->ctx); + + /* + * ZKP(xb * s) + * XXX: this is kinda funky, because we're using + * + * g' = g^{xa + xc + xd} + * + * as the generator, which means X is g'^{xb * s} + * X = t1^{t2} = t1^{xb * s} = g^{(xa + xc + xd) * xb * s} + */ + generate_step_part(send, t2, t1, ctx); + + /* cleanup */ + BN_free(t1); + BN_free(t2); + + return 1; + } + +/* gx = g^{xc + xa + xb} * xd * s */ +static int compute_key(JPAKE_CTX *ctx, const BIGNUM *gx) + { + BIGNUM *t1 = BN_new(); + BIGNUM *t2 = BN_new(); + BIGNUM *t3 = BN_new(); + + /* + * K = (gx/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} + * [which is the same regardless of who calculates it] + */ + + /* t1 = (g^{xd})^{xb} = g^{xb * xd} */ + BN_mod_exp(t1, ctx->p.gxd, ctx->xb, ctx->p.p, ctx->ctx); + /* t2 = -s = q-s */ + BN_sub(t2, ctx->p.q, ctx->secret); + /* t3 = t1^t2 = g^{-xb * xd * s} */ + BN_mod_exp(t3, t1, t2, ctx->p.p, ctx->ctx); + /* t1 = gx * t3 = X/g^{xb * xd * s} */ + BN_mod_mul(t1, gx, t3, ctx->p.p, ctx->ctx); + /* K = t1^{xb} */ + BN_mod_exp(ctx->key, t1, ctx->xb, ctx->p.p, ctx->ctx); + + /* cleanup */ + BN_free(t3); + BN_free(t2); + BN_free(t1); + + return 1; + } + +int JPAKE_STEP2_process(JPAKE_CTX *ctx, const JPAKE_STEP2 *received) + { + BIGNUM *t1 = BN_new(); + BIGNUM *t2 = BN_new(); + int ret = 0; + + /* + * g' = g^{xc + xa + xb} [from our POV] + * t1 = xa + xb + */ + BN_mod_add(t1, ctx->xa, ctx->xb, ctx->p.q, ctx->ctx); + /* t2 = g^{t1} = g^{xa+xb} */ + BN_mod_exp(t2, ctx->p.g, t1, ctx->p.p, ctx->ctx); + /* t1 = g^{xc} * t2 = g^{xc + xa + xb} */ + BN_mod_mul(t1, ctx->p.gxc, t2, ctx->p.p, ctx->ctx); + + if(verify_zkp(received, t1, ctx)) + ret = 1; + else + JPAKEerr(JPAKE_F_JPAKE_STEP2_PROCESS, JPAKE_R_VERIFY_B_FAILED); + + compute_key(ctx, received->gx); + + /* cleanup */ + BN_free(t2); + BN_free(t1); + + return ret; + } + +static void quickhashbn(unsigned char *md, const BIGNUM *bn) + { + SHA_CTX sha; + + SHA1_Init(&sha); + hashbn(&sha, bn); + SHA1_Final(md, &sha); + } + +void JPAKE_STEP3A_init(JPAKE_STEP3A *s3a) + {} + +int JPAKE_STEP3A_generate(JPAKE_STEP3A *send, JPAKE_CTX *ctx) + { + quickhashbn(send->hhk, ctx->key); + SHA1(send->hhk, sizeof send->hhk, send->hhk); + + return 1; + } + +int JPAKE_STEP3A_process(JPAKE_CTX *ctx, const JPAKE_STEP3A *received) + { + unsigned char hhk[SHA_DIGEST_LENGTH]; + + quickhashbn(hhk, ctx->key); + SHA1(hhk, sizeof hhk, hhk); + if(memcmp(hhk, received->hhk, sizeof hhk)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP3A_PROCESS, JPAKE_R_HASH_OF_HASH_OF_KEY_MISMATCH); + return 0; + } + return 1; + } + +void JPAKE_STEP3A_release(JPAKE_STEP3A *s3a) + {} + +void JPAKE_STEP3B_init(JPAKE_STEP3B *s3b) + {} + +int JPAKE_STEP3B_generate(JPAKE_STEP3B *send, JPAKE_CTX *ctx) + { + quickhashbn(send->hk, ctx->key); + + return 1; + } + +int JPAKE_STEP3B_process(JPAKE_CTX *ctx, const JPAKE_STEP3B *received) + { + unsigned char hk[SHA_DIGEST_LENGTH]; + + quickhashbn(hk, ctx->key); + if(memcmp(hk, received->hk, sizeof hk)) + { + JPAKEerr(JPAKE_F_JPAKE_STEP3B_PROCESS, JPAKE_R_HASH_OF_KEY_MISMATCH); + return 0; + } + return 1; + } + +void JPAKE_STEP3B_release(JPAKE_STEP3B *s3b) + {} + +const BIGNUM *JPAKE_get_shared_key(JPAKE_CTX *ctx) + { + return ctx->key; + } + -- cgit v1.2.3