EncryptTransform.cpp [plain text]
#include "EncryptTransform.h"
#include "SecEncryptTransform.h"
#include "EncryptTransformUtilities.h"
#include "Utilities.h"
#include "SecDigestTransform.h"
#include "Digest.h"
#include <Security/SecRandomP.h>
#include <Security/SecKey.h>
#include "SecMaskGenerationFunctionTransform.h"
static CFStringRef kEncryptTransformType = CFSTR("Encrypt Transform");
static CFStringRef kDecryptTransformType = CFSTR("Decrypt Transform");
static uint8 iv[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
static const CSSM_DATA gKeySalt = {16, iv};
dispatch_once_t EncryptDecryptBase::serializerSetUp;
dispatch_queue_t EncryptDecryptBase::serializerTransformStartingExecution;
EncryptDecryptBase::EncryptDecryptBase(CFStringRef type) :
Transform(type),
m_cssm_padding(CSSM_PADDING_NONE),
m_mode(CSSM_ALGMODE_CBCPadIV8),
m_cssm_key(NULL),
m_handle((CSSM_CC_HANDLE)0),
m_forEncryption(FALSE),
m_processedData(NULL),
m_accumulator(NULL)
{
m_forEncryption = CFEqual(type, kEncryptTransformType);
inputAH = transforms_assume(this->getAH(kSecTransformInputAttributeName, false, false));
}
void EncryptDecryptBase::Finalize()
{
if (m_handle != (CSSM_CC_HANDLE)0)
{
CSSM_CC_HANDLE tmp_handle = m_handle;
dispatch_async(mDispatchQueue, ^{
CSSM_DeleteContext(tmp_handle);
});
m_handle = ((CSSM_CC_HANDLE)0);
}
Transform::Finalize();
}
EncryptDecryptBase::~EncryptDecryptBase()
{
if (NULL != m_processedData)
{
CFRelease(m_processedData);
m_processedData = NULL;
}
if (NULL != m_accumulator)
{
CFRelease(m_accumulator);
m_accumulator = NULL;
}
}
bool EncryptDecryptBase::InitializeObject(SecKeyRef key, CFErrorRef *error)
{
SetAttributeNoCallback(kSecEncryptKey, key);
if (error)
{
*error = NULL;
}
return true;
}
CFErrorRef EncryptDecryptBase::SerializedTransformStartingExecution()
{
CFErrorRef result = NULL; SecKeyRef key = (SecKeyRef) GetAttribute(kSecEncryptKey);
if (NULL == key)
{
return CreateSecTransformErrorRef(kSecTransformErrorAttributeNotFound, "The attribute %@ was not found.", kSecEncryptKey);
}
OSStatus err = errSecSuccess;
err = SecKeyGetCSSMKey(key, (const CSSM_KEY **)&m_cssm_key);
if (errSecSuccess != err)
{
CFStringRef result = SecCopyErrorMessageString(err, NULL);
CFErrorRef retValue = CreateSecTransformErrorRef(err, "CDSA error (%@).", result);
CFRelease(result);
return retValue;
}
CSSM_CSP_HANDLE csp;
err = SecKeyGetCSPHandle(key, &csp);
if (errSecSuccess != err)
{
CFStringRef result = SecCopyErrorMessageString(err, NULL);
CFErrorRef retValue = CreateSecTransformErrorRef(err, "CDSA error (%@).", result);
CFRelease(result);
return retValue;
}
CSSM_ALGORITHMS keyAlg = m_cssm_key->KeyHeader.AlgorithmId;
m_cssm_padding = CSSM_PADDING_NONE;
CFStringRef paddingStr = (CFStringRef) GetAttribute(kSecPaddingKey);
CFStringRef modeStr = (CFStringRef) GetAttribute (kSecEncryptionMode);
CFDataRef ivData = (CFDataRef) GetAttribute(kSecIVKey);
Boolean hasPadding = (paddingStr != NULL);
Boolean hasMode = (modeStr != NULL);
Boolean hasIVData = (ivData != NULL);
Boolean isSymmetrical = (m_cssm_key->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY);
if (!hasPadding)
{
if (CSSM_ALGID_RSA == keyAlg || CSSM_ALGID_ECDSA == keyAlg)
{
m_cssm_padding = CSSM_PADDING_PKCS1;
}
else
{
m_cssm_padding = CSSM_PADDING_PKCS7;
}
m_oaep_padding = false;
}
else
{
if (CFStringCompare(kSecPaddingOAEPKey, paddingStr, kCFCompareAnchored)) {
m_oaep_padding = false;
m_cssm_padding = ConvertPaddingStringToEnum(paddingStr);
} else {
m_cssm_padding = CSSM_PADDING_NONE;
m_oaep_padding = true;
m_accumulator = CFDataCreateMutable(NULL, 0);
if (!m_accumulator) {
return GetNoMemoryErrorAndRetain();
}
}
}
if (!hasMode)
{
m_mode = (CSSM_PADDING_NONE == m_cssm_padding) ? CSSM_ALGMODE_CBC_IV8 : CSSM_ALGMODE_CBCPadIV8;
}
else
{
m_mode = ConvertEncryptModeStringToEnum(modeStr, (CSSM_PADDING_NONE != m_cssm_padding));
}
CSSM_RETURN crtn = CSSM_OK;
CSSM_ACCESS_CREDENTIALS creds;
CSSM_ACCESS_CREDENTIALS* credPtr = NULL;
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
err = SecKeyGetCredentials(key,
(m_forEncryption) ? CSSM_ACL_AUTHORIZATION_ENCRYPT : CSSM_ACL_AUTHORIZATION_DECRYPT,
kSecCredentialTypeDefault,
(const CSSM_ACCESS_CREDENTIALS **)&credPtr);
if (errSecSuccess != err)
{
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
credPtr = &creds;
}
if (isSymmetrical)
{
CSSM_DATA initVector;
if (hasIVData)
{
initVector.Length = CFDataGetLength(ivData);
initVector.Data = const_cast<uint8_t*>(CFDataGetBytePtr(ivData));
}
else
{
initVector.Length = gKeySalt.Length;
initVector.Data = (uint8 *)malloc(initVector.Length);
initVector.Data = gKeySalt.Data;
}
crtn = CSSM_CSP_CreateSymmetricContext(csp, keyAlg, m_mode, credPtr, m_cssm_key,
&initVector, m_cssm_padding, NULL, &m_handle);
if (crtn != CSSM_OK)
{
CFStringRef result = SecCopyErrorMessageString(crtn, NULL);
CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA error (%@).", result);
CFRelease(result);
return retValue;
}
}
else
{
crtn = CSSM_CSP_CreateAsymmetricContext(csp, keyAlg, credPtr, m_cssm_key, m_cssm_padding, &m_handle);
if (crtn != CSSM_OK)
{
CFStringRef result = SecCopyErrorMessageString(crtn, NULL);
CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA error (%@).", result);
CFRelease(result);
return retValue;
}
}
crtn = (m_forEncryption) ? CSSM_EncryptDataInit(m_handle) : CSSM_DecryptDataInit(m_handle);
if (crtn != CSSM_OK)
{
CFStringRef result = SecCopyErrorMessageString(crtn, NULL);
CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA encrypt/decrypt init error (%@).", result);
CFRelease(result);
return retValue;
}
return result;
}
CFErrorRef EncryptDecryptBase::TransformStartingExecution()
{
dispatch_once(&serializerSetUp, ^{
serializerTransformStartingExecution = dispatch_queue_create("com.apple.security.EncryptDecrypt.key-setup", NULL);
});
__block CFErrorRef result = NULL;
dispatch_sync(serializerTransformStartingExecution, ^{
result = SerializedTransformStartingExecution();
});
return result;
}
Boolean EncryptDecryptBase::TransformCanExecute()
{
SecKeyRef key = (SecKeyRef) GetAttribute(kSecEncryptKey);
return key != NULL;
}
void EncryptDecryptBase::SendCSSMError(CSSM_RETURN retCode)
{
CFStringRef errorString = SecCopyErrorMessageString(retCode, NULL);
CFErrorRef errorRef = CreateGenericErrorRef(kCFErrorDomainOSStatus, retCode, "%@", errorString);
CFRelease(errorString);
SendAttribute(kSecTransformOutputAttributeName, errorRef);
CFRelease(errorRef);
}
void xor_bytes(UInt8 *dst, const UInt8 *src1, const UInt8 *src2, CFIndex length);
void xor_bytes(UInt8 *dst, const UInt8 *src1, const UInt8 *src2, CFIndex length)
{
while (length--) {
*dst++ = *src1++ ^ *src2++;
}
}
extern "C" {
extern CFDataRef oaep_unpadding_via_c(CFDataRef encodedMessage);
}
CFDataRef EncryptDecryptBase::remove_oaep_padding(CFDataRef encodedMessage)
{
#if 1
return oaep_unpadding_via_c(encodedMessage);
#else
CFStringRef hashAlgo = NULL;
CFDataRef message = NULL, maskedSeed = NULL, maskedDB = NULL, seedMask = NULL, seed = NULL, dbMask = NULL;
CFDataRef pHash = NULL, pHashPrime = NULL;
CFDataRef EncodingParameters = NULL;
CFErrorRef error = NULL;
UInt8 *raw_seed = NULL, *raw_DB = NULL, *addr01 = NULL;
SecTransformRef mgf_maskedDB = NULL, mgf_dbMask = NULL, hash = NULL;
int hLen = -1;
const int extraPaddingLength = 1;
hashAlgo = (CFStringRef)this->GetAttribute(kSecOAEPMGF1DigestAlgorithmAttributeName);
if (hashAlgo == NULL) {
hashAlgo = kSecDigestSHA1;
}
hLen = Digest::LengthForType(hashAlgo);
if (CFDataGetLength(encodedMessage) < 2*hLen + 1) {
goto out;
}
maskedSeed = CFDataCreateWithBytesNoCopy(NULL, CFDataGetBytePtr(encodedMessage) +extraPaddingLength, hLen, kCFAllocatorNull);
maskedDB = CFDataCreateWithBytesNoCopy(NULL, CFDataGetBytePtr(encodedMessage) + hLen +extraPaddingLength, CFDataGetLength(encodedMessage) - hLen -extraPaddingLength, kCFAllocatorNull);
mgf_maskedDB = SecCreateMaskGenerationFunctionTransform(hashAlgo, hLen, &error);
if (!mgf_maskedDB) {
goto out;
}
if (!SecTransformSetAttribute(mgf_maskedDB, kSecTransformInputAttributeName, maskedDB, &error)) {
goto out;
}
seedMask = (CFDataRef)SecTransformExecute(mgf_maskedDB, &error);
if (!seedMask) {
goto out;
}
(void)transforms_assume(hLen == CFDataGetLength(seedMask));
raw_seed = (UInt8*)malloc(hLen);
xor_bytes(raw_seed, CFDataGetBytePtr(maskedSeed), CFDataGetBytePtr(seedMask), hLen);
seed = CFDataCreateWithBytesNoCopy(NULL, raw_seed, hLen, kCFAllocatorNull);
if (!seed) {
free(raw_seed);
error = GetNoMemoryErrorAndRetain();
goto out;
}
mgf_dbMask = SecCreateMaskGenerationFunctionTransform(hashAlgo, CFDataGetLength(encodedMessage) - hLen, &error);
if (!mgf_dbMask) {
goto out;
}
if (!SecTransformSetAttribute(mgf_dbMask, kSecTransformInputAttributeName, seed, &error)) {
goto out;
}
dbMask = (CFDataRef)SecTransformExecute(mgf_dbMask, &error);
if (!dbMask) {
goto out;
}
raw_DB = (UInt8*)malloc(CFDataGetLength(dbMask));
xor_bytes(raw_DB, CFDataGetBytePtr(maskedDB), CFDataGetBytePtr(dbMask), CFDataGetLength(dbMask));
hash = SecDigestTransformCreate(hashAlgo, 0, &error);
if (!hash) {
goto out;
}
EncodingParameters = (CFDataRef)this->GetAttribute(kSecOAEPEncodingParametersAttributeName);
if (EncodingParameters) {
CFRetain(EncodingParameters);
} else {
EncodingParameters = CFDataCreate(NULL, (UInt8*)"", 0);
if (!EncodingParameters) {
goto out;
}
}
if (!SecTransformSetAttribute(hash, kSecTransformInputAttributeName, EncodingParameters, &error)) {
goto out;
}
pHash = (CFDataRef)transforms_assume(SecTransformExecute(hash, &error));
if (!pHash) {
goto out;
}
(void)transforms_assume(hLen == CFDataGetLength(pHash));
pHashPrime = CFDataCreateWithBytesNoCopy(NULL, raw_DB, hLen, kCFAllocatorNull);
if (CFEqual(pHash, pHashPrime)) {
addr01 = (UInt8*)memchr(raw_DB + hLen, 0x01, CFDataGetLength(dbMask) - hLen);
if (!addr01) {
goto out;
}
message = CFDataCreate(NULL, addr01 + 1, (CFDataGetLength(dbMask) - ((addr01 - raw_DB) + 1)) -extraPaddingLength);
} else {
goto out;
}
out:
if (!message) {
if (!error) {
error = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "decoding error");
}
SetAttributeNoCallback(kSecTransformOutputAttributeName, error);
}
CFSafeRelease(maskedSeed);
CFSafeRelease(maskedDB);
CFSafeRelease(seedMask);
CFSafeRelease(seed);
CFSafeRelease(dbMask);
CFSafeRelease(pHash);
CFSafeRelease(pHashPrime);
CFSafeRelease(mgf_dbMask);
CFSafeRelease(mgf_maskedDB);
CFSafeRelease(hash);
CFSafeRelease(EncodingParameters);
free(raw_DB);
return message;
#endif
}
extern "C" {
extern CFDataRef oaep_padding_via_c(int desired_message_length, CFDataRef dataValue);
}
CFDataRef EncryptDecryptBase::apply_oaep_padding(CFDataRef dataValue)
{
#if 1
CFErrorRef error = NULL;
int hLen = Digest::LengthForType(kSecDigestSHA1);
CFNumberRef desired_message_length_cf = (CFNumberRef)this->GetAttribute(kSecOAEPMessageLengthAttributeName);
int desired_message_length = 0;
CSSM_QUERY_SIZE_DATA RSA_size;
CFDataRef EM = NULL;
if (desired_message_length_cf) {
CFNumberGetValue(desired_message_length_cf, kCFNumberIntType, &desired_message_length);
} else {
RSA_size.SizeInputBlock = (uint32)(CFDataGetLength(dataValue) + 2*hLen +1);
RSA_size.SizeOutputBlock = 0;
OSStatus status = CSSM_QuerySize(m_handle, CSSM_TRUE, 1, &RSA_size);
if (status != errSecSuccess) {
CFStringRef errorString = SecCopyErrorMessageString(status, NULL);
error = CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "CDSA error (%@).", errorString);
CFRelease(errorString);
SetAttributeNoCallback(kSecTransformOutputAttributeName, error);
(void)transforms_assume_zero(EM);
return EM;
}
(void)transforms_assume(RSA_size.SizeInputBlock <= RSA_size.SizeOutputBlock);
desired_message_length = RSA_size.SizeOutputBlock;
}
CFDataRef returnData = oaep_padding_via_c(desired_message_length, dataValue);
return returnData;
#else
CFDataRef seed = NULL, dbMask = NULL, maskedDB = NULL, seedMask = NULL, padHash = NULL, padZeros = NULL;
CFDataRef EncodingParameters = NULL;
CFMutableDataRef EM = NULL, dataBlob = NULL;
CFNumberRef desired_message_length_cf = NULL;
CFErrorRef error = NULL;
CFStringRef hashAlgo = NULL;
UInt8 *raw_padZeros = NULL, *raw_seed = NULL, *raw_maskedSeed = NULL, *raw_maskedDB = NULL;
SecTransformRef mgf_dbMask = NULL, mgf_seedMask = NULL, hash = NULL;
CFIndex paddingNeeded = -1, padLen = -1;
int hLen = -1;
CSSM_QUERY_SIZE_DATA RSA_size;
hashAlgo = (CFStringRef)this->GetAttribute(kSecOAEPMGF1DigestAlgorithmAttributeName);
if (hashAlgo == NULL) {
hashAlgo = kSecDigestSHA1;
}
hLen = Digest::LengthForType(hashAlgo);
desired_message_length_cf = (CFNumberRef)this->GetAttribute(kSecOAEPMessageLengthAttributeName);
int desired_message_length = 0;
if (desired_message_length_cf) {
CFNumberGetValue(desired_message_length_cf, kCFNumberIntType, &desired_message_length);
} else {
RSA_size.SizeInputBlock = CFDataGetLength(dataValue) + 2*hLen +1;
RSA_size.SizeOutputBlock = 0;
OSStatus status = CSSM_QuerySize(m_handle, CSSM_TRUE, 1, &RSA_size);
if (status != errSecSuccess) {
CFStringRef errorString = SecCopyErrorMessageString(status, NULL);
error = CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "CDSA error (%@).", errorString);
CFRelease(errorString);
goto out;
}
(void)transforms_assume(RSA_size.SizeInputBlock <= RSA_size.SizeOutputBlock);
desired_message_length = RSA_size.SizeOutputBlock -1;
}
padLen = (desired_message_length - (2*hLen) -1) - CFDataGetLength(dataValue);
if (padLen < 0) {
error = CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "Your message is too long for your message length, it needs to be %d bytes shorter, or you need to adjust the kSecOAEPMessageLengthAttributeName attribute", -padLen);
goto out;
}
raw_padZeros = (UInt8*)calloc(padLen, 1);
if (!raw_padZeros) {
error = GetNoMemoryErrorAndRetain();
goto out;
}
padZeros = CFDataCreateWithBytesNoCopy(NULL, raw_padZeros, padLen, kCFAllocatorMalloc);
if (!padZeros) {
free(raw_padZeros);
error = GetNoMemoryErrorAndRetain();
goto out;
}
hash = SecDigestTransformCreate(hashAlgo, 0, &error);
if (!hash) {
goto out;
}
EncodingParameters = (CFDataRef)this->GetAttribute(kSecOAEPEncodingParametersAttributeName);
if (EncodingParameters) {
CFRetain(EncodingParameters);
} else {
EncodingParameters = CFDataCreate(NULL, (UInt8*)"", 0);
if (!EncodingParameters) {
error = GetNoMemoryErrorAndRetain();
goto out;
}
}
if (!SecTransformSetAttribute(hash, kSecTransformInputAttributeName, EncodingParameters, &error)) {
goto out;
}
padHash = (CFDataRef)transforms_assume(SecTransformExecute(hash, &error));
if (!padHash) {
goto out;
}
(void)transforms_assume(hLen == CFDataGetLength(padHash));
dataBlob = CFDataCreateMutable(NULL, CFDataGetLength(padHash) + padLen + 1 + CFDataGetLength(dataValue));
if (!dataBlob) {
error = GetNoMemoryErrorAndRetain();
goto out;
}
CFDataAppendBytes(dataBlob, CFDataGetBytePtr(padHash), hLen);
CFDataAppendBytes(dataBlob, raw_padZeros, padLen);
CFDataAppendBytes(dataBlob, (UInt8*)"\01", 1);
CFDataAppendBytes(dataBlob, CFDataGetBytePtr(dataValue), CFDataGetLength(dataValue));
seed = (CFDataRef)this->GetAttribute(CFSTR("FixedSeedForOAEPTesting"));
raw_seed = NULL;
if (seed) {
(void)transforms_assume(hLen == CFDataGetLength(seed));
CFRetain(seed);
} else {
seed = SecRandomCopyData(kSecRandomDefault, hLen);
if (!seed) {
error = GetNoMemoryErrorAndRetain();
goto out;
}
}
raw_seed = (UInt8*)CFDataGetBytePtr(seed);
mgf_dbMask = transforms_assume(SecCreateMaskGenerationFunctionTransform(hashAlgo, desired_message_length - hLen, &error));
if (!mgf_dbMask) {
goto out;
}
if (!SecTransformSetAttribute(mgf_dbMask, kSecTransformInputAttributeName, seed, &error)) {
goto out;
}
dbMask = (CFDataRef)SecTransformExecute(mgf_dbMask, &error);
raw_maskedDB = (UInt8 *)malloc(CFDataGetLength(dbMask));
if (!raw_maskedDB) {
error = GetNoMemoryErrorAndRetain();
goto out;
}
xor_bytes(raw_maskedDB, CFDataGetBytePtr(dbMask), CFDataGetBytePtr(dataBlob), CFDataGetLength(dbMask));
maskedDB = CFDataCreateWithBytesNoCopy(NULL, raw_maskedDB, CFDataGetLength(dataBlob), kCFAllocatorMalloc);
if (!maskedDB) {
free(raw_maskedDB);
error = GetNoMemoryErrorAndRetain();
goto out;
}
mgf_seedMask = transforms_assume(SecCreateMaskGenerationFunctionTransform(hashAlgo, hLen, &error));
if (!mgf_seedMask) {
goto out;
}
if (!SecTransformSetAttribute(mgf_seedMask, kSecTransformInputAttributeName, maskedDB, &error)) {
goto out;
}
seedMask = transforms_assume((CFDataRef)SecTransformExecute(mgf_seedMask, &error));
if (!seedMask) {
goto out;
}
raw_maskedSeed = (UInt8 *)malloc(hLen);
if (!raw_maskedSeed) {
error = GetNoMemoryErrorAndRetain();
goto out;
}
xor_bytes(raw_maskedSeed, raw_seed, CFDataGetBytePtr(seedMask), hLen);
RSA_size.SizeInputBlock = hLen + CFDataGetLength(maskedDB);
CSSM_QuerySize(m_handle, CSSM_TRUE, 1, &RSA_size);
paddingNeeded = RSA_size.SizeOutputBlock - RSA_size.SizeInputBlock;
(void)transforms_assume(paddingNeeded >= 0);
EM = CFDataCreateMutable(NULL, CFDataGetLength(maskedDB) + hLen + paddingNeeded);
if (!EM) {
error = GetNoMemoryErrorAndRetain();
goto out;
}
while(paddingNeeded--) {
CFDataAppendBytes(EM, (UInt8*)"", 1);
}
CFDataAppendBytes(EM, raw_maskedSeed, hLen);
CFDataAppendBytes(EM, raw_maskedDB, CFDataGetLength(maskedDB));
out:
if (error) {
SetAttributeNoCallback(kSecTransformOutputAttributeName, error);
(void)transforms_assume_zero(EM);
}
CFSafeRelease(seed); CFSafeRelease(dbMask);
CFSafeRelease(maskedDB);
CFSafeRelease(seedMask);
CFSafeRelease(padHash);
CFSafeRelease(padZeros);
CFSafeRelease(EncodingParameters);
CFSafeRelease(dataBlob);
CFSafeRelease(mgf_dbMask);
CFSafeRelease(mgf_seedMask);
CFSafeRelease(hash);
free(raw_maskedSeed);
return EM;
#endif
}
void EncryptDecryptBase::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef value)
{
if (ah != inputAH)
{
return; }
if (value != NULL)
{
CFTypeID valueType = CFGetTypeID(value);
if (valueType != CFDataGetTypeID())
{
CFStringRef realType = CFCopyTypeIDDescription(valueType);
CFErrorRef error = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "Value is not a CFDataRef -- this one is a %@", realType);
CFRelease(realType);
SetAttributeNoCallback(kSecTransformOutputAttributeName, error);
return;
}
if (m_forEncryption && m_accumulator) {
CFDataRef d = (CFDataRef)value;
CFDataAppendBytes(m_accumulator, CFDataGetBytePtr(d), CFDataGetLength(d));
return;
}
}
if (m_forEncryption && m_accumulator) {
(void)transforms_assume_zero(value);
value = m_accumulator;
m_accumulator = NULL;
dispatch_async(this->mDispatchQueue, ^{
CFSafeRelease(value);
});
this->Pushback(inputAH, NULL);
if (m_oaep_padding) {
value = apply_oaep_padding((CFDataRef)value);
dispatch_async(this->mDispatchQueue, ^{
CFSafeRelease(value);
});
}
}
CFDataRef valueRef = (CFDataRef) value;
CSSM_RETURN crtn = CSSM_OK;
Boolean inFinal = FALSE;
if (valueRef != NULL)
{
CSSM_DATA dataStruct;
dataStruct.Length = CFDataGetLength(valueRef);
dataStruct.Data = const_cast<uint8_t*>(CFDataGetBytePtr(valueRef));
CSSM_DATA intermediateDataStruct;
memset(&intermediateDataStruct, 0, sizeof(intermediateDataStruct));
CSSM_SIZE bytesProcessed = 0;
if (m_forEncryption)
{
crtn = CSSM_EncryptDataUpdate(m_handle,
&dataStruct,
1,
&intermediateDataStruct,
1,
&bytesProcessed);
}
else
{
crtn = CSSM_DecryptDataUpdate(m_handle,
&dataStruct,
1,
&intermediateDataStruct,
1,
&bytesProcessed);
}
if (CSSM_OK != crtn)
{
SendCSSMError(crtn);
return;
}
if (intermediateDataStruct.Length > 0)
{
if (NULL == m_processedData)
{
m_processedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
}
CFDataAppendBytes(m_processedData, intermediateDataStruct.Data, bytesProcessed);
free(intermediateDataStruct.Data);
}
}
else
{
inFinal = TRUE;
CSSM_DATA remData;
memset(&remData, 0, sizeof(remData));
crtn = (m_forEncryption) ? CSSM_EncryptDataFinal(m_handle, &remData) : CSSM_DecryptDataFinal(m_handle, &remData);
if (CSSM_OK == crtn)
{
if (m_forEncryption == false && m_accumulator) {
(void)transforms_assume_zero(m_processedData);
if (remData.Length > 0) {
CFDataAppendBytes(m_accumulator, remData.Data, remData.Length);
}
} else {
if (NULL == m_processedData)
{
m_processedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
}
if (remData.Length > 0)
{
CFDataAppendBytes(m_processedData, remData.Data, remData.Length);
}
}
}
free(remData.Data);
if (CSSM_OK != crtn)
{
SendCSSMError(crtn);
return;
}
}
if (NULL != m_processedData)
{
SendAttribute(kSecTransformOutputAttributeName, m_processedData);
CFRelease(m_processedData);
m_processedData = NULL;
}
if (inFinal)
{
if (m_oaep_padding && m_forEncryption == false) {
CFTypeRef unpadded = remove_oaep_padding(m_accumulator);
SendAttribute(kSecTransformOutputAttributeName, unpadded);
CFRelease(unpadded);
}
SendAttribute(kSecTransformOutputAttributeName, NULL);
}
}
CFDictionaryRef EncryptDecryptBase::CopyState()
{
CFMutableDictionaryRef state = (CFMutableDictionaryRef) CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFStringRef paddingStr = (CFStringRef) GetAttribute(kSecPaddingKey);
CFStringRef modeStr = (CFStringRef) GetAttribute (kSecEncryptionMode);
CFDataRef ivData = (CFDataRef) GetAttribute(kSecIVKey);
if (NULL != paddingStr)
{
CFDictionaryAddValue(state, kSecPaddingKey, paddingStr);
}
if (NULL != modeStr)
{
CFDictionaryAddValue(state, kSecEncryptionMode, modeStr);
}
if (NULL != ivData)
{
CFDictionaryAddValue(state, kSecIVKey, ivData);
}
return state;
}
void EncryptDecryptBase::RestoreState(CFDictionaryRef state)
{
if (NULL == state)
{
return;
}
CFStringRef paddingStr = (CFStringRef)CFDictionaryGetValue(state, kSecPaddingKey);
CFStringRef modeStr = (CFStringRef)CFDictionaryGetValue(state, kSecEncryptionMode);
CFDataRef ivData = (CFDataRef)CFDictionaryGetValue(state, kSecIVKey);
if (NULL != paddingStr)
{
SetAttribute(kSecPaddingKey, paddingStr);
}
if (NULL != modeStr)
{
SetAttribute(kSecEncryptionMode, modeStr);
}
if (NULL != ivData)
{
SetAttribute(kSecIVKey, ivData);
}
}
EncryptTransform::EncryptTransform() : EncryptDecryptBase(kEncryptTransformType)
{
}
EncryptTransform::~EncryptTransform()
{
}
SecTransformRef EncryptTransform::Make()
{
EncryptTransform* tr = new EncryptTransform();
SecTransformRef str = (SecTransformRef) CoreFoundationHolder::MakeHolder(kEncryptTransformType, tr);
return str;
}
class EncryptTransformFactory : public TransformFactory
{
public:
EncryptTransformFactory();
CFTypeRef Make();
};
EncryptTransformFactory::EncryptTransformFactory() :
TransformFactory(kEncryptTransformType)
{}
TransformFactory* EncryptTransform::MakeTransformFactory()
{
return new EncryptTransformFactory;
}
CFTypeRef EncryptTransformFactory::Make()
{
return EncryptTransform::Make();
}
DecryptTransform::DecryptTransform() : EncryptDecryptBase(kDecryptTransformType)
{
}
DecryptTransform::~DecryptTransform()
{
}
SecTransformRef DecryptTransform::Make()
{
DecryptTransform* tr = new DecryptTransform();
SecTransformRef str = (SecTransformRef) CoreFoundationHolder::MakeHolder(kDecryptTransformType, tr);
return str;
}
class DecryptTransformFactory : public TransformFactory
{
public:
DecryptTransformFactory();
CFTypeRef Make();
};
DecryptTransformFactory::DecryptTransformFactory() :
TransformFactory(kDecryptTransformType)
{}
TransformFactory* DecryptTransform::MakeTransformFactory()
{
return new DecryptTransformFactory;
}
CFTypeRef DecryptTransformFactory::Make()
{
return DecryptTransform::Make();
}