/* Compute an DH shared secret between private_key and public_key. Return the result in computed_key and the length of the result in bytes in *computed_key_len. Return 0 iff successful. */ int ccdh_compute_key(ccdh_full_ctx_t private_key, ccdh_pub_ctx_t public_key, cc_unit *r) { int result = CCDH_ERROR_DEFAULT; ccdh_const_gp_t gp = ccdh_ctx_gp(private_key); cc_size n=ccdh_gp_n(gp); /* Validated the public key */ result = ccdh_check_pub(gp,public_key); if(result!=0) { goto errOut; } /* Actual compuation */ cczp_power(gp.zp, r, ccdh_ctx_y(public_key), ccdh_ctx_x(private_key)); /* Result can't be 0 (computation issue) or 1 (y in the group) */ result = CCDH_INVALID_INPUT; if (!(ccn_is_zero_or_one(n,r))) { result = 0; } errOut: return result; }
OSStatus SecDHGenerateKeypair(SecDHContext dh, uint8_t *pub_key, size_t *pub_key_len) { int result; ccdh_gp_t gp = SecDH_gp(dh); ccdh_full_ctx_t priv = SecDH_priv(dh); if((result = ccdh_generate_key(gp, &dhrng, priv))) return result; /* output y as a big endian byte buffer */ size_t ylen = ccn_write_uint_size(ccdh_gp_n(gp), ccdh_ctx_y(priv)); if(*pub_key_len < ylen) return errSecBufferTooSmall; ccn_write_uint(ccdh_gp_n(gp),ccdh_ctx_y(priv), ylen, pub_key); *pub_key_len = ylen; return errSecSuccess; }
int ccdh_generate_key(ccdh_const_gp_t gp, struct ccrng_state *rng, ccdh_full_ctx_t key) { int result=CCDH_ERROR_DEFAULT; ccdh_ctx_init(gp, key); const cc_unit *g = ccdh_gp_g(gp); cc_unit *x = ccdh_ctx_x(key); cc_unit *y = ccdh_ctx_y(key); /* Generate the private key: x per PKCS #3 */ cc_require((result=ccdh_generate_private_key(gp,x,rng))==0,errOut); /* Generate the public key: y=g^x mod p */ cczp_power(gp.zp, y, g, x); result = 0; errOut: return result; }
int ccdh_import_priv(ccdh_const_gp_t gp, size_t in_len, const uint8_t *in, ccdh_full_ctx_t key) { const cc_unit *g = ccdh_gp_g(gp); ccdh_ctx_init(gp, key); cc_unit *x = ccdh_ctx_x(key); cc_unit *y = ccdh_ctx_y(key); if ((ccn_read_uint(ccdh_gp_n(gp), x, in_len, in))) return CCDH_INVALID_INPUT; if (ccn_cmp(ccdh_gp_n(gp), x, cczp_prime(gp.zp)) >= 0) return CCDH_SAFETY_CHECK; /* Generate the public key: y=g^x mod p */ cczp_power(gp.zp, y, g, x); return 0; }
int ccdh_test_compute_vector(const struct ccdh_compute_vector *v) { int result,r1,r2; const cc_size n = ccn_nof(v->len); const size_t s = ccn_sizeof_n(n); unsigned char z[v->zLen]; size_t zLen; unsigned char tmp[v->zLen]; // for negative testing uint32_t status=0; uint32_t nb_test=0; ccdh_gp_decl(s, gp); ccdh_full_ctx_decl(s, a); ccdh_full_ctx_decl(s, b); cc_unit p[n]; cc_unit g[n]; cc_unit r[n]; cc_unit q[n]; // Bail to errOut when unexpected error happens. // Try all usecases otherwise if((result=ccn_read_uint(n, p, v->pLen, v->p))) goto errOut; if((result=ccn_read_uint(n, g, v->gLen, v->g))) goto errOut; if((result=ccn_read_uint(n, q, v->qLen, v->q))) goto errOut; ccdh_init_gp_with_order(gp, n, p, g, q); ccdh_ctx_init(gp, a); ccdh_ctx_init(gp, b); if((result=ccn_read_uint(n, ccdh_ctx_x(a), v->xaLen, v->xa))) // private key goto errOut; if((result=ccn_read_uint(n, ccdh_ctx_y(a), v->yaLen, v->ya))) // public key goto errOut; if((result=ccn_read_uint(n, ccdh_ctx_x(b), v->xbLen, v->xb))) // private key goto errOut; if((result=ccn_read_uint(n, ccdh_ctx_y(b), v->ybLen, v->yb))) // public key goto errOut; /* * Main test */ /* try one side */ zLen = v->zLen; r1=ccdh_compute_key(a, b, r); ccn_write_uint_padded(n, r, zLen, z); r1|=memcmp(z, v->z, zLen); /* try the other side */ zLen = v->zLen; r2=ccdh_compute_key(b, a, r); ccn_write_uint_padded(n, r, zLen, z); r2|=memcmp(z, v->z, zLen); if ((!(r1||r2) && v->valid)||((r1||r2) && !v->valid)) { status|=1<<nb_test; } nb_test++; // We are done if the test is not valid if (!v->valid) goto doneOut; /* * Corner case / negative testing * Only applicable for valid tests */ /* Output is 1 (use private key is (p-1)/2)*/ if((result=ccn_read_uint(n, ccdh_ctx_x(a), v->pLen, v->p))) // private key goto errOut; ccn_sub1(n,ccdh_ctx_x(a),ccdh_ctx_x(a),1); ccn_shift_right(n,ccdh_ctx_x(a),ccdh_ctx_x(a),1); if ((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } if((result=ccn_read_uint(n, ccdh_ctx_x(a), v->xaLen, v->xa))) // restore private key goto errOut; nb_test++; /* negative testing (1 < y < p-1)*/ /* public y = 0 */ zLen = v->zLen; cc_zero(sizeof(tmp),tmp); if((result=ccn_read_uint(n, ccdh_ctx_y(b), zLen, tmp))) { goto errOut; } if((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } nb_test++; /* public y = 1 */ zLen = v->zLen; cc_zero(sizeof(tmp),tmp); tmp[zLen-1]=1; if((result=ccn_read_uint(n, ccdh_ctx_y(b), zLen, tmp))) { goto errOut; } if((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } nb_test++; /* public y = p */ if((result=ccn_read_uint(n, ccdh_ctx_y(b), v->pLen, v->p))) goto errOut; if((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } nb_test++; /* public y = p-1 */ if((result=ccn_read_uint(n, ccdh_ctx_y(b), v->pLen, v->p))) { goto errOut; } ccn_sub1(n,ccdh_ctx_y(b),ccdh_ctx_y(b),1); if((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } nb_test++; /* * When the order is in defined in the group * check that the implementation check the order of the public value: * public y = g+1 (for rfc5114 groups, g+1 is not of order q) */ if (ccdh_gp_order_bitlen(gp)) { if((result=ccn_read_uint(n, ccdh_ctx_y(b), v->gLen, v->g))) { goto errOut; } ccn_add1(n,ccdh_ctx_y(b),ccdh_ctx_y(b),1); if((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } nb_test++; } /* positive testing at the boundaries of (1 < y < p-1)*/ // Don't set the order in gp because 2 and p-2 are not of order q ccdh_init_gp(gp, n, p, g, 0); /* public y = 2 */ zLen = v->zLen; cc_zero(sizeof(tmp),tmp); tmp[zLen-1]=2; if((result=ccn_read_uint(n, ccdh_ctx_y(b), zLen, tmp))) { goto errOut; } if((result=ccdh_compute_key(a, b, r))==0) { status|=1<<nb_test; } nb_test++; /* public y = p-2 */ if((result=ccn_read_uint(n, ccdh_ctx_y(b), v->pLen, v->p))) { goto errOut; } ccn_sub1(n,ccdh_ctx_y(b),ccdh_ctx_y(b),2); if((result=ccdh_compute_key(a, b, r))==0) { status|=1<<nb_test; } nb_test++; /* Negative testing: p is even */ if((result=ccn_read_uint(n, p, v->pLen, v->p))) goto errOut; ccn_set_bit(p,0,0); // Set LS bit to 0 ccdh_init_gp(gp, n, p, g, 0); ccdh_ctx_init(gp, a); ccdh_ctx_init(gp, b); if((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } nb_test++; /* Test aftermath */ doneOut: if ((nb_test==0) || (status!=((1<<nb_test)-1))) { result=1; } else { result=0; // Test is successful, Yeah! } errOut: return result; }