OSStatus SecDHCreate(uint32_t g, const uint8_t *p, size_t p_len, uint32_t l, const uint8_t *recip, size_t recip_len, SecDHContext *pdh) { cc_size n = ccn_nof_size(p_len); size_t context_size = SecDH_context_size(p_len); void *context = malloc(context_size); bzero(context, context_size); ccdh_gp_t gp; gp.gp = context; CCDH_GP_N(gp) = n; CCDH_GP_L(gp) = l; if(ccn_read_uint(n, CCDH_GP_PRIME(gp), p_len, p)) goto errOut; if(recip) { if(ccn_read_uint(n+1, CCDH_GP_RECIP(gp), recip_len, recip)) goto errOut; CCZP_MOD_PRIME(gp.zp) = cczp_mod; } else { cczp_init(gp.zp); }; ccn_seti(n, CCDH_GP_G(gp), g); *pdh = (SecDHContext) context; return errSecSuccess; errOut: SecDHDestroy(context); *pdh = NULL; return errSecInternal; }
static int ccrsa_priv_init(ccrsa_priv_ctx_t privkey, size_t p_size, const uint8_t* p, size_t q_size, const uint8_t* q, size_t dp_size, const uint8_t* dp, size_t dq_size, const uint8_t* dq, size_t qinv_size, const uint8_t* qinv) { int result = -1; const cc_size np = cczp_n(ccrsa_ctx_private_zp(privkey)); cc_size nq = cczp_n(ccrsa_ctx_private_zq(privkey)); if (ccn_read_uint(np, CCZP_PRIME(ccrsa_ctx_private_zp(privkey)), p_size, p)) goto errOut; cczp_init(ccrsa_ctx_private_zp(privkey)); if (ccn_read_uint(np, ccrsa_ctx_private_dp(privkey), dp_size, dp)) goto errOut; if (ccn_read_uint(np, ccrsa_ctx_private_qinv(privkey), qinv_size, qinv)) goto errOut; if (ccn_read_uint(nq, CCZP_PRIME(ccrsa_ctx_private_zq(privkey)), q_size, q)) goto errOut; nq = ccn_n(nq, cczp_prime(ccrsa_ctx_private_zq(privkey))); CCZP_N(ccrsa_ctx_private_zq(privkey)) = nq; cczp_init(ccrsa_ctx_private_zq(privkey)); if (ccn_read_uint(nq, ccrsa_ctx_private_dq(privkey), dq_size, dq)) goto errOut; result = 0; errOut: return result; }
int ccec_make_priv(size_t nbits, size_t xlength, uint8_t *x, size_t ylength, uint8_t *y, size_t klength, uint8_t *k, ccec_full_ctx_t key) { int result; ccec_const_cp_t cp = ccec_get_cp(nbits); ccec_ctx_init(cp, key); if ((result = ccn_read_uint(ccec_cp_n(cp), ccec_ctx_x(key), xlength, x))) goto errOut; if ((result = ccn_read_uint(ccec_cp_n(cp), ccec_ctx_y(key), ylength, y))) goto errOut; if ((result = ccn_read_uint(ccec_cp_n(cp), ccec_ctx_k(key), klength, k))) goto errOut; ccn_seti(ccec_cp_n(cp), ccec_ctx_z(key), 1); errOut: return result; }
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; }
OSStatus SecDHCreateFromParameters(const uint8_t *params, size_t params_len, SecDHContext *pdh) { DERReturn drtn; DERItem paramItem = {(DERByte *)params, params_len}; DER_DHParams decodedParams; uint32_t l; drtn = DERParseSequence(¶mItem, DER_NumDHParamsItemSpecs, DER_DHParamsItemSpecs, &decodedParams, sizeof(decodedParams)); if(drtn) return drtn; drtn = DERParseInteger(&decodedParams.l, &l); if(drtn) return drtn; cc_size n = ccn_nof_size(decodedParams.p.length); cc_size p_len = ccn_sizeof_n(n); size_t context_size = ccdh_gp_size(p_len)+ccdh_full_ctx_size(p_len); void *context = malloc(context_size); if(context==NULL) return errSecAllocate; bzero(context, context_size); ccdh_gp_t gp; gp.gp = context; CCDH_GP_N(gp) = n; CCDH_GP_L(gp) = l; if(ccn_read_uint(n, CCDH_GP_PRIME(gp), decodedParams.p.length, decodedParams.p.data)) goto errOut; if(decodedParams.recip.length) { if(ccn_read_uint(n+1, CCDH_GP_RECIP(gp), decodedParams.recip.length, decodedParams.recip.data)) goto errOut; gp.zp.zp->mod_prime = cczp_mod; } else { cczp_init(gp.zp); }; if(ccn_read_uint(n, CCDH_GP_G(gp), decodedParams.g.length, decodedParams.g.data)) goto errOut; *pdh = (SecDHContext) context; return errSecSuccess; errOut: SecDHDestroy(context); *pdh = NULL; return errSecInvalidKey; }
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; }
static inline int cczp_read_uint(cczp_t r, size_t data_size, const uint8_t *data) { if(ccn_read_uint(ccn_nof_size(data_size), CCZP_PRIME(r), data_size, data) != 0) return -1; CCZP_N(r) = ccn_nof_size(data_size); cczp_init(r); 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_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; }
// // pubkey is initilaized with an n which is the maximum it can hold // We set the n to its correct value given m. // static int ccrsa_pub_init(ccrsa_pub_ctx_t pubkey, size_t m_size, const uint8_t* m, size_t e_size, const uint8_t* e) { cc_skip_zeros(m_size, m); cc_size nm = ccn_nof_size(m_size); if (nm > ccrsa_ctx_n(pubkey)) return -1; ccrsa_ctx_n(pubkey) = nm; ccn_read_uint(nm, ccrsa_ctx_m(pubkey), m_size, m); cczp_init(ccrsa_ctx_zm(pubkey)); return ccn_read_uint(nm, ccrsa_ctx_e(pubkey), e_size, e); }
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 OSStatus ccrsa_full_decode(ccrsa_full_ctx_t fullkey, size_t pkcs1_size, const uint8_t* pkcs1) { OSStatus result = errSecParam; DERItem keyItem = {(DERByte *)pkcs1, pkcs1_size}; DERRSAKeyPair decodedKey; require_noerr_action(DERParseSequence(&keyItem, DERNumRSAKeyPairItemSpecs, DERRSAKeyPairItemSpecs, &decodedKey, sizeof(decodedKey)), errOut, result = errSecDecode); require_noerr(ccrsa_pub_init(fullkey, decodedKey.n.length, decodedKey.n.data, decodedKey.e.length, decodedKey.e.data), errOut); ccn_read_uint(ccrsa_ctx_n(fullkey), ccrsa_ctx_d(fullkey), decodedKey.d.length, decodedKey.d.data); { ccrsa_priv_ctx_t privkey = ccrsa_ctx_private(fullkey); CCZP_N(ccrsa_ctx_private_zp(privkey)) = ccn_nof((ccn_bitsof_n(ccrsa_ctx_n(fullkey)) / 2) + 1); CCZP_N(ccrsa_ctx_private_zq(privkey)) = cczp_n(ccrsa_ctx_private_zp(privkey)); // TODO: Actually remember decodedKey.d. require_noerr(ccrsa_priv_init(privkey, decodedKey.p.length, decodedKey.p.data, decodedKey.q.length, decodedKey.q.data, decodedKey.dp.length, decodedKey.dp.data, decodedKey.dq.length, decodedKey.dq.data, decodedKey.qInv.length, decodedKey.qInv.data), errOut); } result = errSecSuccess; errOut: return result; }
// 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 ccrsa_decrypt_oaep(ccrsa_full_ctx_t key, const struct ccdigest_info* di, size_t *r_size, uint8_t *r, size_t c_size, uint8_t *c, size_t parameter_data_len, const uint8_t *parameter_data) { size_t m_size = ccrsa_block_size(key); cc_size n=ccrsa_ctx_n(key); cc_unit tmp[n]; int err; // Sanity check if (m_size<di->output_size*2+1) { return CCRSA_INVALID_CONFIG; } // Output buffer is too small if(*r_size<m_size-di->output_size*2+2) { return CCRSA_INVALID_INPUT; } // The ciphertext does not match the expected size if ((c_size<m_size) || (ccn_read_uint(n, tmp, c_size, c))) { return CCRSA_INVALID_INPUT; } // RSA decryption if ((err = ccrsa_priv_crypt(ccrsa_ctx_private(key), tmp, tmp)) == 0) { // Padding decoding err = ccrsa_oaep_decode_parameter(di, r_size, r, m_size, tmp, parameter_data_len, parameter_data); } return err; }
int ccrsa_test_verify_pkcs1v15_vector(const struct ccrsa_verify_vector *v) { bool ok; int rc; const struct ccdigest_info *di = v->di; const cc_size n = ccn_nof(v->modlen); const size_t s = ccn_sizeof(v->modlen); unsigned char H[di->output_size]; cc_unit exponent[n]; cc_unit modulus[n]; ccrsa_pub_ctx_decl(ccn_sizeof(v->modlen), key); ccrsa_ctx_n(key) = n; ccn_seti(n, exponent, v->exp); ccn_read_uint(n, modulus, s, v->mod); ccrsa_init_pub(key, modulus, exponent); ccdigest(di, v->msglen, v->msg, H); rc=ccrsa_verify_pkcs1v15(key, di->oid.oid, di->output_size, H, v->siglen, v->sig, &ok); return ((rc==0) && ((ok && v->valid) || (!ok && !v->valid)))?0:1; }
int ccrsa_decrypt_eme_pkcs1v15(ccrsa_full_ctx_t key, size_t *r_size, uint8_t *r, size_t s_size, uint8_t *s) { size_t m_size = ccrsa_block_size(key); cc_size n=ccrsa_ctx_n(key); cc_unit tmp[n]; int err; if(*r_size<m_size) return CCRSA_INVALID_INPUT; *r_size=m_size; if(ccn_read_uint(n, tmp, s_size, s)) return CCRSA_INVALID_INPUT; // RSA decryption if ((err = ccrsa_priv_crypt(ccrsa_ctx_private(key), tmp, tmp)) == 0) { // Padding decoding err = ccrsa_eme_pkcs1v15_decode(r_size, r, m_size, tmp); } return err; }
static OSStatus SecECPrivateKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { ccec_full_ctx_t fullkey; fullkey.hdr = key->key; OSStatus err = errSecParam; switch (encoding) { case kSecKeyEncodingPkcs1: { /* TODO: DER import size (and thus cp), pub.x, pub.y and k. */ //err = ecc_import(keyData, keyDataLength, fullkey); /* DER != PKCS#1, but we'll go along with it */ ccoid_t oid; size_t n; ccec_const_cp_t cp; require_noerr(ccec_der_import_priv_keytype(keyDataLength, keyData, &oid, &n), abort); cp = ccec_cp_for_oid(oid); if (cp.zp == NULL) { cp = ccec_curve_for_length_lookup(n * 8 /* bytes -> bits */, ccec_cp_192(), ccec_cp_224(), ccec_cp_256(), ccec_cp_384(), ccec_cp_521(), NULL); } require_action(cp.zp != NULL, abort, err = errSecDecode); ccec_ctx_init(cp, fullkey); require_noerr(ccec_der_import_priv(cp, keyDataLength, keyData, fullkey), abort); err = errSecSuccess; break; } case kSecKeyEncodingBytes: { ccec_const_cp_t cp = getCPForPrivateSize(keyDataLength); require(cp.zp != NULL, abort); ccec_ctx_init(cp, fullkey); size_t pubSize = ccec_export_pub_size(fullkey); require(pubSize < (size_t) keyDataLength, abort); require_noerr_action(ccec_import_pub(cp, pubSize, keyData, fullkey), abort, err = errSecDecode); keyData += pubSize; keyDataLength -= pubSize; cc_unit *k = ccec_ctx_k(fullkey); require_noerr_action(ccn_read_uint(ccec_ctx_n(fullkey), k, keyDataLength, keyData), abort, err = errSecDecode); err = errSecSuccess; break; } case kSecGenerateKey: { CFDictionaryRef parameters = (CFDictionaryRef) keyData; CFTypeRef ksize = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits); CFIndex keyLengthInBits = getIntValue(ksize); ccec_const_cp_t cp = ccec_get_cp(keyLengthInBits); if (!cp.zp) { secwarning("Invalid or missing key size in: %@", parameters); return errSecKeySizeNotAllowed; } if (!ccec_generate_key(cp, ccrng_seckey, fullkey)) err = errSecSuccess; break; } default: break; } abort: return err; }
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; }
CCCryptorStatus CCRSACryptorCreatePairFromData(uint32_t e, uint8_t *xp1, size_t xp1Length, uint8_t *xp2, size_t xp2Length, uint8_t *xp, size_t xpLength, uint8_t *xq1, size_t xq1Length, uint8_t *xq2, size_t xq2Length, uint8_t *xq, size_t xqLength, CCRSACryptorRef *publicKey, CCRSACryptorRef *privateKey, uint8_t *retp, size_t *retpLength, uint8_t *retq, size_t *retqLength, uint8_t *retm, size_t *retmLength, uint8_t *retd, size_t *retdLength) { CCCryptorStatus retval; CCRSACryptor *privateCryptor = NULL; CCRSACryptor *publicCryptor = NULL; cc_unit x_p1[ccn_nof_size(xp1Length)]; cc_unit x_p2[ccn_nof_size(xp2Length)]; cc_unit x_p[ccn_nof_size(xpLength)]; cc_unit x_q1[ccn_nof_size(xq1Length)]; cc_unit x_q2[ccn_nof_size(xq2Length)]; cc_unit x_q[ccn_nof_size(xqLength)]; cc_unit e_value[1]; size_t nbits = xpLength * 8 + xqLength * 8; // or we'll add this as a parameter. This appears to be correct for FIPS cc_size n = ccn_nof(nbits); cc_unit p[n], q[n], m[n], d[n]; cc_size np, nq, nm, nd; np = nq = nm = nd = n; CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n"); e_value[0] = (cc_unit) e; __Require_Action((privateCryptor = ccMallocRSACryptor(nbits, ccRSAKeyPrivate)) != NULL, errOut, retval = kCCMemoryFailure); __Require_Action(ccn_read_uint(ccn_nof_size(xp1Length), x_p1, xp1Length, xp1) == 0, errOut, retval = kCCParamError); __Require_Action(ccn_read_uint(ccn_nof_size(xp2Length), x_p2, xp2Length, xp2)== 0, errOut, retval = kCCParamError); __Require_Action(ccn_read_uint(ccn_nof_size(xpLength), x_p, xpLength, xp) == 0, errOut, retval = kCCParamError); __Require_Action(ccn_read_uint(ccn_nof_size(xq1Length), x_q1, xq1Length, xq1) == 0, errOut, retval = kCCParamError); __Require_Action(ccn_read_uint(ccn_nof_size(xq2Length), x_q2, xq2Length, xq2) == 0, errOut, retval = kCCParamError); __Require_Action(ccn_read_uint(ccn_nof_size(xqLength), x_q, xqLength, xq) == 0, errOut, retval = kCCParamError); __Require_Action(ccrsa_make_931_key(nbits, 1, e_value, ccn_nof_size(xp1Length), x_p1, ccn_nof_size(xp2Length), x_p2, ccn_nof_size(xpLength), x_p, ccn_nof_size(xq1Length), x_q1, ccn_nof_size(xq2Length), x_q2, ccn_nof_size(xqLength), x_q, privateCryptor->fk, &np, p, &nq, q, &nm, m, &nd, d) == 0, errOut, retval = kCCDecodeError); privateCryptor->keyType = ccRSAKeyPrivate; __Require_Action((publicCryptor = CCRSACryptorGetPublicKeyFromPrivateKey(privateCryptor)) != NULL, errOut, retval = kCCMemoryFailure); *publicKey = publicCryptor; *privateKey = privateCryptor; ccn_write_arg(np, p, retp, retpLength); ccn_write_arg(nq, q, retq, retqLength); ccn_write_arg(nm, m, retm, retmLength); ccn_write_arg(nd, d, retd, retdLength); return kCCSuccess; errOut: if(privateCryptor) ccRSACryptorClear(privateCryptor); if(publicCryptor) ccRSACryptorClear(publicCryptor); // CLEAR the bits *publicKey = *privateKey = NULL; return retval; }
OSStatus SecDHCreateFromParameters(const uint8_t *params, size_t params_len, SecDHContext *pdh) { // We support DomainParameters as specified in PKCS#3 // (http://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-3-diffie-hellman-key-agreement-standar.htm) // DHParameter ::= SEQUENCE { // prime INTEGER, -- p // base INTEGER, -- g // privateValueLength INTEGER OPTIONAL } DERReturn drtn; DERItem paramItem = {(DERByte *)params, params_len}; DER_DHParams decodedParams; uint32_t l = 0; drtn = DERParseSequence(¶mItem, DER_NumDHParamsItemSpecs, DER_DHParamsItemSpecs, &decodedParams, sizeof(decodedParams)); if(drtn) return drtn; if (decodedParams.l.length > 0) { drtn = DERParseInteger(&decodedParams.l, &l); if(drtn) return drtn; } cc_size n = ccn_nof_size(decodedParams.p.length); cc_size p_len = ccn_sizeof_n(n); size_t context_size = ccdh_gp_size(p_len)+ccdh_full_ctx_size(p_len); void *context = malloc(context_size); if(context==NULL) return errSecAllocate; bzero(context, context_size); ccdh_gp_t gp; gp.gp = context; CCDH_GP_N(gp) = n; CCDH_GP_L(gp) = l; if(ccn_read_uint(n, CCDH_GP_PRIME(gp), decodedParams.p.length, decodedParams.p.data)) goto errOut; if(decodedParams.recip.length) { if(ccn_read_uint(n+1, CCDH_GP_RECIP(gp), decodedParams.recip.length, decodedParams.recip.data)) goto errOut; CCZP_MOD_PRIME(gp.zp) = cczp_mod; } else { cczp_init(gp.zp); }; if(ccn_read_uint(n, CCDH_GP_G(gp), decodedParams.g.length, decodedParams.g.data)) goto errOut; *pdh = (SecDHContext) context; return errSecSuccess; errOut: SecDHDestroy(context); *pdh = NULL; return errSecInvalidKey; }
static OSStatus SecRSAPrivateKeyRawDecrypt(SecKeyRef key, SecPadding padding, const uint8_t *cipherText, size_t cipherTextLen, uint8_t *plainText, size_t *plainTextLen) { OSStatus result = errSSLCrypto; 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 recoveredData[ccn_sizeof_n(ccrsa_ctx_n(fullkey))]; ccn_read_uint(ccrsa_ctx_n(fullkey), s, cipherTextLen, cipherText); ccrsa_priv_crypt(ccrsa_ctx_private(fullkey), s, s); const uint8_t* sBytes = (uint8_t*) s; const uint8_t* sEnd = (uint8_t*) (s + ccrsa_ctx_n(fullkey)); require(plainTextLen, errOut); switch (padding) { case kSecPaddingNone: ccn_swap(ccrsa_ctx_n(fullkey), s); // Skip Zeros since our contract is to do so. while (sBytes < sEnd && *sBytes == 0x00) ++sBytes; break; case kSecPaddingPKCS1: { ccn_swap(ccrsa_ctx_n(fullkey), s); // Verify and skip PKCS1 padding: // // 0x00, 0x01 (RSA_PKCS1_PAD_ENCRYPT), 0xFF .. 0x00, signedData // size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(fullkey)) - m_size; while (prefix_zeros--) require_quiet(*sBytes++ == 0x00, errOut); require_quiet(*sBytes++ == 0x00, errOut); require_quiet(*sBytes++ == RSA_PKCS1_PAD_ENCRYPT, errOut); while (*sBytes != 0x00) { require_quiet(++sBytes < sEnd, errOut); } // Required to have at least 8 non-zeros require_quiet((sBytes - (uint8_t*)s) - 2 >= 8, errOut); require_quiet(*sBytes == 0x00, errOut); require_quiet(++sBytes < sEnd, errOut); break; } case kSecPaddingOAEP: { size_t length = sizeof(recoveredData); require_noerr_quiet(ccrsa_oaep_decode(ccsha1_di(), ccn_write_uint_size(ccrsa_ctx_n(fullkey),ccrsa_ctx_m(fullkey)), s, &length, recoveredData), errOut); sBytes = recoveredData; sEnd = recoveredData + length; break; } default: goto errOut; } require((sEnd - sBytes) <= (ptrdiff_t)*plainTextLen, errOut); *plainTextLen = sEnd - sBytes; memcpy(plainText, sBytes, *plainTextLen); result = errSecSuccess; errOut: bzero(recoveredData, sizeof(recoveredData)); ccn_zero(ccrsa_ctx_n(fullkey), s); return result; }
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; }
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; }
static OSStatus SecRSAPublicKeyRawDecrypt(SecKeyRef key, SecPadding padding, const uint8_t *cipherText, size_t cipherTextLen, uint8_t *plainText, size_t *plainTextLen) { OSStatus result = errSSLCrypto; ccrsa_pub_ctx_t pubkey; pubkey.pub = key->key; cc_unit s[ccrsa_ctx_n(pubkey)]; require_action_quiet(cipherText != NULL, errOut, result = errSecParam); require_action_quiet(plainText != NULL, errOut, result = errSecParam); require_action_quiet(plainTextLen != NULL, errOut, result = errSecParam); ccn_read_uint(ccrsa_ctx_n(pubkey), s, cipherTextLen, cipherText); ccrsa_pub_crypt(pubkey, s, s); ccn_swap(ccrsa_ctx_n(pubkey), s); const uint8_t* sBytes = (uint8_t*) s; const uint8_t* sEnd = (uint8_t*) (s + ccrsa_ctx_n(pubkey)); switch (padding) { case kSecPaddingNone: // Skip leading zeros // We return the bytes for a number and // trim leading zeroes while (sBytes < sEnd && *sBytes == 0x00) ++sBytes; break; case kSecPaddingPKCS1: { // Verify and skip PKCS1 padding: // // 0x00, 0x01 (RSA_PKCS1_PAD_ENCRYPT), 0xFF .. 0x00, signedData // size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(pubkey)) - m_size; while (prefix_zeros--) require_quiet(*sBytes++ == 0x00, errOut); require_quiet(*sBytes++ == 0x00, errOut); require_quiet(*sBytes++ == RSA_PKCS1_PAD_ENCRYPT, errOut); while (*sBytes != 0x00) { require_quiet(++sBytes < sEnd, errOut); } // Required to have at least 8 0xFFs require_quiet((sBytes - (uint8_t*)s) - 2 >= 8, errOut); require_quiet(*sBytes == 0x00, errOut); require_quiet(++sBytes < sEnd, errOut); break; } case kSecPaddingOAEP: result = errSecParam; default: goto errOut; } // Return the rest. require_action((sEnd - sBytes) <= (ptrdiff_t)*plainTextLen, errOut, result = errSecParam); *plainTextLen = sEnd - sBytes; memcpy(plainText, sBytes, *plainTextLen); result = errSecSuccess; errOut: ccn_zero(ccrsa_ctx_n(pubkey), 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; }
static OSStatus SecRSAPublicKeyRawVerify(SecKeyRef key, SecPadding padding, const uint8_t *signedData, size_t signedDataLen, const uint8_t *sig, size_t sigLen) { OSStatus result = errSSLCrypto; ccrsa_pub_ctx_t pubkey; pubkey.pub = key->key; cc_unit s[ccrsa_ctx_n(pubkey)]; ccn_read_uint(ccrsa_ctx_n(pubkey), s, sigLen, sig); ccrsa_pub_crypt(pubkey, s, s); ccn_swap(ccrsa_ctx_n(pubkey), s); const uint8_t* sBytes = (uint8_t*) s; const uint8_t* sEnd = (uint8_t*) (s + ccrsa_ctx_n(pubkey)); switch (padding) { case kSecPaddingNone: // Skip leading zeros as long as s is bigger than signedData. while (((ptrdiff_t)signedDataLen < (sEnd - sBytes)) && (*sBytes == 0)) ++sBytes; break; case kSecPaddingPKCS1: { // Verify and skip PKCS1 padding: // // 0x00, 0x01 (RSA_PKCS1_PAD_SIGN), 0xFF .. 0x00, signedData // size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(pubkey)) - m_size; while (prefix_zeros--) require_quiet(*sBytes++ == 0x00, errOut); require_quiet(*sBytes++ == 0x00, errOut); require_quiet(*sBytes++ == RSA_PKCS1_PAD_SIGN, errOut); while (*sBytes == 0xFF) { require_quiet(++sBytes < sEnd, errOut); } // Required to have at least 8 0xFFs require_quiet((sBytes - (uint8_t*)s) - 2 >= 8, errOut); require_quiet(*sBytes == 0x00, errOut); require_quiet(++sBytes < sEnd, errOut); break; } case kSecPaddingOAEP: result = errSecParam; goto errOut; default: result = errSecUnimplemented; goto errOut; } // Compare the rest. require_quiet((sEnd - sBytes) == (ptrdiff_t)signedDataLen, errOut); require_quiet(memcmp(sBytes, signedData, signedDataLen) == 0, errOut); result = errSecSuccess; errOut: cc_zero(ccrsa_ctx_n(pubkey), s); return result; }
static int RSA_POST() { int result = -1; uint32_t uintEValue = 3; // xp1 = 1384167f9844865eae22cb3672 unsigned char* xp1Data = (unsigned char*)"\x13\x84\x16\x7f\x98\x44\x86\x5e\xae\x22\xcb\x36\x72"; size_t xp1DataSize = 13; // xp2 = 1a085b0b737f842a8a1f32b662 unsigned char* xp2Data = (unsigned char*)"\x1a\x08\x5b\x0b\x73\x7f\x84\x2a\x8a\x1f\x32\xb6\x62"; size_t xp2DataSize = 13; // Xp = beef5ad133e9a3955097c8d8b03bd50662b5f82b8e9c3eab5c8d9d3311c337ef7ce8ddfe902bd2235293d2bdf69353f944de0b46417cb2090c1e099206af1b4 unsigned char* xpData = (unsigned char*)"\xbe\xef\x5a\xd1\x33\xe9\xa3\x95\x50\x97\xc8\xd8\xb0\x3b\xd5\x06\x62\xb5\xf8\x2b\x8e\x9c\x3e\xab\x5c\x8d\x9d\x33\x11\xc3\x37\xef\x7c\xe8\xdd\xfe\x90\x2b\xd2\x23\x52\x93\xd2\xbd\xf6\x93\x53\xf9\x44\xde\x0b\x46\x41\x7c\xb2\x09\x0c\x1e\x09\x92\x06\xaf\x1b\x04"; size_t xpDataSize = 64; // xq1 = 17fa0d7d2189c759b0b8eb1d18 unsigned char* xq1Data = (unsigned char*)"\x17\xfa\x0d\x7d\x21\x89\xc7\x59\xb0\xb8\xeb\x1d\x18"; size_t xq1DataSize = 13; // xq2 = 17c8e735fb8d58e13a412ae214 unsigned char* xq2Data = (unsigned char*)"\x17\xc8\xe7\x35\xfb\x8d\x58\xe1\x3a\x41\x2a\xe2\x14"; size_t xq2DataSize = 13; // Xq = f2d7b992fb914cd677876bb3702b1441716ebd2b447c3a0500a6e0e0449feb1cbdec1d7eee96a88230224ef3f7c2c7b858cd63f1c86df0432798de6ffd41a12a unsigned char* xqData = (unsigned char*)"\xf2\xd7\xb9\x92\xfb\x91\x4c\xd6\x77\x87\x6b\xb3\x70\x2b\x14\x41\x71\x6e\xbd\x2b\x44\x7c\x3a\x05\x00\xa6\xe0\xe0\x44\x9f\xeb\x1c\xbd\xec\x1d\x7e\xee\x96\xa8\x82\x30\x22\x4e\xf3\xf7\xc2\xc7\xb8\x58\xcd\x63\xf1\xc8\x6d\xf0\x43\x27\x98\xde\x6f\xfd\x41\xa1\x2a"; size_t xqDataSize = 64; cc_unit x_p1[ccn_nof_size(xp1DataSize)]; cc_unit x_p2[ccn_nof_size(xp2DataSize)]; cc_unit x_p[ccn_nof_size(xpDataSize)]; cc_unit x_q1[ccn_nof_size(xq1DataSize)]; cc_unit x_q2[ccn_nof_size(xq2DataSize)]; cc_unit x_q[ccn_nof_size(xqDataSize)]; cc_unit e_value[1]; size_t nbits = xpDataSize * 8 + xqDataSize * 8; // or we'll add this as a parameter. This appears to be correct for FIPS cc_size n = ccn_nof(nbits); e_value[0] = (cc_unit)uintEValue; if (0 != ccn_read_uint(ccn_nof_size(xp1DataSize), x_p1, xp1DataSize, xp1Data)) { return result; } if (0 != ccn_read_uint(ccn_nof_size(xp2DataSize), x_p2, xp2DataSize, xp2Data)) { return result; } if (0 != ccn_read_uint(ccn_nof_size(xpDataSize), x_p, xpDataSize, xpData)) { return result; } if (0 != ccn_read_uint(ccn_nof_size(xq1DataSize), x_q1, xq1DataSize, xq1Data)) { return result; } if (0 != ccn_read_uint(ccn_nof_size(xq2DataSize), x_q2, xq2DataSize, xq2Data)) { return result; } if (0 != ccn_read_uint(ccn_nof_size(xqDataSize), x_q, xqDataSize, xqData)) { return result; }; cc_size np = n; cc_size nq = n; cc_size nm = n; cc_size nd = n; cc_unit p[n]; cc_unit q[n]; cc_unit m[n]; cc_unit d[n]; ccrsa_full_ctx_decl(ccn_sizeof_n(n), full_key); ccrsa_ctx_n(full_key) = n; if (0 != ccrsa_make_931_key(nbits, 1, e_value, ccn_nof_size(xp1DataSize), x_p1, ccn_nof_size(xp2DataSize), x_p2, ccn_nof_size(xpDataSize), x_p, ccn_nof_size(xq1DataSize), x_q1, ccn_nof_size(xq2DataSize), x_q2, ccn_nof_size(xqDataSize), x_q, full_key, &np, p, &nq, q, &nm, m, &nd, d)) { ccrsa_full_ctx_clear(ccn_sizeof(nbits), full_key); return result; } ccrsa_full_ctx *fk = full_key; ccrsa_pub_ctx_t pub_key = ccrsa_ctx_public(fk); unsigned char fake_digest[20]; memcpy(fake_digest, "ABCEDFGHIJKLMNOPRSTU", 20); uint8_t sig[(nbits+7)/8]; size_t siglen=sizeof(sig); if (0 != ccrsa_sign_pkcs1v15(full_key, ccoid_sha1, CCSHA1_OUTPUT_SIZE, fake_digest, &siglen, sig)) { ccrsa_full_ctx_clear(ccn_sizeof(nbits), full_key); return result; } bool ok; if (0 != ccrsa_verify_pkcs1v15(pub_key, ccoid_sha1, CCSHA1_OUTPUT_SIZE, fake_digest, siglen, sig, &ok) || !ok) { ccrsa_full_ctx_clear(ccn_sizeof(nbits), full_key); return result; } return 0; }