// Generate each party's random numbers. xa is in [0, q), xb is in [1, q). static void genrand(JPakeUser * user, const JPakeParameters * params) { BIGNUM *qm1; // xa in [0, q) user->xa = BN_new(); BN_rand_range(user->xa, params->q); // q-1 qm1 = BN_new(); BN_copy(qm1, params->q); BN_sub_word(qm1, 1); // ... and xb in [0, q-1) user->xb = BN_new(); BN_rand_range(user->xb, qm1); // [1, q) BN_add_word(user->xb, 1); // cleanup BN_free(qm1); // Show printf("x%d", user->p.base); showbn("", user->xa); printf("x%d", user->p.base + 1); showbn("", user->xb); }
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"); 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); }
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} // [which is the same regardless of who calculates it] // t1 = (g^{xd})^{xb} = g^{xb * xd} BN_mod_exp(t1, us->p.s1d.gx, us->xb, params->p, params->ctx); // t2 = -s = q-s BN_sub(t2, params->q, us->secret); // t3 = t1^t2 = g^{-xb * xd * s} BN_mod_exp(t3, t1, t2, params->p, params->ctx); // t1 = X * t3 = X/g^{xb * xd * s} BN_mod_mul(t1, us->p.s2.X, t3, params->p, params->ctx); // K = t1^{xb} us->key = BN_new(); BN_mod_exp(us->key, t1, us->xb, params->p, params->ctx); // show showbn(" K", us->key); // cleanup BN_free(t3); BN_free(t2); BN_free(t1); }
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 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); // t1 = g^b BN_mod_exp(t1, zkpg, zkp->b, params->p, params->ctx); // t2 = (g^x)^h = g^{hx} BN_mod_exp(t2, gx, h, params->p, params->ctx); // t3 = t1 * t2 = g^{hx} * g^b = g^{hx+b} = g^r (allegedly) 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); // verify t3 == g^r if (BN_cmp(t3, zkp->gr) == 0) ret = 1; // cleanup BN_free(t3); BN_free(t2); BN_free(t1); BN_free(h); if (ret) puts(" OK"); else puts(" FAIL"); return ret; }
// 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) { BIGNUM *r = BN_new(); BIGNUM *gx = 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, params->q); // g^r zkp->gr = BN_new(); BN_mod_exp(zkp->gr, zkpg, r, params->p, params->ctx); // g^x BN_mod_exp(gx, zkpg, x, params->p, params->ctx); // 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_mod_sub(zkp->b, r, t, params->q, params->ctx); // show printf(" ZKP(x%d%s)\n", n, suffix); showbn(" zkpg", zkpg); showbn(" g^x", gx); showbn(" g^r", zkp->gr); showbn(" b", zkp->b); // cleanup BN_free(t); BN_free(h); BN_free(gx); BN_free(r); }
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); // X = g^{(xa + xc + xd) * xb * s} // t1 = g^xa BN_mod_exp(t1, params->g, us->xa, params->p, params->ctx); // t2 = t1 * g^{xc} = g^{xa} * g^{xc} = g^{xa + xc} BN_mod_mul(t2, t1, us->p.s1c.gx, params->p, params->ctx); // t1 = t2 * g^{xd} = g^{xa + xc + xd} BN_mod_mul(t1, t2, us->p.s1d.gx, params->p, params->ctx); // t2 = xb * s BN_mod_mul(t2, us->xb, us->secret, params->q, params->ctx); // X = t1^{t2} = t1^{xb * s} = g^{(xa + xc + xd) * xb * s} them->s2.X = BN_new(); BN_mod_exp(them->s2.X, t1, t2, params->p, params->ctx); // Show 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); // 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} CreateZKP(&them->s2.zkpxbs, t2, us, t1, params, us->p.base + 1, " * s"); // cleanup BN_free(t1); BN_free(t2); }
static int run_srp(const char *username, const char *client_pass, const char *server_pass) { int ret=-1; BIGNUM *s = NULL; BIGNUM *v = NULL; BIGNUM *a = NULL; BIGNUM *b = NULL; BIGNUM *u = NULL; BIGNUM *x = NULL; BIGNUM *Apub = NULL; BIGNUM *Bpub = NULL; BIGNUM *Kclient = NULL; BIGNUM *Kserver = NULL; unsigned char rand_tmp[RANDOM_SIZE]; /* use builtin 1024-bit params */ const SRP_gN *GN = SRP_get_default_gN("1024"); if(GN == NULL) { fprintf(stderr, "Failed to get SRP parameters\n"); return -1; } /* Set up server's password entry */ if(!SRP_create_verifier_BN(username, server_pass, &s, &v, GN->N, GN->g)) { fprintf(stderr, "Failed to create SRP verifier\n"); return -1; } showbn("N", GN->N); showbn("g", GN->g); showbn("Salt", s); showbn("Verifier", v); /* Server random */ RAND_pseudo_bytes(rand_tmp, sizeof(rand_tmp)); b = BN_bin2bn(rand_tmp, sizeof(rand_tmp), NULL); /* TODO - check b != 0 */ showbn("b", b); /* Server's first message */ Bpub = SRP_Calc_B(b, GN->N, GN->g, v); showbn("B", Bpub); if(!SRP_Verify_B_mod_N(Bpub, GN->N)) { fprintf(stderr, "Invalid B\n"); return -1; } /* Client random */ RAND_pseudo_bytes(rand_tmp, sizeof(rand_tmp)); a = BN_bin2bn(rand_tmp, sizeof(rand_tmp), NULL); /* TODO - check a != 0 */ showbn("a", a); /* Client's response */ Apub = SRP_Calc_A(a, GN->N, GN->g); showbn("A", Apub); if(!SRP_Verify_A_mod_N(Apub, GN->N)) { fprintf(stderr, "Invalid A\n"); return -1; } /* Both sides calculate u */ u = SRP_Calc_u(Apub, Bpub, GN->N); /* Client's key */ x = SRP_Calc_x(s, username, client_pass); Kclient = SRP_Calc_client_key(GN->N, Bpub, GN->g, x, a, u); showbn("Client's key", Kclient); /* Server's key */ Kserver = SRP_Calc_server_key(Apub, v, u, b, GN->N); showbn("Server's key", Kserver); if(BN_cmp(Kclient, Kserver) == 0) { ret = 0; } else { fprintf(stderr, "Keys mismatch\n"); ret = 1; } BN_clear_free(Kclient); BN_clear_free(Kserver); BN_clear_free(x); BN_free(u); BN_free(Apub); BN_clear_free(a); BN_free(Bpub); BN_clear_free(b); BN_free(s); BN_clear_free(v); return ret; }
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); // Shared secret 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); // Alice's x1, x2 genrand(&alice, ¶ms); // Bob's x3, x4 genrand(&bob, ¶ms); // Now send stuff to each other... sendstep1(&alice, &bob.p, ¶ms); 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; // 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; // Compute common key computekey(&alice, ¶ms); computekey(&bob, ¶ms); // Confirm the common key is identical // XXX: if the two secrets are not the same, everything works up // to this point, so the only way to detect a failure is by the // difference in the calculated keys. // Since we're all the same code, just compare them directly. In a // 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; } return 0; }
static int run_jpake(JPAKE_CTX *alice, JPAKE_CTX *bob) { JPAKE_STEP1 alice_s1; JPAKE_STEP1 bob_s1; JPAKE_STEP2 alice_s2; JPAKE_STEP2 bob_s2; JPAKE_STEP3A alice_s3a; JPAKE_STEP3B bob_s3b; /* Alice -> Bob: step 1 */ puts("A->B s1"); JPAKE_STEP1_init(&alice_s1); JPAKE_STEP1_generate(&alice_s1, alice); if(!JPAKE_STEP1_process(bob, &alice_s1)) { printf("Bob fails to process Alice's step 1\n"); ERR_print_errors_fp(stdout); return 1; } JPAKE_STEP1_release(&alice_s1); /* Bob -> Alice: step 1 */ puts("B->A s1"); JPAKE_STEP1_init(&bob_s1); JPAKE_STEP1_generate(&bob_s1, bob); if(!JPAKE_STEP1_process(alice, &bob_s1)) { printf("Alice fails to process Bob's step 1\n"); ERR_print_errors_fp(stdout); return 2; } JPAKE_STEP1_release(&bob_s1); /* Alice -> Bob: step 2 */ puts("A->B s2"); JPAKE_STEP2_init(&alice_s2); JPAKE_STEP2_generate(&alice_s2, alice); if(!JPAKE_STEP2_process(bob, &alice_s2)) { printf("Bob fails to process Alice's step 2\n"); ERR_print_errors_fp(stdout); return 3; } JPAKE_STEP2_release(&alice_s2); /* Bob -> Alice: step 2 */ puts("B->A s2"); JPAKE_STEP2_init(&bob_s2); JPAKE_STEP2_generate(&bob_s2, bob); if(!JPAKE_STEP2_process(alice, &bob_s2)) { printf("Alice fails to process Bob's step 2\n"); ERR_print_errors_fp(stdout); return 4; } JPAKE_STEP2_release(&bob_s2); showbn("Alice's key", JPAKE_get_shared_key(alice)); showbn("Bob's key ", JPAKE_get_shared_key(bob)); /* Alice -> Bob: step 3a */ puts("A->B s3a"); JPAKE_STEP3A_init(&alice_s3a); JPAKE_STEP3A_generate(&alice_s3a, alice); if(!JPAKE_STEP3A_process(bob, &alice_s3a)) { printf("Bob fails to process Alice's step 3a\n"); ERR_print_errors_fp(stdout); return 5; } JPAKE_STEP3A_release(&alice_s3a); /* Bob -> Alice: step 3b */ puts("B->A s3b"); JPAKE_STEP3B_init(&bob_s3b); JPAKE_STEP3B_generate(&bob_s3b, bob); if(!JPAKE_STEP3B_process(alice, &bob_s3b)) { printf("Alice fails to process Bob's step 3b\n"); ERR_print_errors_fp(stdout); return 6; } JPAKE_STEP3B_release(&bob_s3b); return 0; }
int main(int argc, char **argv) { JPAKE_CTX *alice; JPAKE_CTX *bob; BIGNUM *p = NULL; BIGNUM *g = NULL; BIGNUM *q = NULL; BIGNUM *secret = BN_new(); BIO *bio_err; bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); CRYPTO_malloc_debug_init(); CRYPTO_dbg_set_options(V_CRYPTO_MDEBUG_ALL); CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); ERR_load_crypto_strings(); /* BN_hex2bn(&p, "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7"); BN_hex2bn(&g, "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d0782675159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a"); BN_hex2bn(&q, "9760508f15230bccb292b982a2eb840bf0581cf5"); */ /* p = BN_new(); BN_generate_prime(p, 1024, 1, NULL, NULL, NULL, NULL); */ /* Use a safe prime for p (that we found earlier) */ BN_hex2bn(&p, "F9E5B365665EA7A05A9C534502780FEE6F1AB5BD4F49947FD036DBD7E905269AF46EF28B0FC07487EE4F5D20FB3C0AF8E700F3A2FA3414970CBED44FEDFF80CE78D800F184BB82435D137AADA2C6C16523247930A63B85661D1FC817A51ACD96168E95898A1F83A79FFB529368AA7833ABD1B0C3AEDDB14D2E1A2F71D99F763F"); showbn("p", p); g = BN_new(); BN_set_word(g, 2); showbn("g", g); q = BN_new(); BN_rshift1(q, p); showbn("q", q); BN_rand(secret, 32, -1, 0); /* A normal run, expect this to work... */ alice = JPAKE_CTX_new("Alice", "Bob", p, g, q, secret); bob = JPAKE_CTX_new("Bob", "Alice", p, g, q, secret); if(run_jpake(alice, bob) != 0) { fprintf(stderr, "Plain JPAKE run failed\n"); return 1; } JPAKE_CTX_free(bob); JPAKE_CTX_free(alice); /* Now give Alice and Bob different secrets */ alice = JPAKE_CTX_new("Alice", "Bob", p, g, q, secret); BN_add_word(secret, 1); bob = JPAKE_CTX_new("Bob", "Alice", p, g, q, secret); if(run_jpake(alice, bob) != 5) { fprintf(stderr, "Mismatched secret JPAKE run failed\n"); return 1; } JPAKE_CTX_free(bob); JPAKE_CTX_free(alice); BN_free(secret); BN_free(q); BN_free(g); BN_free(p); CRYPTO_cleanup_all_ex_data(); ERR_remove_state(0); ERR_free_strings(); CRYPTO_mem_leaks(bio_err); return 0; }
static int run_srp(const char *username, const char *client_pass, const char *server_pass) { int ret = 0; BIGNUM *s = NULL; BIGNUM *v = NULL; BIGNUM *a = NULL; BIGNUM *b = NULL; BIGNUM *u = NULL; BIGNUM *x = NULL; BIGNUM *Apub = NULL; BIGNUM *Bpub = NULL; BIGNUM *Kclient = NULL; BIGNUM *Kserver = NULL; unsigned char rand_tmp[RANDOM_SIZE]; /* use builtin 1024-bit params */ const SRP_gN *GN; if (!TEST_ptr(GN = SRP_get_default_gN("1024"))) return 0; /* Set up server's password entry */ if (!TEST_true(SRP_create_verifier_BN(username, server_pass, &s, &v, GN->N, GN->g))) goto end; showbn("N", GN->N); showbn("g", GN->g); showbn("Salt", s); showbn("Verifier", v); /* Server random */ RAND_bytes(rand_tmp, sizeof(rand_tmp)); b = BN_bin2bn(rand_tmp, sizeof(rand_tmp), NULL); if (!TEST_BN_ne_zero(b)) goto end; showbn("b", b); /* Server's first message */ Bpub = SRP_Calc_B(b, GN->N, GN->g, v); showbn("B", Bpub); if (!TEST_true(SRP_Verify_B_mod_N(Bpub, GN->N))) goto end; /* Client random */ RAND_bytes(rand_tmp, sizeof(rand_tmp)); a = BN_bin2bn(rand_tmp, sizeof(rand_tmp), NULL); if (!TEST_BN_ne_zero(a)) goto end; showbn("a", a); /* Client's response */ Apub = SRP_Calc_A(a, GN->N, GN->g); showbn("A", Apub); if (!TEST_true(SRP_Verify_A_mod_N(Apub, GN->N))) goto end; /* Both sides calculate u */ u = SRP_Calc_u(Apub, Bpub, GN->N); /* Client's key */ x = SRP_Calc_x(s, username, client_pass); Kclient = SRP_Calc_client_key(GN->N, Bpub, GN->g, x, a, u); showbn("Client's key", Kclient); /* Server's key */ Kserver = SRP_Calc_server_key(Apub, v, u, b, GN->N); showbn("Server's key", Kserver); if (!TEST_BN_eq(Kclient, Kserver)) goto end; ret = 1; end: BN_clear_free(Kclient); BN_clear_free(Kserver); BN_clear_free(x); BN_free(u); BN_free(Apub); BN_clear_free(a); BN_free(Bpub); BN_clear_free(b); BN_free(s); BN_clear_free(v); return ret; }