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 CFDataRef SecRSAPublicKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_pub_ctx_t pubkey) { size_t m_size = ccn_write_int_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); size_t e_size = ccn_write_int_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey)); const size_t seq_size = DERLengthOfItem(ASN1_INTEGER, m_size) + DERLengthOfItem(ASN1_INTEGER, e_size); const size_t result_size = DERLengthOfItem(ASN1_SEQUENCE, seq_size); CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size); if (pkcs1 == NULL) return NULL; CFDataSetLength(pkcs1, result_size); uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1); *bytes++ = ASN1_CONSTR_SEQUENCE; DERSize itemLength = 4; DEREncodeLength(seq_size, bytes, &itemLength); bytes += itemLength; ccasn_encode_int(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, &bytes); ccasn_encode_int(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey), e_size, &bytes); return pkcs1; }
/* 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; }
/* 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; }
void ccrsa_dump_public_key(ccrsa_pub_ctx_t key) { ccn_cprint(ccrsa_ctx_n(key), "uint8_t m[] = ", ccrsa_ctx_m(key)); ccn_cprint(ccrsa_ctx_n(key) + 1, "uint8_t rm[] = ", cczp_recip(ccrsa_ctx_zm(key))); ccn_cprint(ccrsa_ctx_n(key), "uint8_t e[] = ", ccrsa_ctx_e(key)); printf("--\n"); }
static OSStatus SecRSAPublicKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { OSStatus result = errSecParam; ccrsa_pub_ctx_t pubkey; pubkey.pub = key->key; // Set maximum size for parsers ccrsa_ctx_n(pubkey) = ccn_nof(kMaximumRSAKeyBits); switch (encoding) { case kSecKeyEncodingBytes: // Octets is PKCS1 case kSecKeyEncodingPkcs1: result = ccrsa_pub_decode(pubkey, keyDataLength, keyData); break; case kSecKeyEncodingApplePkcs1: result = ccrsa_pub_decode_apple(pubkey, keyDataLength, keyData); break; case kSecKeyEncodingRSAPublicParams: { SecRSAPublicKeyParams *params = (SecRSAPublicKeyParams *)keyData; require_noerr(ccrsa_pub_init(pubkey, params->modulusLength, params->modulus, params->exponentLength, params->exponent), errOut); result = errSecSuccess; break; } case kSecExtractPublicFromPrivate: { ccrsa_full_ctx_t fullKey; fullKey.full = (ccrsa_full_ctx*) keyData; cc_size fullKeyN = ccrsa_ctx_n(fullKey); require(fullKeyN <= ccrsa_ctx_n(pubkey), errOut); memcpy(pubkey.pub, ccrsa_ctx_public(fullKey).pub, ccrsa_pub_ctx_size(ccn_sizeof_n(fullKeyN))); result = errSecSuccess; break; } default: break; } errOut: return result; }
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; }
// // 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); }
CFDataRef SecKeyCopyExponent(SecKeyRef key) { ccrsa_pub_ctx_t pubkey; pubkey.pub = key->key; size_t e_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey)); CFAllocatorRef allocator = CFGetAllocator(key); CFMutableDataRef exponentData = CFDataCreateMutable(allocator, e_size); if (exponentData == NULL) return NULL; CFDataSetLength(exponentData, e_size); ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), e_size, CFDataGetMutableBytePtr(exponentData)); return exponentData; }
CFDataRef SecKeyCopyModulus(SecKeyRef key) { ccrsa_pub_ctx_t pubkey; pubkey.pub = key->key; size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); CFAllocatorRef allocator = CFGetAllocator(key); CFMutableDataRef modulusData = CFDataCreateMutable(allocator, m_size); if (modulusData == NULL) return NULL; CFDataSetLength(modulusData, m_size); ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, CFDataGetMutableBytePtr(modulusData)); return modulusData; }
static CCRSACryptor * ccMallocRSACryptor(size_t nbits, CCRSAKeyType keyType) { CCRSACryptor *retval; cc_size n = ccn_nof(nbits); if((retval = CC_XMALLOC(sizeof(CCRSACryptor))) == NULL) return NULL; retval->keySize = nbits; ccrsa_ctx_n(retval->fk) = n; return retval; }
CCCryptorStatus CCRSACryptorImport(const void *keyPackage, size_t keyPackageLen, CCRSACryptorRef *key) { CCRSACryptor *cryptor = NULL; CCCryptorStatus retval; CCRSAKeyType keyToMake; cc_size keyN; CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n"); if(!keyPackage || !key) return kCCParamError; if((keyN = ccrsa_import_priv_n(keyPackageLen, keyPackage)) != 0) keyToMake = ccRSAKeyPrivate; else if((keyN = ccrsa_import_pub_n(keyPackageLen, keyPackage)) != 0) keyToMake = ccRSAKeyPublic; else return kCCDecodeError; __Require_Action((cryptor = ccMallocRSACryptor(kCCMaximumRSAKeyBits, keyToMake)) != NULL, errOut, retval = kCCMemoryFailure); switch(keyToMake) { case ccRSAKeyPublic: ccrsa_ctx_n(ccrsa_ctx_public(cryptor->fk)) = keyN; if(ccrsa_import_pub(ccrsa_ctx_public(cryptor->fk), keyPackageLen, keyPackage)) { ccRSACryptorClear(cryptor); return kCCDecodeError; } break; case ccRSAKeyPrivate: ccrsa_ctx_n(cryptor->fk) = keyN; if(ccrsa_import_priv(cryptor->fk, keyPackageLen, keyPackage)) { ccRSACryptorClear(cryptor); return kCCDecodeError; } break; } cryptor->keyType = keyToMake; *key = cryptor; cryptor->keySize = ccRSAkeysize(cryptor); return kCCSuccess; errOut: if(cryptor) ccRSACryptorClear(cryptor); *key = NULL; return retval; }
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; }
void ccrsa_dump_full_key(ccrsa_full_ctx_t key) { ccn_cprint(ccrsa_ctx_n(key), "uint8_t m[] = ", ccrsa_ctx_m(key)); ccn_cprint(ccrsa_ctx_n(key) + 1, "uint8_t rm[] = ", cczp_recip(ccrsa_ctx_zm(key))); ccn_cprint(ccrsa_ctx_n(key), "uint8_t e[] = ", ccrsa_ctx_e(key)); ccn_cprint(ccrsa_ctx_n(key), "uint8_t d[] = ", ccrsa_ctx_d(key)); printf("cc_size np = %lu;\n", cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key)))); ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))), "uint8_t p[] = ", cczp_prime(ccrsa_ctx_private_zp(ccrsa_ctx_private(key)))); ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))) + 1, "uint8_t rp[] = ", cczp_recip(ccrsa_ctx_private_zp(ccrsa_ctx_private(key)))); printf("cc_size nq = %lu;\n", cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key)))); ccn_cprint(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))), "uint8_t q[] = ", cczp_prime(ccrsa_ctx_private_zq(ccrsa_ctx_private(key)))); ccn_cprint(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))) + 1, "uint8_t rq[] = ", cczp_recip(ccrsa_ctx_private_zq(ccrsa_ctx_private(key)))); ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))), "uint8_t dp[] = ", ccrsa_ctx_private_dp(ccrsa_ctx_private(key))); ccn_cprint(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))), "uint8_t dq[] = ", ccrsa_ctx_private_dq(ccrsa_ctx_private(key))); ccn_cprint(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))), "uint8_t qinv[] = ", ccrsa_ctx_private_qinv(ccrsa_ctx_private(key))); printf("--\n"); }
size_t ccder_encode_rsa_priv_size(const ccrsa_full_ctx_t key) { ccrsa_priv_ctx_t privk = ccrsa_ctx_private(key); cc_size n = ccrsa_ctx_n(key); cc_unit version_0[ccn_nof(1)] = {0x00}; return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, ccder_sizeof_integer(ccn_nof(1), version_0) + ccder_sizeof_integer(n, ccrsa_ctx_m(key)) + ccder_sizeof_integer(n, ccrsa_ctx_e(key)) + ccder_sizeof_integer(n, ccrsa_ctx_d(key)) + ccder_sizeof_integer(cczp_n(ccrsa_ctx_private_zp(privk)), cczp_prime(ccrsa_ctx_private_zp(privk))) + ccder_sizeof_integer(cczp_n(ccrsa_ctx_private_zq(privk)), cczp_prime(ccrsa_ctx_private_zq(privk))) + ccder_sizeof_integer(cczp_n(ccrsa_ctx_private_zp(privk)), ccrsa_ctx_private_dp(privk)) + ccder_sizeof_integer(cczp_n(ccrsa_ctx_private_zq(privk)), ccrsa_ctx_private_dq(privk)) + ccder_sizeof_integer(cczp_n(ccrsa_ctx_private_zp(privk)), ccrsa_ctx_private_qinv(privk)) ); }
static OSStatus SecRSAPrivateKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { OSStatus result = errSecParam; ccrsa_full_ctx_t fullkey; fullkey.full = key->key; // Set maximum size for parsers ccrsa_ctx_n(fullkey) = ccn_nof(kMaximumRSAKeyBits); switch (encoding) { case kSecKeyEncodingBytes: // Octets is PKCS1 case kSecKeyEncodingPkcs1: result = ccrsa_full_decode(fullkey, keyDataLength, keyData); break; case kSecGenerateKey: { CFDictionaryRef parameters = (CFDictionaryRef) keyData; CFTypeRef ksize = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits); CFIndex keyLengthInBits = getIntValue(ksize); if (keyLengthInBits < 256 || keyLengthInBits > kMaximumRSAKeyBits) { secwarning("Invalid or missing key size in: %@", parameters); return errSecKeySizeNotAllowed; } /* TODO: Add support for kSecPublicExponent parameter. */ static uint8_t e[] = { 0x01, 0x00, 0x01 }; // Default is 65537 if (!ccrsa_generate_key(keyLengthInBits, fullkey.full, sizeof(e), e, ccrng_seckey)) result = errSecSuccess; break; } default: break; } return result; }
int ccrsa_get_fullkey_components(const ccrsa_full_ctx_t key, uint8_t *modulus, size_t *modulusLength, uint8_t *exponent, size_t *exponentLength, uint8_t *p, size_t *pLength, uint8_t *q, size_t *qLength) { cc_size n = ccrsa_ctx_n(key); if(ccCoreZP2pointerAndData(cczp_n(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))), cczp_prime(ccrsa_ctx_private_zp(ccrsa_ctx_private(key))), p, pLength )) return -1; if(ccCoreZP2pointerAndData(cczp_n(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))), cczp_prime(ccrsa_ctx_private_zq(ccrsa_ctx_private(key))), q, qLength )) return -1; if(ccCoreZP2pointerAndData(n, ccrsa_ctx_m(key), modulus, modulusLength )) return -1; if(ccCoreZP2pointerAndData(n, ccrsa_ctx_d(key), exponent, exponentLength )) return -1; return 0; }
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 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 CFDataRef SecRSAPrivateKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_full_ctx_t fullkey) { ccrsa_priv_ctx_t privkey = ccrsa_ctx_private(fullkey); const cc_size np = cczp_n(ccrsa_ctx_private_zp(privkey)); const cc_size nq = cczp_n(ccrsa_ctx_private_zq(privkey)); size_t m_size = ccn_write_int_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); size_t e_size = ccn_write_int_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_e(fullkey)); size_t d_size = ccn_write_int_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_d(fullkey)); size_t p_size = ccn_write_int_size(np, cczp_prime(ccrsa_ctx_private_zp(privkey))); size_t q_size = ccn_write_int_size(nq, cczp_prime(ccrsa_ctx_private_zq(privkey))); size_t dp_size = ccn_write_int_size(np, ccrsa_ctx_private_dp(privkey)); size_t dq_size = ccn_write_int_size(nq, ccrsa_ctx_private_dq(privkey)); size_t qinv_size = ccn_write_int_size(np, ccrsa_ctx_private_qinv(privkey)); const size_t seq_size = 3 + DERLengthOfItem(ASN1_INTEGER, m_size) + DERLengthOfItem(ASN1_INTEGER, e_size) + DERLengthOfItem(ASN1_INTEGER, d_size) + DERLengthOfItem(ASN1_INTEGER, p_size) + DERLengthOfItem(ASN1_INTEGER, q_size) + DERLengthOfItem(ASN1_INTEGER, dp_size) + DERLengthOfItem(ASN1_INTEGER, dq_size) + DERLengthOfItem(ASN1_INTEGER, qinv_size); const size_t result_size = DERLengthOfItem(ASN1_SEQUENCE, seq_size); CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size); if (pkcs1 == NULL) return NULL; CFDataSetLength(pkcs1, result_size); uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1); *bytes++ = ASN1_CONSTR_SEQUENCE; DERSize itemLength = 4; DEREncodeLength(seq_size, bytes, &itemLength); bytes += itemLength; *bytes++ = ASN1_INTEGER; *bytes++ = 0x01; *bytes++ = 0x00; ccasn_encode_int(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey), m_size, &bytes); ccasn_encode_int(ccrsa_ctx_n(fullkey), ccrsa_ctx_e(fullkey), e_size, &bytes); ccasn_encode_int(ccrsa_ctx_n(fullkey), ccrsa_ctx_d(fullkey), d_size, &bytes); ccasn_encode_int(np, cczp_prime(ccrsa_ctx_private_zp(privkey)), p_size, &bytes); ccasn_encode_int(nq, cczp_prime(ccrsa_ctx_private_zq(privkey)), q_size, &bytes); ccasn_encode_int(np, ccrsa_ctx_private_dp(privkey), dp_size, &bytes); ccasn_encode_int(nq, ccrsa_ctx_private_dq(privkey), dq_size, &bytes); ccasn_encode_int(np, ccrsa_ctx_private_qinv(privkey), qinv_size, &bytes); return pkcs1; }
static size_t SecRSAPrivateKeyBlockSize(SecKeyRef key) { ccrsa_full_ctx_t fullkey; fullkey.full = key->key; return ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); }
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; }
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 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; }
/* Private key static functions. */ static void SecRSAPrivateKeyDestroy(SecKeyRef key) { /* Zero out the public key */ ccrsa_full_ctx_t fullkey; fullkey.full = key->key; cc_zero(ccrsa_full_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(fullkey))), fullkey.full); }
static size_t SecRSAPublicKeyBlockSize(SecKeyRef key) { ccrsa_pub_ctx_t pubkey; pubkey.pub = key->key; return ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); }