/* new in 10.6 */
OSStatus
SecKeyDecrypt(
    SecKeyRef           key,                /* Private key */
	SecPadding          padding,			/* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
	const uint8_t       *cipherText,
	size_t              cipherTextLen,		/* length of cipherText */
	uint8_t             *plainText,	
	size_t              *plainTextLen)		/* IN/OUT */
{
	BEGIN_SECAPI

	SecPointer<KeyItem> keyItem(KeyItem::required(key));
	CSSM_DATA inData, outData;
	inData.Data = (uint8*) cipherText;
	inData.Length = cipherTextLen;
	outData.Data = plainText;
	outData.Length = *plainTextLen;
	
	const AccessCredentials* credentials = keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault);

	keyItem->Decrypt(padding, inData, credentials, outData);
	*plainTextLen = outData.Length;

	END_SECAPI
}
/* new in 10.6 */
OSStatus
SecKeyRawVerify(
    SecKeyRef           key,
	SecPadding          padding,
	const uint8_t       *signedData,
	size_t              signedDataLen,
	const uint8_t       *sig,
	size_t              sigLen)
{
	BEGIN_SECAPI

	Required(key);
	
	SecPointer<KeyItem> keyItem(KeyItem::required(key));
	CSSM_DATA dataInput;
	
	dataInput.Data = (uint8_t*) signedData;
	dataInput.Length = signedDataLen;
	
	CSSM_DATA signature;
	signature.Data = (uint8_t*) sig;
	signature.Length = sigLen;
	
	const AccessCredentials* credentials = keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, kSecCredentialTypeDefault);

	keyItem->RawVerify(padding, dataInput, credentials, signature);

	END_SECAPI
}
/* new in 10.6 */
OSStatus
SecKeyEncrypt(
    SecKeyRef           key,
	SecPadding          padding,
	const uint8_t		*plainText,
	size_t              plainTextLen,
	uint8_t             *cipherText,
	size_t              *cipherTextLen)
{
	BEGIN_SECAPI

	SecPointer<KeyItem> keyItem(KeyItem::required(key));
	CSSM_DATA inData, outData;
	inData.Data = (uint8*) plainText;
	inData.Length = plainTextLen;
	outData.Data = cipherText;
	outData.Length = *cipherTextLen;
	
	const AccessCredentials* credentials = keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault);

	keyItem->Encrypt(padding, inData, credentials, outData);
	*cipherTextLen = outData.Length;

	END_SECAPI
}
/* new in 10.6 */
OSStatus
SecKeyRawSign(
    SecKeyRef           key,
	SecPadding          padding,
	const uint8_t       *dataToSign,
	size_t              dataToSignLen,
	uint8_t             *sig,
	size_t              *sigLen)
{
	BEGIN_SECAPI

	Required(key);
	SecPointer<KeyItem> keyItem(KeyItem::required(key));
	CSSM_DATA dataInput;
	
	dataInput.Data = (uint8_t*) dataToSign;
	dataInput.Length = dataToSignLen;
	
	CSSM_DATA output;
	output.Data = sig;
	output.Length = *sigLen;
	
	const AccessCredentials* credentials = keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault);

	keyItem->RawSign(padding, dataInput, credentials, output);
	*sigLen = output.Length;

	END_SECAPI
}
OSStatus
SecKeyGetStrengthInBits(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER *algid, unsigned int *strength)
{
    BEGIN_SECAPI

	SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
	Required(strength) = keyItem->strengthInBits(algid);

	END_SECAPI
}
OSStatus
SecKeyGetAlgorithmID(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER **algid)
{
    BEGIN_SECAPI

	SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
	Required(algid) = &keyItem->algorithmIdentifier();

	END_SECAPI
}
OSStatus
SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle)
{
    BEGIN_SECAPI

	SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
	Required(cspHandle) = keyItem->csp()->handle();

	END_SECAPI
}
OSStatus
SecKeyGetCredentials(
	SecKeyRef keyRef,
	CSSM_ACL_AUTHORIZATION_TAG operation,
	SecCredentialType credentialType,
	const CSSM_ACCESS_CREDENTIALS **outCredentials)
{
	BEGIN_SECAPI

	SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
	Required(outCredentials) = keyItem->getCredentials(operation, credentialType);

	END_SECAPI
}
CFDataRef decodePrivateKeyHeader(SecKeychainRef keychain, const FVPrivateKeyHeader &inHeader)
{	
	// kSecKeyLabel is defined in libsecurity_keychain/lib/SecKey.h
	SecKeychainAttribute attrs[] =
	{
		{ 6 /* kSecKeyLabel */, inHeader.publicKeyHashSize, const_cast<uint8 *>(inHeader.publicKeyHash) }
	};
	SecKeychainAttributeList attrList =
	{
		sizeof(attrs) / sizeof(SecKeychainAttribute),
		attrs
	};
	CSSM_CSP_HANDLE cspHandle = 0;
	const CSSM_KEY *cssmKey = NULL;
    const CSSM_ACCESS_CREDENTIALS *accessCred = NULL;
    CSSM_CC_HANDLE cc = 0;
	
	SecKeychainSearchRef _searchRef;
	throwIfError(SecKeychainSearchCreateFromAttributes(keychain, (SecItemClass) CSSM_DL_DB_RECORD_PRIVATE_KEY, &attrList, &_searchRef));
	CFRef<SecKeychainSearchRef> searchRef(_searchRef);
	
	SecKeychainItemRef _item;
    if (SecKeychainSearchCopyNext(searchRef, &_item) != 0) {
		return NULL;  // XXX possibly should throw here?
    }
	
	CFRef<SecKeyRef> keyItem(reinterpret_cast<SecKeyRef>(_item));
	throwIfError(SecKeyGetCSPHandle(keyItem, &cspHandle));
	throwIfError(SecKeyGetCSSMKey(keyItem, &cssmKey));
    throwIfError(SecKeyGetCredentials(keyItem, CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeDefault, &accessCred));
    throwIfError(CSSM_CSP_CreateAsymmetricContext(cspHandle, cssmKey->KeyHeader.AlgorithmId, accessCred, cssmKey, CSSM_PADDING_PKCS1, &cc));
	CFDataRef result;
	
	try
	{		
		CssmMemoryFunctions memFuncs;
		throwIfError(CSSM_GetAPIMemoryFunctions(cspHandle, &memFuncs));
		CssmMemoryFunctionsAllocator allocator(memFuncs);
		
		const CssmData cipherBuf(const_cast<uint8 *>(inHeader.encryptedBlob), inHeader.encryptedBlobSize);
		CssmAutoData clearBuf(allocator);
		CssmAutoData remData(allocator);
		size_t bytesDecrypted;
		CSSM_RETURN crx = CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get());
		secinfo("FDERecovery", "decodePrivateKeyHeader: CSSM_DecryptData result: %d", crx);
		throwIfError(crx);
//		throwIfError(CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get()));
		clearBuf.length(bytesDecrypted);
//		rawKey.copy(clearBuf.get());
		result = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)clearBuf.get().data(), clearBuf.get().length());
//		result = parseKeyBlob(clearBuf.get());
	}
	catch(...)
	{
		CSSM_DeleteContext(cc);
		throw;
	}
	
	throwIfError(CSSM_DeleteContext(cc));
	
	return result;
}