int cczp_sqrt(cczp_const_t zp, cc_unit *r, const cc_unit *x) { cc_size n=cczp_n(zp); cc_unit t[n]; ccn_set(n,t,cczp_prime(zp)); int result = -1; // Square root can be computed as x^((p+1)/4) when p = 3 mod 4 cc_require(((t[0]&3) == 3),errOut); // Compute ((p+1)/4) ccn_add1(n, t, t, 1); ccn_shift_right(n, t, t, 2); // Exponentiation cczp_power_fast(zp,r,x,t); // Confirm that the result is valid // => r is not the square root of x cczp_mul(zp,t,r,r); cc_require(ccn_cmp(n,t,x)==0,errOut); // r^2 == x ? result=0; errOut: return result; }
static double perf_ccn_cmp(unsigned long loops, cc_size count) { cc_unit s[count]; cc_unit t[count]; ccn_random(count, s, rng); ccn_set(count, t, s); perf_start(); do { r_for_cmp=ccn_cmp(count, s, t); } while (--loops != 0); return perf_time(); }
int ccec_generate_key_internal_fips(ccec_const_cp_t cp, struct ccrng_state *rng, ccec_full_ctx_t key) { int result=CCEC_GENERATE_KEY_DEFAULT_ERR; /* Get base point G in projected form. */ ccec_point_decl_cp(cp, base); cczp_const_t zq = ccec_cp_zq(cp); cc_require((result=ccec_projectify(cp, base, ccec_cp_g(cp),rng))==0,errOut); /* Generate a random private key k. */ ccec_ctx_init(cp, key); cc_unit *k = ccec_ctx_k(key); cc_unit *q_minus_2 = ccec_ctx_x(key); // used as temp buffer int cmp_result=1; /* Need to test candidate against q-2 */ ccn_sub1(ccec_cp_n(cp), q_minus_2, cczp_prime(zq), 2); size_t i; /* Generate adequate random for private key */ for (i = 0; i < MAX_RETRY && cmp_result>0; i++) { /* Random bits */ cc_require(((result = ccn_random_bits(ccec_cp_order_bitlen(cp), k, rng)) == 0),errOut); /* If k <= q-2, the number is valid */ cmp_result=ccn_cmp(ccec_cp_n(cp), k, q_minus_2); } if (i >= MAX_RETRY) { result=CCEC_GENERATE_KEY_TOO_MANY_TRIES; } else { cc_assert(cmp_result<=0); /* k is now in range [ 0, q-2 ] ==> +1 for range [ 1, q-1 ] */ ccn_add1(ccec_cp_n(cp), k, k, 1); /* Calculate the public key for k. */ cc_require_action(ccec_mult(cp, ccec_ctx_point(key), k, base,rng) == 0 ,errOut, result=CCEC_GENERATE_KEY_MULT_FAIL); cc_require_action(ccec_is_point_projective(cp, ccec_ctx_point(key)),errOut, result=CCEC_GENERATE_NOT_ON_CURVE); cc_require_action(ccec_affinify(cp, ccec_ctx_point(key), ccec_ctx_point(key)) == 0,errOut, result=CCEC_GENERATE_KEY_AFF_FAIL); ccn_seti(ccec_cp_n(cp), ccec_ctx_z(key), 1); result=0; } errOut: return result; }
CC_INLINE bool ccsrp_component_equal(char *label, ccsrp_ctx_t srp, cc_unit *a, cc_unit *b) { bool retval = ccn_cmp(ccsrp_ctx_n(srp), a, b) == 0; if(!retval) { size_t bytes_n = ccsrp_ctx_sizeof_n(srp); cc_printf("ccsrp_test_calculations: mismatch for %s:\n", label); cc_printf("\t"); dump_hex((void *) a, bytes_n); cc_printf("\t"); dump_hex((void *) b, bytes_n); cc_printf("\n"); } return retval; }
/* q*t + r == s [e.g. s/t, q=quotient, r=remainder]. */ static void ccn_divn(cc_size nqs, cc_unit *q, cc_unit *r, const cc_unit *s, size_t nrt, cc_unit *t) { if (ccn_is_zero(nrt, t)) { /* Division by zero is illegal. */ return; } /* If s < t then q = 0, r = s */ if (ccn_cmpn(nqs, s, nrt, t) < 0) { if (r) ccn_setn(nrt, r, CC_MIN(nrt, nqs), s); if (q) ccn_zero(nqs, q); return; } /* s >= t => k >= 0 */ size_t k = ccn_bitlen(nqs, s); size_t l = ccn_bitlen(nrt, t); assert(k >= l); k -= l; cc_unit tr[nqs]; cc_unit tt[nqs]; cc_unit tq[nqs]; ccn_set(nqs, tr, s); ccn_setn(nqs, tt, nrt, t); ccn_shift_left_multi(nqs, tt, tt, k); ccn_zero(nqs, tq); for (;;) { if (ccn_cmp(nqs, tr, tt) >= 0) { ccn_sub(nqs, tr, tr, tt); ccn_set_bit(tq, k, 1); } if (!k) break; --k; ccn_shift_right(nqs, tt, tt, 1); } if (r) { ccn_setn(nrt, r, CC_MIN(nrt, nqs), tr); } if (q) { ccn_set(nqs, q, tq); } }
/* TODO: Potentially write and use ccn_lcm(n, r2n, s, t). */ void ccn_lcm(cc_size n, cc_unit *r2n, const cc_unit *s, const cc_unit *t) { cc_unit tmp[n*2]; if (ccn_cmp(n, s, t) < 0) CC_SWAP(s,t); /* Now s >= t. */ ccn_zero(n*2, r2n); ccn_gcd(n, r2n, s, t); cc_unit t2[n*2]; ccn_setn(n*2, t2, n, t); ccn_divmod(n, tmp, NULL, t2, r2n); ccn_mul(n, r2n, s, tmp); }
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; }
static void ccn_mod_384(cczp_const_t zp, cc_unit *r, const cc_unit *a, CC_UNUSED cc_ws_t ws) { cc_assert(cczp_n(zp) == CCN384_N); cc_unit s1[CCN384_N] = { ccn384_32( Anil, Anil, Anil, Anil, Anil, A(23), A(22), A(21), Anil, Anil, Anil, Anil) }; //cc_unit s2[CCN384_N] = { ccn384_32( A(23), A(22), A(21), A(20), A(19), A(18), A(17), A(16), A(15), A(14), A(13), A(12)) }; cc_unit s3[CCN384_N] = { ccn384_32( A(20), A(19), A(18), A(17), A(16), A(15), A(14), A(13), A(12), A(23), A(22), A(21)) }; cc_unit s4[CCN384_N] = { ccn384_32( A(19), A(18), A(17), A(16), A(15), A(14), A(13), A(12), A(20), Anil, A(23), Anil) }; cc_unit s5[CCN384_N] = { ccn384_32( Anil, Anil, Anil, Anil, A(23), A(22), A(21), A(20), Anil, Anil, Anil, Anil) }; cc_unit s6[CCN384_N] = { ccn384_32( Anil, Anil, Anil, Anil, Anil, Anil, A(23), A(22), A(21), Anil, Anil, A(20)) }; cc_unit d1[CCN384_N] = { ccn384_32( A(22), A(21), A(20), A(19), A(18), A(17), A(16), A(15), A(14), A(13), A(12), A(23)) }; cc_unit d2[CCN384_N] = { ccn384_32( Anil, Anil, Anil, Anil, Anil, Anil, Anil, A(23), A(22), A(21), A(20), Anil) }; cc_unit d3[CCN384_N] = { ccn384_32( Anil, Anil, Anil, Anil, Anil, Anil, Anil, A(23), A(23), Anil, Anil, Anil) }; cc_unit *select[2] __attribute__((aligned(16))) ={s1,s3}; cc_unit carry,carry_mask; ccn_add(ccn_nof(160)+1, d2, d2, d3); // smaller size and no carry possible ccn_add(ccn_nof(224)+1, s1, s1, s1); // smaller size and no carry possible, alternatively cc_shiftl(s1, 1) but add is currently faster. ccn_add(ccn_nof(256)+1, s5, s5, s1); // smaller size and no carry possible ccn_add(ccn_nof(256)+1, s5, s5, s6); // smaller size and no carry possible carry = ccn_add(CCN384_N, r, a, &a[CCN384_N]); carry += ccn_add(CCN384_N, r, r, s3); carry += ccn_add(CCN384_N, r, r, s4); carry += ccn_add(CCN384_N, r, r, s5); carry -= ccn_sub(CCN384_N, d1, cczp_prime(zp), d1); carry += ccn_add(CCN384_N, r, r, d1); carry -= ccn_sub(CCN384_N, s3, r, d2); /* Reduce r mod p384 by subtraction of up to four multiples of p384. */ carry_mask=CC_CARRY_3BITS(carry); carry -= (carry_mask & ccn_sub(CCN384_N,select[carry_mask],s3,cczp_prime(zp))); carry_mask=CC_CARRY_2BITS(carry); carry -= (carry_mask & ccn_sub(CCN384_N,select[carry_mask],s3,cczp_prime(zp))); carry_mask=CC_CARRY_2BITS(carry); carry -= (carry_mask & ccn_sub(CCN384_N,select[carry_mask],s3,cczp_prime(zp))); carry ^= ccn_sub(CCN384_N,s1,s3,cczp_prime(zp)); ccn_set(CCN384_N,r,select[carry]); /* Sanity for debug */ cc_assert(ccn_cmp(CCN384_N, r, cczp_prime(zp)) < 0); }
/* r = s^e (mod zp->prime). Caller provides recip of m as recip; s and r can have the same address. */ void cczp_power(cczp_const_t zp, cc_unit *r, const cc_unit *s, const cc_unit *e) { cc_size n = cczp_n(zp); unsigned long ebitlen = ccn_bitlen(n, e); if (ebitlen == 0) { ccn_seti(n, r, 1); return; } CC_DECL_WORKSPACE(ws, CCZP_MUL_WORKSPACE_N(n)+n); cc_unit *r1=ws->start; ws->start+=n; /* do we actually need to handle this case where s>m */ if (ccn_cmp(cczp_n(zp), s, cczp_prime(zp)) >= 0) { cc_unit *tbig=ws->start; // 2*n buffer ws->start+=2*n; ccn_zero(n, tbig + n); ccn_set(n, tbig, s); cczp_mod(zp, r, tbig, ws); ws->start-=2*n; } else { ccn_set(n, r, s); } if (ebitlen != 1) { cc_unit *R[2] __attribute__((aligned(16)))={r,r1}; cczp_sqr_ws(zp, r1, r, ws); for (unsigned long bit = ebitlen - 2; bit < ebitlen; --bit) { cc_unit ki=ccn_bit(e, bit); cczp_mul_ws(zp, R[ki^1], R[ki], R[ki^1],ws); cczp_sqr_ws(zp, R[ki], R[ki], ws); } } ws->start-=n; // r CC_CLEAR_AND_FREE_WORKSPACE(ws); }
static int ccec_mult_ws(ccec_const_cp_t cp, ccec_projective_point_t r, const cc_unit *d, ccec_const_projective_point_t s, struct ccrng_state *rng, cc_ws_t ws) { cc_size n=ccec_cp_n(cp); size_t dbitlen=ccn_bitlen(n,d); cc_unit *R0=ws->start; // R0 and R1 are full points: cc_unit *R1=ws->start+2*n; // X in [0..n-1] and Y in [n..2n-1] ws->start+=4*n; cc_assert((ws->start)<=ws->end); // Check that provided workspace is sufficient; // Check edge cases // Scalar d must be <= q to // prevent intermediary results to be the point at infinity // corecrypto to take care to meet this requirement cc_assert(ccn_cmp(n,d,cczp_prime(ccec_cp_zq(cp)))<=0); // d <= q ccn_sub1(n,R0,cczp_prime(ccec_cp_zq(cp)),1); // q-1 if (dbitlen < 1) { ccn_clear(n, ccec_point_x(r, cp)); ccn_clear(n, ccec_point_y(r, cp)); ccn_clear(n, ccec_point_z(r, cp)); } else if (dbitlen == 1) { // If d=1 => r=s ccn_set(n, ccec_point_x(r, cp), ccec_const_point_x(s, cp)); ccn_set(n, ccec_point_y(r, cp), ccec_const_point_y(s, cp)); ccn_set(n, ccec_point_z(r, cp), ccec_const_point_z(s, cp)); } else if (ccn_cmp(n,d,R0)==0) { // If d=(q-1) => r=-s // Case not handle by Montgomery Ladder because R1-R0 = s. // On the last iteration r=R0 => R1 is equal to infinity which is not supported ccn_set(n, ccec_point_x(r, cp), ccec_const_point_x(s, cp)); ccn_sub(n, ccec_point_y(r, cp), cczp_prime(cp.zp), ccec_const_point_y(s, cp)); ccn_set(n, ccec_point_z(r, cp), ccec_const_point_z(s, cp)); } else { // Randomize buffer to harden against cache attacks // TODO: scalar randomization. cc_unit c=1; if (rng) ccn_random_bits(1,&c,rng); // Core of the EC scalar multiplication cc_unit dbit; // Bit of d at index i cc_unit *R[2] __attribute__((aligned(16)))={R0,R1}; XYCZdblJac(cp,R[c^1],R[c^0],s,ws); // Main loop for (unsigned long i = dbitlen - 2; i>0; --i) { dbit=c^(ccn_bit(d, i)); XYCZaddC(cp,R[dbit],R[1^dbit],ws); XYCZadd(cp,R[dbit],R[1^dbit],ws); // Per Montgomery Ladder: // Invariably, R1 - R0 = P at this point of the loop } // Last iteration dbit=c^(ccn_bit(d, 0)); XYCZaddC(cp,R[dbit],R[1^dbit],ws); // If d0 = 0 1 // R1-R0=-P R1-R0=P // Therefore we can reconstruct the Z coordinate // To save an inversion and keep the result in Jacobian projective coordinates, // we compute coefficient for X and Y. XYCZrecoverCoeffJac(cp, ccec_point_x(r, cp), ccec_point_y(r, cp), ccec_point_z(r, cp), R[c^1],R[c^0], (int)(dbit^c), s, ws); XYCZadd(cp,R[dbit],R[1^dbit],ws); // Apply coefficients cczp_mul_ws(cp.zp, ccec_point_x(r, cp), ccec_point_x(r, cp), &(R[c][0]), ws); // X0 * lambdaX cczp_mul_ws(cp.zp, ccec_point_y(r, cp), ccec_point_y(r, cp), &(R[c][n]), ws); // Y0 * lambdaY } #if CCEC_MULT_DEBUG ccn_lprint(n, "Result X:", ccec_point_x(r, cp)); ccn_lprint(n, "Result Y:", ccec_point_y(r, cp)); ccn_lprint(n, "Result Z:", ccec_point_z(r, cp)); #endif ws->start-=4*n; return 0; }
static OSStatus SecRSAPrivateKeyRawSign(SecKeyRef key, SecPadding padding, const uint8_t *dataToSign, size_t dataToSignLen, uint8_t *sig, size_t *sigLen) { OSStatus result = errSecParam; ccrsa_full_ctx_t fullkey; fullkey.full = key->key; size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); cc_unit s[ccrsa_ctx_n(fullkey)]; uint8_t* sBytes = (uint8_t*) s; require(sigLen, errOut); require(*sigLen >= m_size, errOut); switch (padding) { case kSecPaddingNone: require_noerr_quiet(ccn_read_uint(ccrsa_ctx_n(fullkey), s, dataToSignLen, dataToSign), errOut); require_quiet(ccn_cmp(ccrsa_ctx_n(fullkey), s, ccrsa_ctx_m(fullkey)) < 0, errOut); break; case kSecPaddingPKCS1: { // Create PKCS1 padding: // // 0x00, 0x01 (RSA_PKCS1_PAD_SIGN), 0xFF .. 0x00, signedData // const int kMinimumPadding = 1 + 1 + 8 + 1; require(dataToSignLen < m_size - kMinimumPadding, errOut); size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(fullkey)) - m_size; while (prefix_zeros--) *sBytes++ = 0x00; size_t pad_size = m_size - dataToSignLen; *sBytes++ = 0x00; *sBytes++ = RSA_PKCS1_PAD_SIGN; size_t ff_size; for(ff_size = pad_size - 3; ff_size > 0; --ff_size) *sBytes++ = 0xFF; *sBytes++ = 0x00; // Get the user data into s looking like a ccn. memcpy(sBytes, dataToSign, dataToSignLen); ccn_swap(ccrsa_ctx_n(fullkey), s); break; } case kSecPaddingOAEP: result = errSecParam; default: goto errOut; } ccrsa_priv_crypt(ccrsa_ctx_private(fullkey), s, s); // Pad with leading zeros to fit in modulus size ccn_write_uint_padded(ccrsa_ctx_n(fullkey), s, m_size, sig); *sigLen = m_size; result = errSecSuccess; errOut: ccn_zero(ccrsa_ctx_n(fullkey), s); return result; }
static OSStatus SecRSAPublicKeyRawEncrypt(SecKeyRef key, SecPadding padding, const uint8_t *plainText, size_t plainTextLen, uint8_t *cipherText, size_t *cipherTextLen) { OSStatus result = errSecParam; ccrsa_pub_ctx_t pubkey; pubkey.pub = key->key; cc_unit s[ccrsa_ctx_n(pubkey)]; const size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); require(cipherTextLen, errOut); require(*cipherTextLen >= m_size, errOut); uint8_t* sBytes = (uint8_t*) s; switch (padding) { case kSecPaddingNone: require_noerr_quiet(ccn_read_uint(ccrsa_ctx_n(pubkey), s, plainTextLen, plainText), errOut); require_quiet(ccn_cmp(ccrsa_ctx_n(pubkey), s, ccrsa_ctx_m(pubkey)) < 0, errOut); break; case kSecPaddingPKCS1: { // Create PKCS1 padding: // // 0x00, 0x01 (RSA_PKCS1_PAD_ENCRYPT), 0xFF .. 0x00, signedData // const int kMinimumPadding = 1 + 1 + 8 + 1; require_quiet(plainTextLen < m_size - kMinimumPadding, errOut); size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(pubkey)) - m_size; while (prefix_zeros--) *sBytes++ = 0x00; size_t pad_size = m_size - plainTextLen; *sBytes++ = 0x00; *sBytes++ = RSA_PKCS1_PAD_ENCRYPT; ccrng_generate(ccrng_seckey, pad_size - 3, sBytes); // Remove zeroes from the random pad const uint8_t* sEndOfPad = sBytes + (pad_size - 3); while (sBytes < sEndOfPad) { if (*sBytes == 0x00) *sBytes = 0xFF; // Michael said 0xFF was good enough. ++sBytes; } *sBytes++ = 0x00; memcpy(sBytes, plainText, plainTextLen); ccn_swap(ccrsa_ctx_n(pubkey), s); break; } case kSecPaddingOAEP: { const struct ccdigest_info* di = ccsha1_di(); const size_t encodingOverhead = 2 + 2 * di->output_size; require_action(m_size > encodingOverhead, errOut, result = errSecParam); require_action_quiet(plainTextLen < m_size - encodingOverhead, errOut, result = errSSLCrypto); require_noerr_action(ccrsa_oaep_encode(di, ccrng_seckey, m_size, s, plainTextLen, plainText), errOut, result = errSecInternal); break; } default: goto errOut; } ccrsa_pub_crypt(pubkey, s, s); ccn_write_uint_padded(ccrsa_ctx_n(pubkey), s, m_size, cipherText); *cipherTextLen = m_size; result = errSecSuccess; errOut: ccn_zero(ccrsa_ctx_n(pubkey), s); return result; }