X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_transform/lib/EncryptTransform.cpp diff --git a/Security/libsecurity_transform/lib/EncryptTransform.cpp b/Security/libsecurity_transform/lib/EncryptTransform.cpp deleted file mode 100644 index c6617513..00000000 --- a/Security/libsecurity_transform/lib/EncryptTransform.cpp +++ /dev/null @@ -1,1098 +0,0 @@ -/* - * Copyright (c) 2010-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#include "EncryptTransform.h" -#include "SecEncryptTransform.h" -#include "EncryptTransformUtilities.h" -#include "Utilities.h" -#include "SecDigestTransform.h" -#include "Digest.h" -#include -#include "SecMaskGenerationFunctionTransform.h" - -static CFStringRef kEncryptTransformType = CFSTR("Encrypt Transform"); -static CFStringRef kDecryptTransformType = CFSTR("Decrypt Transform"); -//static const char *kEncryptTransformType_cstr = "Encrypt Transform"; -//static const char *kDecryptTransformType_cstr = "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}; // default Salt for key - -dispatch_once_t EncryptDecryptBase::serializerSetUp; -dispatch_queue_t EncryptDecryptBase::serializerTransformStartingExecution; - -/* -------------------------------------------------------------------------- - Implementation of the EncryptDecryptBase class - -------------------------------------------------------------------------- */ - -/* -------------------------------------------------------------------------- - method: EncryptDecryptBase (Constructor) - description: Initialize a new instance of a EncryptDecryptBase class - -------------------------------------------------------------------------- */ -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)); -} - -/* -------------------------------------------------------------------------- - method: ~EncryptDecryptBase (pre-Destructor) - description: Clean m_handle, let Transform::Finalize() do the rest - -------------------------------------------------------------------------- */ -void EncryptDecryptBase::Finalize() -{ - if (m_handle != (CSSM_CC_HANDLE)0) - { - CSSM_CC_HANDLE tmp_handle = m_handle; - // Leaving this to the destructor causes occasional crashes. - // This may be a CDSA thread afinity bug, or it might be more - // local. - dispatch_async(mDispatchQueue, ^{ - CSSM_DeleteContext(tmp_handle); - }); - m_handle = ((CSSM_CC_HANDLE)0); - } - - Transform::Finalize(); -} - - -/* -------------------------------------------------------------------------- - method: ~EncryptDecryptBase (Destructor) - description: Clean up the memory of an EncryptDecryptBase object - -------------------------------------------------------------------------- */ -EncryptDecryptBase::~EncryptDecryptBase() -{ - if (NULL != m_processedData) - { - CFRelease(m_processedData); - m_processedData = NULL; - } - if (NULL != m_accumulator) - { - CFRelease(m_accumulator); - m_accumulator = NULL; - } -} - -/* -------------------------------------------------------------------------- - method: InitializeObject(SecKeyRef key, CFErrorRef *error) - description: Initialize an instance of the base encrypt/decrypt transform - -------------------------------------------------------------------------- */ -bool EncryptDecryptBase::InitializeObject(SecKeyRef key, CFErrorRef *error) -{ - SetAttributeNoCallback(kSecEncryptKey, key); - if (error) - { - *error = NULL; - } - - return true; -} - -/* -------------------------------------------------------------------------- - method: SerializedTransformStartingExecution() - description: Get this transform ready to run, should only be called on - the serializerTransformStartingExecution queue - -------------------------------------------------------------------------- */ -CFErrorRef EncryptDecryptBase::SerializedTransformStartingExecution() -{ - CFErrorRef result = NULL; // Assume all is well - 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(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); - - // Need better error here - 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); - - // Need better error here - if (crtn != CSSM_OK) - { - CFStringRef result = SecCopyErrorMessageString(crtn, NULL); - CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA error (%@).", result); - CFRelease(result); - return retValue; - } - } - - // Encryption - crtn = (m_forEncryption) ? CSSM_EncryptDataInit(m_handle) : CSSM_DecryptDataInit(m_handle); - // Need better error here - 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; -} - -/* -------------------------------------------------------------------------- - method: TransformStartingExecution() - description: Get this transform ready to run. - NOTE: the encrypt/decrypt setup is not safe to call for a single - key from multiple threads at once, TransformStartingExecution is - responsable making sure this doesn't happen, - SerializedTransformStartingExecution() does the real set up work. - -------------------------------------------------------------------------- */ -CFErrorRef EncryptDecryptBase::TransformStartingExecution() -{ - - dispatch_once(&serializerSetUp, ^{ - serializerTransformStartingExecution = dispatch_queue_create("com.apple.security.EncryptDecrypt.key-setup", NULL); - }); - - __block CFErrorRef result = NULL; // Assume all is well - - dispatch_sync(serializerTransformStartingExecution, ^{ - result = SerializedTransformStartingExecution(); - }); - return result; -} - -/* -------------------------------------------------------------------------- - method: TransformCanExecute - description: Do we have a key? - -------------------------------------------------------------------------- */ -Boolean EncryptDecryptBase::TransformCanExecute() -{ - // make sure we have a key -- there may be some circumstance when one isn't available - // and besides, it helps test this logic - SecKeyRef key = (SecKeyRef) GetAttribute(kSecEncryptKey); - return key != NULL; -} - -void EncryptDecryptBase::SendCSSMError(CSSM_RETURN retCode) -{ - // make a CFErrorRef for the error message - CFStringRef errorString = SecCopyErrorMessageString(retCode, NULL); - CFErrorRef errorRef = CreateGenericErrorRef(kCFErrorDomainOSStatus, retCode, "%@", errorString); - CFRelease(errorString); - - SendAttribute(kSecTransformOutputAttributeName, errorRef); - CFRelease(errorRef); -} - -#warning "This declaration should be in some header" -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) -{ - // NOTE: this can be made faster, but see if we already have a faster version somewhere first. - - // _mm_xor_ps would be nice here - // failing that, getting to an aligned boundry and switching to uint64_t - // would be good. - - 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; - // RSA's OAEP documentation assumes the crypto layer will remove the leading (partial) byte, - // but CDSA leaves that responsability to us (we did ask it for "no padding" after all). - // (use extraPaddingLength = 0 when using a layer that does strip that byte) - const int extraPaddingLength = 1; - - // The numbered steps below correspond to RSA Laboratories' RSAES-OAEP Encryption Scheme - // document's numbered steps. - - // NOTE: we omit step 1: "If the length of P is greater than the input limitation for the hash - // function (2^61 − 1 octets for SHA-1) then output ‘‘decoding error’’ and stop."; we don't have - // ready access to the input limits of the hash functions, and in the real world we won't be - // seeing messages that long anyway. - - // (2) If emLen < 2hLen + 1, output ‘‘decoding error’’ and stop. - hashAlgo = (CFStringRef)this->GetAttribute(kSecOAEPMGF1DigestAlgorithmAttributeName); - if (hashAlgo == NULL) { - hashAlgo = kSecDigestSHA1; - } - hLen = Digest::LengthForType(hashAlgo); - if (CFDataGetLength(encodedMessage) < 2*hLen + 1) { - goto out; - } - - // (3) Let maskedSeed be the first hLen octets of EM and let maskedDB be the remaining emLen−hLen - // octets. - maskedSeed = CFDataCreateWithBytesNoCopy(NULL, CFDataGetBytePtr(encodedMessage) +extraPaddingLength, hLen, kCFAllocatorNull); - maskedDB = CFDataCreateWithBytesNoCopy(NULL, CFDataGetBytePtr(encodedMessage) + hLen +extraPaddingLength, CFDataGetLength(encodedMessage) - hLen -extraPaddingLength, kCFAllocatorNull); - - // (4) Let seedMask = MGF(maskedDB, hLen). - 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)); - - // (5) Let seed = maskedSeed ⊕ 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; - } - // (6) Let dbMask = MGF (seed, emLen − hLen). - 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; - } - - // (7) Let DB = maskedDB ⊕ dbMask. - raw_DB = (UInt8*)malloc(CFDataGetLength(dbMask)); - xor_bytes(raw_DB, CFDataGetBytePtr(maskedDB), CFDataGetBytePtr(dbMask), CFDataGetLength(dbMask)); - - // (8) Let pHash = Hash(P), an octet string of length hLen. - 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)); - - - // (9) Separate DB into an octet string pHash’ consisting of the first hLen octets of DB, a - // (possibly empty) octet string PS consisting of consecutive zero octets following pHash’, - // and a message M as If there is no 01 octet to separate PS from M , output ‘‘decoding error’’ and stop. - 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 { - // (10) If pHash’ does not equal pHash, output ‘‘decoding error’’ and stop. - goto out; - } - -out: - if (!message) { - if (!error) { - error = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "decoding error"); - } - SetAttributeNoCallback(kSecTransformOutputAttributeName, error); - } - - // Release eveything except: - // hashAlgo (obtained via get) - // message (return value) - CFSafeRelease(maskedSeed); - CFSafeRelease(maskedDB); - CFSafeRelease(seedMask); - CFSafeRelease(seed); - CFSafeRelease(dbMask); - CFSafeRelease(pHash); - CFSafeRelease(pHashPrime); - CFSafeRelease(mgf_dbMask); - CFSafeRelease(mgf_maskedDB); - CFSafeRelease(hash); - CFSafeRelease(EncodingParameters); - // raw_seed is free'd via CFData, addr01 was never allocated, so raw_DB is our lot - free(raw_DB); - - // (11) Output M. - 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 - // MGF1 w/ SHA1 assumed here - - 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 { - // take RSA (or whatever crypto) block size onto account too - 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; - - // NOTE: we omit (1) If the length of P is greater than the input limitation for the hash function - // (2^61 − 1 octets for SHA-1) then output ‘‘parameter string too long’’ and stop. - // We don't have ready access to the input limit of the hash functions, and in the real world - // we won't be seeing a message that long anyway. - - // (2) If mLen > emLen − 2hLen − 1, output ‘‘message too long’’ and stop. - 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 { - // take RSA (or whatever crypto) block size onto account too - 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; - } - - // (3) Generate an octet string PS consisting of emLen − mLen − 2hLen − 1 zero octets. The length of PS may be 0. - 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; - } - - // (4) Let pHash = Hash(P), an octet string of length hLen. - 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)); - - // (5) Concatenate pHash,PS, the message M, and other padding to form a data block DB as DB = pHash∥PS∥01∥M. - 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)); - - // (6) Generate a random octet string seed of length hLen. - seed = (CFDataRef)this->GetAttribute(CFSTR("FixedSeedForOAEPTesting")); - raw_seed = NULL; - if (seed) { - raw_seed = (UInt8*)CFDataGetBytePtr(seed); - (void)transforms_assume(hLen == CFDataGetLength(seed)); - CFRetain(seed); - } else { - raw_seed = (UInt8*)malloc(hLen); - if (!raw_seed) { - error = GetNoMemoryErrorAndRetain(); - goto out; - } - SecRandomCopyBytes(kSecRandomDefault, hLen, raw_seed); - seed = CFDataCreateWithBytesNoCopy(NULL, raw_seed, hLen, kCFAllocatorMalloc); - if (!seed) { - free(raw_seed); - error = GetNoMemoryErrorAndRetain(); - } - } - - // (7) Let dbMask = MGF (seed, emLen − hLen). - 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); - - // (8) Let maskedDB = DB ⊕ dbMask. - // NOTE: we do some allocations above...you know, we should be able to malloc ONE buffer of the - // proper size. - 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; - } - - // (9) Let seedMask = MGF(maskedDB, hLen). - 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; - } - - // (10) Let maskedSeed = seed ⊕ seedMask - raw_maskedSeed = (UInt8 *)malloc(hLen); - if (!raw_maskedSeed) { - error = GetNoMemoryErrorAndRetain(); - goto out; - } - xor_bytes(raw_maskedSeed, raw_seed, CFDataGetBytePtr(seedMask), hLen); - - // (11) Let EM = maskedSeed∥maskedDB (if we didn't have to pushback the NULL we could do this without physically concatanating) - // (figure out amount of leading zero padding we need) - 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); // via get?? - CFSafeRelease(dbMask); - CFSafeRelease(maskedDB); - CFSafeRelease(seedMask); - CFSafeRelease(padHash); - CFSafeRelease(padZeros); - CFSafeRelease(EncodingParameters); - CFSafeRelease(dataBlob); - // desired_message_length_cf -- via get - // hashAlgo -- via get - CFSafeRelease(mgf_dbMask); - CFSafeRelease(mgf_seedMask); - CFSafeRelease(hash); - // raw_* are all freed by their associated CFDatas, except raw_maskedSeed - free(raw_maskedSeed); - - // (12) Output EM. - return EM; -#endif -} - -/* -------------------------------------------------------------------------- - method: AttributeChanged - description: deal with input - -------------------------------------------------------------------------- */ -void EncryptDecryptBase::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef value) -{ - // sanity check our arguments - if (ah != inputAH) - { - return; // we only deal with input - } - - 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); - }); - } - } - - // add the input to our cryptor - CFDataRef valueRef = (CFDataRef) value; - CSSM_RETURN crtn = CSSM_OK; - Boolean inFinal = FALSE; - - if (valueRef != NULL) - { - // Convert to A CSSM_DATA - CSSM_DATA dataStruct; - dataStruct.Length = CFDataGetLength(valueRef); - dataStruct.Data = const_cast(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 - { - // Finalize - - 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); - } - - -} - -/* -------------------------------------------------------------------------- - method: CopyState - description: Copy the current state of this transform - -------------------------------------------------------------------------- */ -CFDictionaryRef EncryptDecryptBase::CopyState() -{ - // make a dictionary for our state - 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; -} - -/* -------------------------------------------------------------------------- - method: RestoreState - description: Restore the state of this transform from a dictionary - -------------------------------------------------------------------------- */ -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); - } - -} - -/* -------------------------------------------------------------------------- - Implementation of the EncryptTransform - -------------------------------------------------------------------------- */ - -/* -------------------------------------------------------------------------- - method: EncryptTransform (Constructor) - description: Make a new EncryptTransform - -------------------------------------------------------------------------- */ -EncryptTransform::EncryptTransform() : EncryptDecryptBase(kEncryptTransformType) -{ -} - -/* -------------------------------------------------------------------------- - method: ~EncryptTransform (Destructor) - description: Clean up the memory of anEncryptTransform - -------------------------------------------------------------------------- */ -EncryptTransform::~EncryptTransform() -{ -} - -/* -------------------------------------------------------------------------- - method: [static] Make - description: Make a new instance of this class - -------------------------------------------------------------------------- */ -SecTransformRef EncryptTransform::Make() -{ - EncryptTransform* tr = new EncryptTransform(); - SecTransformRef str = (SecTransformRef) CoreFoundationHolder::MakeHolder(kEncryptTransformType, tr); - return str; -} - -/* -------------------------------------------------------------------------- - Interface and implementation of the EncryptTransformFactory - -------------------------------------------------------------------------- */ - -class EncryptTransformFactory : public TransformFactory -{ -public: - EncryptTransformFactory(); - CFTypeRef Make(); -}; - - -/* -------------------------------------------------------------------------- - method: EncryptTransformFactory (Constructor) - description: - -------------------------------------------------------------------------- */ -EncryptTransformFactory::EncryptTransformFactory() : -TransformFactory(kEncryptTransformType) -{} - - -/* -------------------------------------------------------------------------- - method: MakeTransformFactory - description: Make an instance of this factory class - -------------------------------------------------------------------------- */ -TransformFactory* EncryptTransform::MakeTransformFactory() -{ - return new EncryptTransformFactory; -} - -/* -------------------------------------------------------------------------- - method: Make - description: Create an instance of this class - -------------------------------------------------------------------------- */ -CFTypeRef EncryptTransformFactory::Make() -{ - return EncryptTransform::Make(); -} - - -/* -------------------------------------------------------------------------- - method: DecryptTransform (Constructor) - description: Make a new DecryptTransform - -------------------------------------------------------------------------- */ -DecryptTransform::DecryptTransform() : EncryptDecryptBase(kDecryptTransformType) -{ -} - -/* -------------------------------------------------------------------------- - method: ~DecryptTransform (Destructor) - description: Clean up the memory of anDecryptTransform - -------------------------------------------------------------------------- */ -DecryptTransform::~DecryptTransform() -{ -} - - -/* -------------------------------------------------------------------------- - method: [static] Make - description: Make a new instance of this class - -------------------------------------------------------------------------- */ -SecTransformRef DecryptTransform::Make() -{ - DecryptTransform* tr = new DecryptTransform(); - SecTransformRef str = (SecTransformRef) CoreFoundationHolder::MakeHolder(kDecryptTransformType, tr); - return str; -} - -/* -------------------------------------------------------------------------- - Interface and implementation of the DecryptTransformFactory - -------------------------------------------------------------------------- */ - -class DecryptTransformFactory : public TransformFactory -{ -public: - DecryptTransformFactory(); - CFTypeRef Make(); -}; - - -/* -------------------------------------------------------------------------- - method: DecryptTransformFactory (Constructor) - description: - -------------------------------------------------------------------------- */ -DecryptTransformFactory::DecryptTransformFactory() : -TransformFactory(kDecryptTransformType) -{} - - -/* -------------------------------------------------------------------------- - method: MakeTransformFactory - description: Make an instance of this factory class - -------------------------------------------------------------------------- */ -TransformFactory* DecryptTransform::MakeTransformFactory() -{ - return new DecryptTransformFactory; -} - -/* -------------------------------------------------------------------------- - method: Make - description: Create an instance of this class - -------------------------------------------------------------------------- */ -CFTypeRef DecryptTransformFactory::Make() -{ - return DecryptTransform::Make(); -} -