int ccrsa_verify_pkcs1v15(ccrsa_pub_ctx_t key, const uint8_t *oid, size_t digest_len, const uint8_t *digest, size_t sig_len, const uint8_t *sig, bool *valid) { size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(key), ccrsa_ctx_m(key)); cc_size n=ccrsa_ctx_n(key); cc_unit s[n]; *valid = false; int err; cc_require_action(sig_len==m_size,errOut,err=CCRSA_INVALID_INPUT); ccn_read_uint(n, s, sig_len, sig); cc_require((err=ccrsa_pub_crypt(key, s, s))==0,errOut); { unsigned char em[m_size]; ccn_write_uint_padded(n, s, m_size, em); #ifdef VERIFY_BY_ENCODE_THEN_MEMCMP unsigned char em2[m_size]; cc_require((err=ccrsa_emsa_pkcs1v15_encode(m_size, em2, digest_len, digest, oid))==0,errOut); /* digest len is too big ?*/ if(memcmp(em, em2, m_size)==0) *valid = true; #else if(ccrsa_emsa_pkcs1v15_verify(m_size, em, digest_len, digest, oid)==0) *valid = true; #endif } errOut: return err; }
/* siglen will be the actual lenght of the prime in bytes */ int ccrsa_sign_pkcs1v15(ccrsa_full_ctx_t key, const uint8_t *oid, size_t digest_len, const uint8_t *digest, size_t *sig_len, uint8_t *sig) { size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(key), ccrsa_ctx_m(key)); cc_size n=ccrsa_ctx_n(key); cc_unit s[n]; int err; if(*sig_len<m_size) return CCRSA_INVALID_INPUT; *sig_len=m_size; err=ccrsa_emsa_pkcs1v15_encode(m_size, sig, digest_len, digest, oid); if(err) return err; ccn_read_uint(n, s, m_size, sig); err=ccrsa_priv_crypt(ccrsa_ctx_private(key), s, s); if(err) return err; /* we need to write leading zeroes if necessary */ ccn_write_uint_padded(n, s, m_size, sig); return 0; }
CCCryptorStatus CCRSACryptorCrypt(CCRSACryptorRef rsaKey, const void *in, size_t inLen, void *out, size_t *outLen) { CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n"); if(!rsaKey || !in || !out || !outLen) return kCCParamError; size_t keysizeBytes = (rsaKey->keySize+7)/8; if(inLen != keysizeBytes || *outLen < keysizeBytes) return kCCMemoryFailure; cc_size n = ccrsa_ctx_n(rsaKey->fk); cc_unit buf[n]; ccn_read_uint(n, buf, inLen, in); switch(rsaKey->keyType) { case ccRSAKeyPublic: ccrsa_pub_crypt(ccrsa_ctx_public(rsaKey->fk), buf, buf); break; case ccRSAKeyPrivate: ccrsa_priv_crypt(ccrsa_ctx_private(rsaKey->fk), buf, buf); break; default: return kCCParamError; } *outLen = keysizeBytes; ccn_write_uint_padded(n, buf, *outLen, out); return kCCSuccess; }
/* siglen will be the actual lenght of the prime in bytes */ int ccrsa_sign_oaep(ccrsa_full_ctx_t key, const struct ccdigest_info* di, struct ccrng_state *rng, size_t digest_len, const uint8_t *digest, size_t *sig_len, uint8_t *sig) { size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(key), ccrsa_ctx_m(key)); cc_size n=ccrsa_ctx_n(key); cc_unit s[n]; int err; if(*sig_len<m_size) return CCRSA_INVALID_INPUT; *sig_len=m_size; err=ccrsa_oaep_encode(di, rng, m_size, s, digest_len, digest); if(err) return err; err=ccrsa_priv_crypt(ccrsa_ctx_private(key), s, s); if(err) return err; /* we need to write leading zeroes if necessary */ ccn_write_uint_padded(n, s, m_size, sig); return 0; }
static CFDataRef SecECPPrivateKeyExport(CFAllocatorRef allocator, ccec_full_ctx_t fullkey) { size_t prime_size = ccec_cp_prime_size(ccec_ctx_cp(fullkey)); size_t key_size = ccec_export_pub_size(fullkey) + prime_size; CFMutableDataRef blob = CFDataCreateMutable(allocator, key_size); if (blob) { CFDataSetLength(blob, key_size); ccec_export_pub(fullkey, CFDataGetMutableBytePtr(blob)); UInt8 *dest = CFDataGetMutableBytePtr(blob) + ccec_export_pub_size(fullkey); const cc_unit *k = ccec_ctx_k(fullkey); ccn_write_uint_padded(ccec_ctx_n(fullkey), k, prime_size, dest); } return blob; }
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; }
void ccz_write_uint(const ccz *s, size_t out_size, void *out) { ccn_write_uint_padded(ccz_n(s), s->u, out_size, out); }
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; }
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; }