static size_t ccn_write_radix_size(cc_size n, const cc_unit *s, unsigned radix) { if (ccn_is_zero(n, s)) { return 1; } /* digs is the digit count */ cc_unit uradix[1] = { radix }; size_t k = ccn_bitlen(1, uradix) - 1; size_t l = ccn_trailing_zeros(1, uradix); if (k == l) { /* Radix is 2**k. */ return (ccn_bitlen(n, s) + k - 1) / k; } else { size_t size = 0; n = ccn_n(n, s); cc_unit t[n]; ccn_set(n, t, s); cc_unit v[1]; while (n) { ccn_div1(n, t, v, t, radix); n = ccn_n(n, t); ++size; } return size; } }
CCCryptorStatus CCRSACryptorCreateFromData( CCRSAKeyType keyType, uint8_t *modulus, size_t modulusLength, uint8_t *exponent, size_t exponentLength, uint8_t *p, size_t pLength, uint8_t *q, size_t qLength, CCRSACryptorRef *ref) { CCCryptorStatus retval = kCCSuccess; CCRSACryptor *rsaKey = NULL; size_t n = ccn_nof_size(modulusLength); cc_unit m[n]; CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n"); __Require_Action(ccn_read_uint(n, m, modulusLength, modulus) == 0, errOut, retval = kCCParamError); size_t nbits = ccn_bitlen(n, m); __Require_Action((rsaKey = ccMallocRSACryptor(nbits, keyType)) != NULL, errOut, retval = kCCMemoryFailure); __Require_Action(ccn_read_uint(n, ccrsa_ctx_m(rsaKey->fk), modulusLength, modulus) == 0, errOut, retval = kCCParamError); __Require_Action(ccn_read_uint(n, ccrsa_ctx_e(rsaKey->fk), exponentLength, exponent) == 0, errOut, retval = kCCParamError); cczp_init(ccrsa_ctx_zm(rsaKey->fk)); rsaKey->keySize = ccn_bitlen(n, ccrsa_ctx_m(rsaKey->fk)); switch(keyType) { case ccRSAKeyPublic: rsaKey->keyType = ccRSAKeyPublic; break; case ccRSAKeyPrivate: { ccrsa_priv_ctx_t privk = ccrsa_ctx_private(rsaKey->fk); size_t psize = ccn_nof_size(pLength); size_t qsize = ccn_nof_size(qLength); CCZP_N(ccrsa_ctx_private_zp(privk)) = psize; __Require_Action(ccn_read_uint(psize, CCZP_PRIME(ccrsa_ctx_private_zp(privk)), pLength, p) == 0, errOut, retval = kCCParamError); CCZP_N(ccrsa_ctx_private_zq(privk)) = qsize; __Require_Action(ccn_read_uint(qsize, CCZP_PRIME(ccrsa_ctx_private_zq(privk)), qLength, q) == 0, errOut, retval = kCCParamError); ccrsa_crt_makekey(ccrsa_ctx_zm(rsaKey->fk), ccrsa_ctx_e(rsaKey->fk), ccrsa_ctx_d(rsaKey->fk), ccrsa_ctx_private_zp(privk), ccrsa_ctx_private_dp(privk), ccrsa_ctx_private_qinv(privk), ccrsa_ctx_private_zq(privk), ccrsa_ctx_private_dq(privk)); rsaKey->keyType = ccRSAKeyPrivate; break; } default: retval = kCCParamError; goto errOut; } *ref = rsaKey; return kCCSuccess; errOut: if(rsaKey) ccRSACryptorClear(rsaKey); 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); } }
// Key is expected to be in PKCS #1 format cc_size ccder_decode_rsa_pub_n(const uint8_t *der, const uint8_t *der_end) { cc_size n = ccn_nof(8192); cc_unit m[n]; if((der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &der_end, der, der_end)) == NULL) return 0; if((der = ccder_decode_uint(n, m, der, der_end)) == NULL) return 0; return ccn_nof(ccn_bitlen(n, m)); }
cc_size ccder_decode_rsa_priv_n(const uint8_t *der, const uint8_t *der_end) { cc_unit version_0[ccn_nof(1)] = {0x00}; cc_size n = ccn_nof(8192); cc_unit m[n]; if((der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &der_end, der, der_end)) == NULL) return 0; if((der = ccder_decode_uint(1, version_0, der, der_end)) == NULL) return 0; if(version_0[0] != 0) return 0; if((der = ccder_decode_uint(n, m, der, der_end)) == NULL) return 0; return ccn_nof(ccn_bitlen(n, m)); }
static void ccn_div1(cc_size n, cc_unit *q, cc_unit *r, const cc_unit *s, cc_unit v) { if (n == 0) { *r = 0; return; } size_t k = ccn_bitlen(1, &v) - 1; size_t l = ccn_trailing_zeros(1, &v); if (k == l) { /* Divide by power of 2, remainder in *r. */ *r = s[0] & (v - 1); ccn_shift_right(n, q, s, k); } else { ccn_divn(n, q, r, s, 1, &v); } }
void ccz_lsr(ccz *r, const ccz *s, size_t k) { size_t l = ccn_bitlen(ccz_n(s), s->u); if (l <= k) { ccz_zero(r); } else { cc_size kn = k / CCN_UNIT_BITS; l -= k; k &= (CCN_UNIT_BITS - 1); ccz_set_sign(r, ccz_sign(s)); ccz_set_capacity(r, ccz_n(s) - kn); if (k) { ccn_shift_right(ccz_n(s) - kn, r->u, s->u + kn, k); } else if (kn || r != s) { /* Forward copy, safe to use ccn_set(). */ ccn_set(ccz_n(s) - kn, r->u, s->u + kn); } ccz_set_n(r, ccn_nof(l)); } }
/* 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); }
// verify the signature in sig. The original (hash of the message) message is in digest int ccrsa_verify_pss(ccrsa_pub_ctx_t key, const struct ccdigest_info* di, const struct ccdigest_info* MgfDi, size_t digestSize, const uint8_t *digest, size_t sigSize, const uint8_t *sig, size_t saltSize, bool *valid) { const cc_size modBits =ccn_bitlen(ccrsa_ctx_n(key), ccrsa_ctx_m(key)); const cc_size modBytes = cc_ceiling(modBits, 8); const cc_size emBits = modBits-1; //as defined in §8.1.1 const cc_size emSize = cc_ceiling(emBits, 8); *valid = false; int rc=0; //1. if(modBytes!= sigSize) return CCRSA_INVALID_INPUT; if(digestSize != di->output_size) return CCRSA_INVALID_INPUT; //2. const cc_size modWords=ccrsa_ctx_n(key); cc_unit EM[modWords]; //EM islarge enough to fit sig variable //2.a read sig to tmp array and make sure it fits cc_require_action(ccn_read_uint(modWords, EM, sigSize, sig)==0,errOut,rc=CCRSA_INVALID_INPUT); //2.b cc_require((rc=ccrsa_pub_crypt(key, EM, EM))==0,errOut); //2.c ccn_swap(modWords, EM); //3 const size_t ofs = modWords*sizeof(cc_unit)-emSize; cc_assert(ofs<=sizeof(cc_unit)); //make sure sizes are consistent and we don't overrun buffers. rc|= ccrsa_emsa_pss_decode(di, MgfDi, saltSize, digestSize, digest, emBits, (uint8_t *) EM+ofs); *valid = (rc==0)?true:false; errOut: return rc; }
int p12_pbe_gen(CFStringRef passphrase, uint8_t *salt_ptr, size_t salt_length, unsigned iter_count, P12_PBE_ID pbe_id, uint8_t *data, size_t length) { unsigned int hash_blocksize = CC_SHA1_BLOCK_BYTES; unsigned int hash_outputsize = CC_SHA1_DIGEST_LENGTH; if (!passphrase) return -1; /* generate diversifier block */ unsigned char diversifier[hash_blocksize]; memset(diversifier, pbe_id, sizeof(diversifier)); /* convert passphrase to BE UTF16 and append double null */ CFDataRef passphrase_be_unicode = CFStringCreateExternalRepresentation(kCFAllocatorDefault, passphrase, kCFStringEncodingUTF16BE, '\0'); if (!passphrase_be_unicode) return -1; uint8_t null_termination[2] = { 0, 0 }; CFMutableDataRef passphrase_be_unicode_null_term = CFDataCreateMutableCopy(NULL, 0, passphrase_be_unicode); CFRelease(passphrase_be_unicode); if (!passphrase_be_unicode_null_term) return -1; CFDataAppendBytes(passphrase_be_unicode_null_term, null_termination, sizeof(null_termination)); /* generate passphrase block */ uint8_t *passphrase_data = NULL; size_t passphrase_data_len = 0; size_t passphrase_length = CFDataGetLength(passphrase_be_unicode_null_term); const unsigned char *passphrase_ptr = CFDataGetBytePtr(passphrase_be_unicode_null_term); passphrase_data = concatenate_to_blocksize(passphrase_ptr, passphrase_length, hash_blocksize, &passphrase_data_len); CFRelease(passphrase_be_unicode_null_term); if (!passphrase_data) return -1; /* generate salt block */ uint8_t *salt_data = NULL; size_t salt_data_len = 0; if (salt_length) salt_data = concatenate_to_blocksize(salt_ptr, salt_length, hash_blocksize, &salt_data_len); if (!salt_data) return -1; /* generate S||P block */ size_t I_length = salt_data_len + passphrase_data_len; uint8_t *I_data = malloc(I_length); if (!I_data) return -1; memcpy(I_data + 0, salt_data, salt_data_len); memcpy(I_data + salt_data_len, passphrase_data, passphrase_data_len); free(salt_data); free(passphrase_data); /* round up output buffer to multiple of hash block size and allocate */ size_t hash_output_blocks = (length + hash_outputsize - 1) / hash_outputsize; size_t temp_buf_size = hash_output_blocks * hash_outputsize; uint8_t *temp_buf = malloc(temp_buf_size); uint8_t *cursor = temp_buf; if (!temp_buf) return -1; /* 64 bits cast(s): worst case here is we dont hash all the data and incorectly derive the wrong key, when the passphrase + salt are over 2^32 bytes long */ /* loop over output in hash_output_size increments */ while (cursor < temp_buf + temp_buf_size) { CC_SHA1_CTX ctx; CC_SHA1_Init(&ctx); CC_SHA1_Update(&ctx, diversifier, (CC_LONG)sizeof(diversifier)); assert(I_length<=UINT32_MAX); /* debug check. Correct as long as CC_LONG is uint32_t */ CC_SHA1_Update(&ctx, I_data, (CC_LONG)I_length); CC_SHA1_Final(cursor, &ctx); /* run block through SHA-1 for iteration count */ unsigned int i; for (i = 1; /*first round done above*/ i < iter_count; i++) CC_SHA1(cursor, hash_outputsize, cursor); /* * b) Concatenate copies of A[i] to create a string B of * length v bits (the final copy of A[i]i may be truncated * to create B). */ size_t A_i_len = 0; uint8_t *A_i = concatenate_to_blocksize(cursor, hash_outputsize, hash_blocksize, &A_i_len); if (!A_i) return -1; /* * c) Treating I as a concatenation I[0], I[1], ..., * I[k-1] of v-bit blocks, where k = ceil(s/v) + ceil(p/v), * modify I by setting I[j]=(I[j]+B+1) mod (2 ** v) * for each j. */ /* tmp1 = B+1 */ const cc_size tmp_n = ccn_nof_size(A_i_len + 1) > ccn_nof_size(hash_blocksize) ? ccn_nof_size(A_i_len + 1) : ccn_nof_size(hash_blocksize); cc_unit tmp1[tmp_n]; ccn_read_uint(tmp_n, tmp1, A_i_len, A_i); ccn_add1(tmp_n, tmp1, tmp1, 1); free(A_i); cc_unit tmp2[tmp_n]; unsigned int j; for (j = 0; j < I_length; j+=hash_blocksize) { /* tempg = I[j]; */ ccn_read_uint(tmp_n, tmp2, hash_blocksize, I_data + j); /* tempg += tmp1 */ ccn_add(tmp_n, tmp2, tmp2, tmp1); /* I[j] = tempg mod 2**v Just clear all the high bits above 2**v In practice at most it rolled over by 1 bit, since all we did was add so we should only clear one bit at most. */ size_t bitSize; const size_t hash_blocksize_bits = hash_blocksize * 8; while ((bitSize = ccn_bitlen(tmp_n, tmp2)) > hash_blocksize_bits) { ccn_set_bit(tmp2, bitSize - 1, 0); } ccn_write_uint_padded(tmp_n, tmp2, hash_blocksize, I_data + j); } cursor += hash_outputsize; } /* * 7. Concatenate A[1], A[2], ..., A[c] together to form a * pseudo-random bit string, A. * * 8. Use the first n bits of A as the output of this entire * process. */ memmove(data, temp_buf, length); free(temp_buf); free(I_data); return 0; }
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 inline size_t ccRSAkeysize(CCRSACryptor *cryptor) { return ccn_bitlen(ccrsa_ctx_n(cryptor->fk), ccrsa_ctx_m(cryptor->fk)); }