/ OSX / libsecurity_transform / lib / EncryptTransform.cpp
EncryptTransform.cpp
   1  /*
   2   * Copyright (c) 2010-2014 Apple Inc. All Rights Reserved.
   3   *
   4   * @APPLE_LICENSE_HEADER_START@
   5   * 
   6   * This file contains Original Code and/or Modifications of Original Code
   7   * as defined in and that are subject to the Apple Public Source License
   8   * Version 2.0 (the 'License'). You may not use this file except in
   9   * compliance with the License. Please obtain a copy of the License at
  10   * http://www.opensource.apple.com/apsl/ and read it before using this
  11   * file.
  12   * 
  13   * The Original Code and all software distributed under the License are
  14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  18   * Please see the License for the specific language governing rights and
  19   * limitations under the License.
  20   * 
  21   * @APPLE_LICENSE_HEADER_END@
  22   */
  23  
  24  
  25  #include "EncryptTransform.h"
  26  #include "SecEncryptTransform.h"
  27  #include "EncryptTransformUtilities.h"
  28  #include "Utilities.h"
  29  #include "SecDigestTransform.h"
  30  #include "Digest.h"
  31  #include <Security/SecRandomP.h>
  32  #include <Security/SecKey.h>
  33  #include "SecMaskGenerationFunctionTransform.h"
  34  
  35  static CFStringRef kEncryptTransformType = CFSTR("Encrypt Transform");
  36  static CFStringRef kDecryptTransformType = CFSTR("Decrypt Transform");
  37  //static const char *kEncryptTransformType_cstr = "Encrypt Transform";
  38  //static const char *kDecryptTransformType_cstr = "Decrypt Transform";
  39  static uint8 iv[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  40  static const CSSM_DATA gKeySalt = {16, iv}; // default Salt for key
  41  
  42  dispatch_once_t EncryptDecryptBase::serializerSetUp;
  43  dispatch_queue_t EncryptDecryptBase::serializerTransformStartingExecution;
  44  
  45  /* --------------------------------------------------------------------------
  46   Implementation of the EncryptDecryptBase class
  47   -------------------------------------------------------------------------- */
  48  
  49  /* --------------------------------------------------------------------------
  50   method: 		EncryptDecryptBase (Constructor)
  51   description: 	Initialize a new instance of a EncryptDecryptBase class
  52   -------------------------------------------------------------------------- */
  53  EncryptDecryptBase::EncryptDecryptBase(CFStringRef type) :
  54  Transform(type),
  55  m_cssm_padding(CSSM_PADDING_NONE),
  56  m_mode(CSSM_ALGMODE_CBCPadIV8),
  57  m_cssm_key(NULL),
  58  m_handle((CSSM_CC_HANDLE)0),
  59  m_forEncryption(FALSE),
  60  m_processedData(NULL),
  61  m_accumulator(NULL)
  62  {
  63  	m_forEncryption = CFEqual(type, kEncryptTransformType);
  64      inputAH = transforms_assume(this->getAH(kSecTransformInputAttributeName, false, false));
  65  }
  66  
  67  /* --------------------------------------------------------------------------
  68   method: 		~EncryptDecryptBase (pre-Destructor)
  69   description: 	Clean m_handle, let Transform::Finalize() do the rest
  70   -------------------------------------------------------------------------- */
  71  void EncryptDecryptBase::Finalize()
  72  {
  73  	if (m_handle != (CSSM_CC_HANDLE)0)
  74  	{
  75  		CSSM_CC_HANDLE tmp_handle = m_handle;
  76  		// Leaving this to the destructor causes occasional crashes.
  77  		// This may be a CDSA thread afinity bug, or it might be more
  78  		// local.
  79  		dispatch_async(mDispatchQueue, ^{
  80  			CSSM_DeleteContext(tmp_handle);
  81  		});
  82  		m_handle = ((CSSM_CC_HANDLE)0);
  83  	}
  84  
  85  	Transform::Finalize();
  86  }
  87  
  88  
  89  /* --------------------------------------------------------------------------
  90   method: 		~EncryptDecryptBase (Destructor)
  91   description: 	Clean up the memory of an EncryptDecryptBase object
  92   -------------------------------------------------------------------------- */
  93  EncryptDecryptBase::~EncryptDecryptBase()
  94  {
  95  	if (NULL != m_processedData)
  96  	{
  97  		CFReleaseNull(m_processedData);
  98  		m_processedData = NULL;
  99  	}
 100  	if (NULL != m_accumulator)
 101  	{
 102  		CFReleaseNull(m_accumulator);
 103  		m_accumulator = NULL;
 104  	}
 105  }
 106  
 107  /* --------------------------------------------------------------------------
 108   method: 		InitializeObject(SecKeyRef key, CFErrorRef *error)
 109   description: 	Initialize an instance of the base encrypt/decrypt transform
 110   -------------------------------------------------------------------------- */
 111  bool EncryptDecryptBase::InitializeObject(SecKeyRef key, CFErrorRef *error)
 112  {
 113  	SetAttributeNoCallback(kSecEncryptKey, key);
 114  	if (error)
 115  	{
 116  		*error = NULL;
 117  	}
 118  
 119  	return true;
 120  }
 121  
 122  /* --------------------------------------------------------------------------
 123   method: 		SerializedTransformStartingExecution()
 124   description: 	Get this transform ready to run, should only be called on
 125  				the serializerTransformStartingExecution queue
 126   -------------------------------------------------------------------------- */
 127  CFErrorRef EncryptDecryptBase::SerializedTransformStartingExecution()
 128  {
 129  	CFErrorRef result = NULL;	// Assume all is well
 130  	SecKeyRef key = (SecKeyRef) GetAttribute(kSecEncryptKey);
 131  	if (NULL == key)
 132  	{
 133  		return CreateSecTransformErrorRef(kSecTransformErrorAttributeNotFound, "The attribute %@ was not found.", kSecEncryptKey);
 134  	}
 135  
 136  	OSStatus err = errSecSuccess;
 137  	err = SecKeyGetCSSMKey(key, (const CSSM_KEY **)&m_cssm_key);
 138  	if (errSecSuccess != err)
 139  	{
 140  		CFStringRef result = SecCopyErrorMessageString(err, NULL);
 141  		CFErrorRef retValue = CreateSecTransformErrorRef(err, "CDSA error (%@).", result);
 142  		CFReleaseNull(result);
 143  		return retValue;
 144  	}
 145  
 146  	CSSM_CSP_HANDLE csp;
 147  	err = SecKeyGetCSPHandle(key, &csp);
 148  	if (errSecSuccess != err)
 149  	{
 150  		CFStringRef result = SecCopyErrorMessageString(err, NULL);
 151  		CFErrorRef retValue = CreateSecTransformErrorRef(err, "CDSA error (%@).", result);
 152  		CFReleaseNull(result);
 153  		return retValue;
 154  	}
 155  
 156  	CSSM_ALGORITHMS	keyAlg = m_cssm_key->KeyHeader.AlgorithmId;
 157  
 158  	m_cssm_padding = CSSM_PADDING_NONE;
 159  	CFStringRef paddingStr = (CFStringRef) GetAttribute(kSecPaddingKey);
 160  	CFStringRef modeStr = (CFStringRef) GetAttribute (kSecEncryptionMode);
 161  	CFDataRef ivData = (CFDataRef) GetAttribute(kSecIVKey);
 162  
 163  	Boolean hasPadding = (paddingStr != NULL);
 164  	Boolean hasMode = (modeStr != NULL);
 165  	Boolean hasIVData = (ivData != NULL);
 166  	Boolean isSymmetrical = (m_cssm_key->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY);
 167  
 168  
 169      if (!hasPadding)
 170  	{
 171  		if (CSSM_ALGID_RSA == keyAlg || CSSM_ALGID_ECDSA == keyAlg)
 172  		{
 173  			m_cssm_padding = CSSM_PADDING_PKCS1;
 174  		}
 175  		else
 176  		{
 177  			m_cssm_padding = CSSM_PADDING_PKCS7;
 178  		}
 179  		m_oaep_padding = false;
 180  	}
 181  	else
 182  	{
 183  		if (CFStringCompare(kSecPaddingOAEPKey, paddingStr, kCFCompareAnchored)) {
 184  			m_oaep_padding = false;
 185  			m_cssm_padding = ConvertPaddingStringToEnum(paddingStr);
 186  		} else {
 187  			m_cssm_padding = CSSM_PADDING_NONE;
 188  			m_oaep_padding = true;
 189  			m_accumulator = CFDataCreateMutable(NULL, 0);
 190  			if (!m_accumulator) {
 191  				return GetNoMemoryErrorAndRetain();
 192  			}
 193  		}
 194  	}
 195  
 196  	if (!hasMode)
 197  	{
 198  		m_mode = (CSSM_PADDING_NONE == m_cssm_padding) ? CSSM_ALGMODE_CBC_IV8 : CSSM_ALGMODE_CBCPadIV8;
 199  	}
 200  	else
 201  	{
 202  		m_mode = ConvertEncryptModeStringToEnum(modeStr, (CSSM_PADDING_NONE != m_cssm_padding));
 203  	}
 204  
 205  
 206  	CSSM_RETURN crtn = CSSM_OK;
 207  	CSSM_ACCESS_CREDENTIALS	creds;
 208  	CSSM_ACCESS_CREDENTIALS* credPtr = NULL;
 209  	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
 210  
 211  	err = SecKeyGetCredentials(key,
 212  	                           (m_forEncryption) ? CSSM_ACL_AUTHORIZATION_ENCRYPT : CSSM_ACL_AUTHORIZATION_DECRYPT,
 213  	                           kSecCredentialTypeDefault,
 214  	                           (const CSSM_ACCESS_CREDENTIALS **)&credPtr);
 215  	if (errSecSuccess != err)
 216  	{
 217  		memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
 218  		credPtr = &creds;
 219  	}
 220  
 221  	if (isSymmetrical)
 222  	{
 223          // Clang thinks we're leaking initVect.data.
 224          // While it's difficult to analyze whether that ends up being true or not, this is not code we love enough to refactor
 225  #ifndef __clang_analyzer__
 226  		CSSM_DATA initVector;
 227  		if (hasIVData)
 228  		{
 229  			initVector.Length = CFDataGetLength(ivData);
 230  			initVector.Data = const_cast<uint8_t*>(CFDataGetBytePtr(ivData));
 231  		}
 232  		else
 233  		{
 234  			initVector.Length = gKeySalt.Length;
 235  			initVector.Data = (uint8 *)malloc(initVector.Length);
 236  			initVector.Data = gKeySalt.Data;
 237  		}
 238  
 239  		crtn = CSSM_CSP_CreateSymmetricContext(csp, keyAlg, m_mode, credPtr, m_cssm_key,
 240  		                                       &initVector, m_cssm_padding, NULL, &m_handle);
 241  
 242  		// Need better error here
 243  		if (crtn != CSSM_OK)
 244  		{
 245  			CFStringRef result = SecCopyErrorMessageString(crtn, NULL);
 246  			CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA error (%@).", result);
 247  			CFReleaseNull(result);
 248  			return retValue;
 249  		}
 250  #endif
 251  	}
 252  	else
 253  	{
 254  		crtn = CSSM_CSP_CreateAsymmetricContext(csp, keyAlg, credPtr, m_cssm_key, m_cssm_padding, &m_handle);
 255  
 256  		// Need better error here
 257  		if (crtn != CSSM_OK)
 258  		{
 259  			CFStringRef result = SecCopyErrorMessageString(crtn, NULL);
 260  			CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA error (%@).", result);
 261  			CFReleaseNull(result);
 262  			return retValue;
 263  		}
 264  	}
 265  
 266  	// Encryption
 267  	crtn = (m_forEncryption) ? CSSM_EncryptDataInit(m_handle) : CSSM_DecryptDataInit(m_handle);
 268  	// Need better error here
 269  	if (crtn != CSSM_OK)
 270  	{
 271  			CFStringRef result = SecCopyErrorMessageString(crtn, NULL);
 272  			CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA encrypt/decrypt init error (%@).", result);
 273  			CFReleaseNull(result);
 274  			return retValue;
 275  	}
 276  
 277  
 278  	return result;
 279  }
 280  
 281  /* --------------------------------------------------------------------------
 282   method: 		TransformStartingExecution()
 283   description: 	Get this transform ready to run.
 284   NOTE:			the encrypt/decrypt setup is not safe to call for a single
 285  				key from multiple threads at once, TransformStartingExecution is
 286  				responsable making sure this doesn't happen,
 287  				SerializedTransformStartingExecution() does the real set up work.
 288   -------------------------------------------------------------------------- */
 289  CFErrorRef EncryptDecryptBase::TransformStartingExecution()
 290  {
 291  
 292  	dispatch_once(&serializerSetUp, ^{
 293  		serializerTransformStartingExecution = dispatch_queue_create("com.apple.security.EncryptDecrypt.key-setup", NULL);
 294  	});
 295  
 296  	__block CFErrorRef result = NULL;	// Assume all is well
 297  
 298  	dispatch_sync(serializerTransformStartingExecution, ^{
 299  		result = SerializedTransformStartingExecution();
 300  	});
 301  	return result;
 302  }
 303  
 304  /* --------------------------------------------------------------------------
 305   method: 		TransformCanExecute
 306   description: 	Do we have a key?
 307   -------------------------------------------------------------------------- */
 308  Boolean EncryptDecryptBase::TransformCanExecute()
 309  {
 310  	// make sure we have a key -- there may be some circumstance when one isn't available
 311  	// and besides, it helps test this logic
 312  	SecKeyRef key = (SecKeyRef) GetAttribute(kSecEncryptKey);
 313  	return key != NULL;
 314  }
 315  
 316  void EncryptDecryptBase::SendCSSMError(CSSM_RETURN retCode)
 317  {
 318  	// make a CFErrorRef for the error message
 319  	CFStringRef errorString = SecCopyErrorMessageString(retCode, NULL);
 320  	CFErrorRef errorRef = CreateGenericErrorRef(kCFErrorDomainOSStatus, retCode, "%@", errorString);
 321  	CFReleaseNull(errorString);
 322  
 323  	SendAttribute(kSecTransformOutputAttributeName, errorRef);
 324  	CFReleaseNull(errorRef);
 325  }
 326  
 327  void xor_bytes(UInt8 *dst, const UInt8 *src1, const UInt8 *src2, CFIndex length);
 328  void xor_bytes(UInt8 *dst, const UInt8 *src1, const UInt8 *src2, CFIndex length)
 329  {
 330  	// NOTE: this can be made faster, but see if we already have a faster version somewhere first.
 331  
 332  	// _mm_xor_ps would be nice here
 333  	// failing that, getting to an aligned boundry and switching to uint64_t
 334  	// would be good.
 335  
 336  	while (length--) {
 337  		*dst++ = *src1++ ^ *src2++;
 338  	}
 339  }
 340  
 341  extern "C" {
 342  	extern CFDataRef oaep_unpadding_via_c(CFDataRef encodedMessage);
 343  }
 344  
 345  CFDataRef EncryptDecryptBase::remove_oaep_padding(CFDataRef encodedMessage)
 346  {
 347  #if 1
 348  	return oaep_unpadding_via_c(encodedMessage);
 349  #else
 350      CFStringRef hashAlgo = NULL;
 351      CFDataRef message = NULL, maskedSeed = NULL, maskedDB = NULL, seedMask = NULL, seed = NULL, dbMask = NULL;
 352      CFDataRef pHash = NULL, pHashPrime = NULL;
 353      CFDataRef EncodingParameters = NULL;
 354      CFErrorRef error = NULL;
 355      UInt8 *raw_seed = NULL, *raw_DB = NULL, *addr01 = NULL;
 356      SecTransformRef mgf_maskedDB = NULL, mgf_dbMask = NULL, hash = NULL;
 357      int hLen = -1;
 358  	// RSA's OAEP documentation assumes the crypto layer will remove the leading (partial) byte,
 359  	// but CDSA leaves that responsability to us (we did ask it for "no padding" after all).
 360  	// (use extraPaddingLength = 0 when using a layer that does strip that byte)
 361      const int extraPaddingLength = 1;
 362  
 363  	// The numbered steps below correspond to RSA Laboratories' RSAES-OAEP Encryption Scheme
 364  	// document's numbered steps.
 365  
 366      // NOTE: we omit step 1: "If the length of P is greater than the input limitation for the hash
 367      // function (2^61 − 1 octets for SHA-1) then output ‘‘decoding error’’ and stop."; we don't have
 368      // ready access to the input limits of the hash functions, and in the real world we won't be
 369      // seeing messages that long anyway.
 370  
 371      // (2) If emLen < 2hLen + 1, output ‘‘decoding error’’ and stop.
 372      hashAlgo = (CFStringRef)this->GetAttribute(kSecOAEPMGF1DigestAlgorithmAttributeName);
 373  	if (hashAlgo == NULL) {
 374  		hashAlgo = kSecDigestSHA1;
 375  	}
 376      hLen = Digest::LengthForType(hashAlgo);
 377      if (CFDataGetLength(encodedMessage) < 2*hLen + 1) {
 378          goto out;
 379      }
 380  
 381      // (3) Let maskedSeed be the first hLen octets of EM and let maskedDB be the remaining emLen−hLen
 382      // octets.
 383      maskedSeed = CFDataCreateWithBytesNoCopy(NULL, CFDataGetBytePtr(encodedMessage) +extraPaddingLength, hLen, kCFAllocatorNull);
 384      maskedDB = CFDataCreateWithBytesNoCopy(NULL, CFDataGetBytePtr(encodedMessage) + hLen +extraPaddingLength, CFDataGetLength(encodedMessage) - hLen -extraPaddingLength, kCFAllocatorNull);
 385  
 386      // (4) Let seedMask = MGF(maskedDB, hLen).
 387      mgf_maskedDB = SecCreateMaskGenerationFunctionTransform(hashAlgo, hLen, &error);
 388      if (!mgf_maskedDB) {
 389          goto out;
 390      }
 391      if (!SecTransformSetAttribute(mgf_maskedDB, kSecTransformInputAttributeName, maskedDB, &error)) {
 392          goto out;
 393      }
 394      seedMask = (CFDataRef)SecTransformExecute(mgf_maskedDB, &error);
 395      if (!seedMask) {
 396          goto out;
 397      }
 398  	(void)transforms_assume(hLen == CFDataGetLength(seedMask));
 399  
 400      // (5) Let seed = maskedSeed ⊕ seedMask.
 401      raw_seed = (UInt8*)malloc(hLen);
 402      xor_bytes(raw_seed, CFDataGetBytePtr(maskedSeed), CFDataGetBytePtr(seedMask), hLen);
 403      seed = CFDataCreateWithBytesNoCopy(NULL, raw_seed, hLen, kCFAllocatorNull);
 404      if (!seed) {
 405  		free(raw_seed);
 406  		error = GetNoMemoryErrorAndRetain();
 407  		goto out;
 408  	}
 409      // (6) Let dbMask = MGF (seed, emLen − hLen).
 410      mgf_dbMask = SecCreateMaskGenerationFunctionTransform(hashAlgo, CFDataGetLength(encodedMessage) - hLen, &error);
 411      if (!mgf_dbMask) {
 412          goto out;
 413      }
 414      if (!SecTransformSetAttribute(mgf_dbMask, kSecTransformInputAttributeName, seed, &error)) {
 415          goto out;
 416      }
 417      dbMask = (CFDataRef)SecTransformExecute(mgf_dbMask, &error);
 418      if (!dbMask) {
 419          goto out;
 420      }
 421  
 422      // (7) Let DB = maskedDB ⊕ dbMask.
 423      raw_DB = (UInt8*)malloc(CFDataGetLength(dbMask));
 424      xor_bytes(raw_DB, CFDataGetBytePtr(maskedDB), CFDataGetBytePtr(dbMask), CFDataGetLength(dbMask));
 425  
 426      // (8) Let pHash = Hash(P), an octet string of length hLen.
 427      hash = SecDigestTransformCreate(hashAlgo, 0, &error);
 428  	if (!hash) {
 429  		goto out;
 430  	}
 431      EncodingParameters = (CFDataRef)this->GetAttribute(kSecOAEPEncodingParametersAttributeName);
 432  	if (EncodingParameters) {
 433  		CFRetain(EncodingParameters);
 434  	} else {
 435  		EncodingParameters = CFDataCreate(NULL, (UInt8*)"", 0);
 436  		if (!EncodingParameters) {
 437  			goto out;
 438  		}
 439  	}
 440  	if (!SecTransformSetAttribute(hash, kSecTransformInputAttributeName, EncodingParameters, &error)) {
 441  		goto out;
 442  	}
 443  
 444  	pHash = (CFDataRef)transforms_assume(SecTransformExecute(hash, &error));
 445  	if (!pHash) {
 446  		goto out;
 447  	}
 448  	(void)transforms_assume(hLen == CFDataGetLength(pHash));
 449  
 450  
 451      // (9) Separate DB into an octet string pHash’ consisting of the first hLen octets of DB, a
 452      // (possibly empty) octet string PS consisting of consecutive zero octets following pHash’,
 453      // and a message M as If there is no 01 octet to separate PS from M , output ‘‘decoding error’’ and stop.
 454      pHashPrime = CFDataCreateWithBytesNoCopy(NULL, raw_DB, hLen, kCFAllocatorNull);
 455      if (CFEqual(pHash, pHashPrime)) {
 456          addr01 = (UInt8*)memchr(raw_DB + hLen, 0x01, CFDataGetLength(dbMask) - hLen);
 457          if (!addr01) {
 458              goto out;
 459          }
 460          message = CFDataCreate(NULL, addr01 + 1, (CFDataGetLength(dbMask) - ((addr01 - raw_DB) + 1)) -extraPaddingLength);
 461      } else {
 462          // (10) If pHash’ does not equal pHash, output ‘‘decoding error’’ and stop.
 463          goto out;
 464      }
 465  
 466  out:
 467      if (!message) {
 468          if (!error) {
 469              error = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "decoding error");
 470          }
 471          SetAttributeNoCallback(kSecTransformOutputAttributeName, error);
 472      }
 473  
 474  	// Release eveything except:
 475  	//	hashAlgo (obtained via get)
 476  	//	message (return value)
 477  	CFSafeRelease(maskedSeed);
 478  	CFSafeRelease(maskedDB);
 479  	CFSafeRelease(seedMask);
 480  	CFSafeRelease(seed);
 481  	CFSafeRelease(dbMask);
 482  	CFSafeRelease(pHash);
 483  	CFSafeRelease(pHashPrime);
 484  	CFSafeRelease(mgf_dbMask);
 485  	CFSafeRelease(mgf_maskedDB);
 486  	CFSafeRelease(hash);
 487  	CFSafeRelease(EncodingParameters);
 488  	// raw_seed is free'd via CFData, addr01 was never allocated, so raw_DB is our lot
 489  	free(raw_DB);
 490  
 491      // (11) Output M.
 492      return message;
 493  #endif
 494  }
 495  
 496  extern "C" {
 497  	extern CFDataRef oaep_padding_via_c(int desired_message_length, CFDataRef dataValue);
 498  }
 499  
 500  CFDataRef EncryptDecryptBase::apply_oaep_padding(CFDataRef dataValue)
 501  {
 502  #if 1
 503  	// MGF1 w/ SHA1 assumed here
 504  
 505  	CFErrorRef error = NULL;
 506  	int hLen = Digest::LengthForType(kSecDigestSHA1);
 507  	CFNumberRef desired_message_length_cf = (CFNumberRef)this->GetAttribute(kSecOAEPMessageLengthAttributeName);
 508  	int desired_message_length = 0;
 509  	CSSM_QUERY_SIZE_DATA RSA_size;
 510  	CFDataRef EM = NULL;
 511  
 512  	if (desired_message_length_cf) {
 513  		CFNumberGetValue(desired_message_length_cf, kCFNumberIntType, &desired_message_length);
 514  	} else {
 515  		// take RSA (or whatever crypto) block size onto account too
 516  		RSA_size.SizeInputBlock = (uint32)(CFDataGetLength(dataValue) + 2*hLen +1);
 517  		RSA_size.SizeOutputBlock = 0;
 518  		OSStatus status = CSSM_QuerySize(m_handle, CSSM_TRUE, 1, &RSA_size);
 519  		if (status != errSecSuccess) {
 520  			CFStringRef errorString = SecCopyErrorMessageString(status, NULL);
 521  			error = CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "CDSA error (%@).", errorString);
 522  			CFReleaseNull(errorString);
 523  			SetAttributeNoCallback(kSecTransformOutputAttributeName, error);
 524  			(void)transforms_assume_zero(EM);
 525  			return EM;
 526  		}
 527  		(void)transforms_assume(RSA_size.SizeInputBlock <= RSA_size.SizeOutputBlock);
 528  		desired_message_length = RSA_size.SizeOutputBlock;
 529  	}
 530  	CFDataRef returnData = oaep_padding_via_c(desired_message_length, dataValue);
 531  	return returnData;
 532  
 533  #else
 534  	CFDataRef seed = NULL, dbMask = NULL, maskedDB = NULL, seedMask = NULL, padHash = NULL, padZeros = NULL;
 535      CFDataRef EncodingParameters = NULL;
 536  	CFMutableDataRef EM = NULL, dataBlob = NULL;
 537  	CFNumberRef desired_message_length_cf = NULL;
 538  	CFErrorRef error = NULL;
 539  	CFStringRef hashAlgo = NULL;
 540  	UInt8 *raw_padZeros = NULL, *raw_seed = NULL, *raw_maskedSeed = NULL, *raw_maskedDB = NULL;
 541  	SecTransformRef mgf_dbMask = NULL, mgf_seedMask = NULL, hash = NULL;
 542  	CFIndex paddingNeeded = -1, padLen = -1;
 543  	int hLen = -1;
 544  	CSSM_QUERY_SIZE_DATA RSA_size;
 545  
 546  	// NOTE: we omit (1) If the length of P is greater than the input limitation for the hash function
 547  	// (2^61 − 1 octets for SHA-1) then output ‘‘parameter string too long’’ and stop.
 548  	// We don't have ready access to the input limit of the hash functions, and in the real world
 549  	// we won't be seeing a message that long anyway.
 550  
 551  	// (2) If mLen > emLen − 2hLen − 1, output ‘‘message too long’’ and stop.
 552  	hashAlgo = (CFStringRef)this->GetAttribute(kSecOAEPMGF1DigestAlgorithmAttributeName);
 553  	if (hashAlgo == NULL) {
 554  		hashAlgo = kSecDigestSHA1;
 555  	}
 556  	hLen = Digest::LengthForType(hashAlgo);
 557  	desired_message_length_cf = (CFNumberRef)this->GetAttribute(kSecOAEPMessageLengthAttributeName);
 558  	int desired_message_length = 0;
 559  	if (desired_message_length_cf) {
 560  		CFNumberGetValue(desired_message_length_cf, kCFNumberIntType, &desired_message_length);
 561  	} else {
 562  		// take RSA (or whatever crypto) block size onto account too
 563  		RSA_size.SizeInputBlock = CFDataGetLength(dataValue) + 2*hLen +1;
 564  		RSA_size.SizeOutputBlock = 0;
 565  		OSStatus status = CSSM_QuerySize(m_handle, CSSM_TRUE, 1, &RSA_size);
 566  		if (status != errSecSuccess) {
 567  			CFStringRef errorString = SecCopyErrorMessageString(status, NULL);
 568  			error = CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "CDSA error (%@).", errorString);
 569  			CFReleaseNull(errorString);
 570  			goto out;
 571  		}
 572  		(void)transforms_assume(RSA_size.SizeInputBlock <= RSA_size.SizeOutputBlock);
 573  		desired_message_length = RSA_size.SizeOutputBlock -1;
 574  	}
 575  	padLen = (desired_message_length - (2*hLen) -1) - CFDataGetLength(dataValue);
 576  	if (padLen < 0) {
 577  		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);
 578          goto out;
 579  	}
 580  
 581  	// (3) Generate an octet string PS consisting of emLen − mLen − 2hLen − 1 zero octets. The length of PS may be 0.
 582  	raw_padZeros = (UInt8*)calloc(padLen, 1);
 583  	if (!raw_padZeros) {
 584  		error = GetNoMemoryErrorAndRetain();
 585  		goto out;
 586  	}
 587  	padZeros = CFDataCreateWithBytesNoCopy(NULL, raw_padZeros, padLen, kCFAllocatorMalloc);
 588  	if (!padZeros) {
 589  		free(raw_padZeros);
 590  		error = GetNoMemoryErrorAndRetain();
 591  		goto out;
 592  	}
 593  
 594  	// (4) Let pHash = Hash(P), an octet string of length hLen.
 595  	hash = SecDigestTransformCreate(hashAlgo, 0, &error);
 596  	if (!hash) {
 597  		goto out;
 598  	}
 599      EncodingParameters = (CFDataRef)this->GetAttribute(kSecOAEPEncodingParametersAttributeName);
 600  	if (EncodingParameters) {
 601  		CFRetain(EncodingParameters);
 602  	} else {
 603  		EncodingParameters = CFDataCreate(NULL, (UInt8*)"", 0);
 604  		if (!EncodingParameters) {
 605  			error = GetNoMemoryErrorAndRetain();
 606  			goto out;
 607  		}
 608  	}
 609  	if (!SecTransformSetAttribute(hash, kSecTransformInputAttributeName, EncodingParameters, &error)) {
 610  		goto out;
 611  	}
 612  
 613  	padHash = (CFDataRef)transforms_assume(SecTransformExecute(hash, &error));
 614  	if (!padHash) {
 615  		goto out;
 616  	}
 617  	(void)transforms_assume(hLen == CFDataGetLength(padHash));
 618  
 619  	// (5) Concatenate pHash,PS, the message M, and other padding to form a data block DB as DB = pHash∥PS∥01∥M.
 620  	dataBlob = CFDataCreateMutable(NULL, CFDataGetLength(padHash) + padLen + 1 + CFDataGetLength(dataValue));
 621  	if (!dataBlob) {
 622  		error = GetNoMemoryErrorAndRetain();
 623  		goto out;
 624  	}
 625  	CFDataAppendBytes(dataBlob, CFDataGetBytePtr(padHash), hLen);
 626  	CFDataAppendBytes(dataBlob, raw_padZeros, padLen);
 627  	CFDataAppendBytes(dataBlob, (UInt8*)"\01", 1);
 628  	CFDataAppendBytes(dataBlob, CFDataGetBytePtr(dataValue), CFDataGetLength(dataValue));
 629  
 630  	// (6) Generate a random octet string seed of length hLen.
 631  	seed = (CFDataRef)this->GetAttribute(CFSTR("FixedSeedForOAEPTesting"));
 632  	raw_seed = NULL;
 633  	if (seed) {
 634  		(void)transforms_assume(hLen == CFDataGetLength(seed));
 635  		CFRetain(seed);
 636  	} else {
 637  		seed = SecRandomCopyData(kSecRandomDefault, hLen);
 638  		if (!seed) {
 639  			error = GetNoMemoryErrorAndRetain();
 640  			goto out;
 641  		}
 642  	}
 643      raw_seed = (UInt8*)CFDataGetBytePtr(seed);
 644  
 645  	// (7) Let dbMask = MGF (seed, emLen − hLen).
 646  	mgf_dbMask = transforms_assume(SecCreateMaskGenerationFunctionTransform(hashAlgo, desired_message_length - hLen, &error));
 647  	if (!mgf_dbMask) {
 648  		goto out;
 649  	}
 650  	if (!SecTransformSetAttribute(mgf_dbMask, kSecTransformInputAttributeName, seed, &error)) {
 651  		goto out;
 652  	}
 653  	dbMask = (CFDataRef)SecTransformExecute(mgf_dbMask, &error);
 654  
 655  	// (8) Let maskedDB = DB ⊕ dbMask.
 656  	// NOTE: we do some allocations above...you know, we should be able to malloc ONE buffer of the
 657  	// proper size.
 658  	raw_maskedDB = (UInt8 *)malloc(CFDataGetLength(dbMask));
 659  	if (!raw_maskedDB) {
 660  		error = GetNoMemoryErrorAndRetain();
 661  		goto out;
 662  	}
 663  	xor_bytes(raw_maskedDB, CFDataGetBytePtr(dbMask), CFDataGetBytePtr(dataBlob), CFDataGetLength(dbMask));
 664  	maskedDB = CFDataCreateWithBytesNoCopy(NULL, raw_maskedDB, CFDataGetLength(dataBlob), kCFAllocatorMalloc);
 665  	if (!maskedDB) {
 666  		free(raw_maskedDB);
 667  		error = GetNoMemoryErrorAndRetain();
 668  		goto out;
 669  	}
 670  
 671  	// (9) Let seedMask = MGF(maskedDB, hLen).
 672  	mgf_seedMask = transforms_assume(SecCreateMaskGenerationFunctionTransform(hashAlgo, hLen, &error));
 673  	if (!mgf_seedMask) {
 674  		goto out;
 675  	}
 676  	if (!SecTransformSetAttribute(mgf_seedMask, kSecTransformInputAttributeName, maskedDB, &error)) {
 677  		goto out;
 678  	}
 679  	seedMask = transforms_assume((CFDataRef)SecTransformExecute(mgf_seedMask, &error));
 680  	if (!seedMask) {
 681  		goto out;
 682  	}
 683  
 684  	// (10) Let maskedSeed = seed ⊕ seedMask
 685  	raw_maskedSeed = (UInt8 *)malloc(hLen);
 686  	if (!raw_maskedSeed) {
 687  		error = GetNoMemoryErrorAndRetain();
 688  		goto out;
 689  	}
 690  	xor_bytes(raw_maskedSeed, raw_seed, CFDataGetBytePtr(seedMask), hLen);
 691  
 692  	// (11) Let EM = maskedSeed∥maskedDB (if we didn't have to pushback the NULL we could do this without physically concatanating)
 693  	// (figure out amount of leading zero padding we need)
 694  	RSA_size.SizeInputBlock = hLen + CFDataGetLength(maskedDB);
 695  	CSSM_QuerySize(m_handle, CSSM_TRUE, 1, &RSA_size);
 696  	paddingNeeded = RSA_size.SizeOutputBlock - RSA_size.SizeInputBlock;
 697  	(void)transforms_assume(paddingNeeded >= 0);
 698  
 699  	EM = CFDataCreateMutable(NULL, CFDataGetLength(maskedDB) + hLen + paddingNeeded);
 700  	if (!EM) {
 701  		error = GetNoMemoryErrorAndRetain();
 702  		goto out;
 703  	}
 704  	while(paddingNeeded--) {
 705  		CFDataAppendBytes(EM, (UInt8*)"", 1);
 706  	}
 707  
 708  	CFDataAppendBytes(EM, raw_maskedSeed, hLen);
 709  	CFDataAppendBytes(EM, raw_maskedDB, CFDataGetLength(maskedDB));
 710  out:
 711  	if (error) {
 712  		SetAttributeNoCallback(kSecTransformOutputAttributeName, error);
 713  		(void)transforms_assume_zero(EM);
 714  	}
 715  
 716  	CFSafeRelease(seed); // via get??
 717  	CFSafeRelease(dbMask);
 718  	CFSafeRelease(maskedDB);
 719  	CFSafeRelease(seedMask);
 720  	CFSafeRelease(padHash);
 721  	CFSafeRelease(padZeros);
 722  	CFSafeRelease(EncodingParameters);
 723  	CFSafeRelease(dataBlob);
 724  	// desired_message_length_cf -- via get
 725  	// hashAlgo -- via get
 726  	CFSafeRelease(mgf_dbMask);
 727  	CFSafeRelease(mgf_seedMask);
 728  	CFSafeRelease(hash);
 729  	// raw_* are all freed by their associated CFDatas, except raw_maskedSeed
 730  	free(raw_maskedSeed);
 731  
 732  	// (12) Output EM.
 733  	return EM;
 734  #endif
 735  }
 736  
 737  /* --------------------------------------------------------------------------
 738   method: 		AttributeChanged
 739   description: 	deal with input
 740   -------------------------------------------------------------------------- */
 741  void EncryptDecryptBase::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef value)
 742  {
 743  	// sanity check our arguments
 744  	if (ah != inputAH)
 745  	{
 746  		return; // we only deal with input
 747  	}
 748  
 749  	if (value != NULL)
 750  	{
 751  		CFTypeID valueType = CFGetTypeID(value);
 752  		if (valueType != CFDataGetTypeID())
 753  		{
 754  			CFStringRef realType = CFCopyTypeIDDescription(valueType);
 755  			CFErrorRef error = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "Value is not a CFDataRef -- this one is a %@", realType);
 756  			CFReleaseNull(realType);
 757  			SetAttributeNoCallback(kSecTransformOutputAttributeName, error);
 758  			return;
 759  		}
 760  
 761  		if (m_forEncryption && m_accumulator) {
 762  			CFDataRef d = (CFDataRef)value;
 763  			CFDataAppendBytes(m_accumulator, CFDataGetBytePtr(d), CFDataGetLength(d));
 764  			return;
 765  		}
 766  	}
 767  
 768  	if (m_forEncryption && m_accumulator) {
 769  		(void)transforms_assume_zero(value);
 770  		value = m_accumulator;
 771  		m_accumulator = NULL;
 772  		dispatch_async(this->mDispatchQueue, ^{
 773  			CFSafeRelease(value);
 774  		});
 775  		this->Pushback(inputAH, NULL);
 776  
 777          if (m_oaep_padding) {
 778  			value = apply_oaep_padding((CFDataRef)value);
 779  			dispatch_async(this->mDispatchQueue, ^{
 780  				CFSafeRelease(value);
 781  			});
 782          }
 783  	}
 784  
 785  	// add the input to our cryptor
 786  	CFDataRef valueRef = (CFDataRef) value;
 787  	CSSM_RETURN	crtn = CSSM_OK;
 788  	Boolean inFinal = FALSE;
 789  
 790  	if (valueRef != NULL)
 791  	{
 792  		// Convert to A CSSM_DATA
 793  		CSSM_DATA dataStruct;
 794  		dataStruct.Length = CFDataGetLength(valueRef);
 795          dataStruct.Data = const_cast<uint8_t*>(CFDataGetBytePtr(valueRef));
 796  
 797  		CSSM_DATA intermediateDataStruct;
 798  		memset(&intermediateDataStruct, 0, sizeof(intermediateDataStruct));
 799  
 800  		CSSM_SIZE bytesProcessed = 0;
 801  
 802  		if (m_forEncryption)
 803  		{
 804  			crtn = CSSM_EncryptDataUpdate(m_handle,
 805  										  &dataStruct,
 806  										  1,
 807  										  &intermediateDataStruct,
 808  										  1,
 809  										  &bytesProcessed);
 810  		}
 811  		else
 812  		{
 813  			crtn = CSSM_DecryptDataUpdate(m_handle,
 814  										  &dataStruct,
 815  										  1,
 816  										  &intermediateDataStruct,
 817  										  1,
 818  										  &bytesProcessed);
 819  		}
 820  
 821  		if (CSSM_OK != crtn)
 822  		{
 823  			SendCSSMError(crtn);
 824  			return;
 825  		}
 826  
 827  
 828  		if (intermediateDataStruct.Length > 0)
 829  		{
 830  			if (NULL == m_processedData)
 831  			{
 832  				m_processedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
 833  			}
 834  
 835  			CFDataAppendBytes(m_processedData, intermediateDataStruct.Data, bytesProcessed);
 836  			free(intermediateDataStruct.Data);
 837  		}
 838  	}
 839  	else
 840  	{
 841  		// Finalize
 842  
 843  		inFinal = TRUE;
 844  		CSSM_DATA remData;
 845  		memset(&remData, 0, sizeof(remData));
 846  
 847  		crtn = (m_forEncryption) ? CSSM_EncryptDataFinal(m_handle, &remData) : CSSM_DecryptDataFinal(m_handle, &remData);
 848  
 849  		if (CSSM_OK == crtn)
 850  		{
 851              if (m_forEncryption == false && m_accumulator) {
 852                  (void)transforms_assume_zero(m_processedData);
 853                  if (remData.Length > 0) {
 854                      CFDataAppendBytes(m_accumulator, remData.Data, remData.Length);
 855                  }
 856              } else {
 857                  if (NULL == m_processedData)
 858                  {
 859                      m_processedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
 860                  }
 861  
 862                  if (remData.Length > 0)
 863                  {
 864                      CFDataAppendBytes(m_processedData, remData.Data, remData.Length);
 865                  }
 866              }
 867  		}
 868  
 869  		free(remData.Data);
 870  
 871  		if (CSSM_OK != crtn)
 872  		{
 873  			SendCSSMError(crtn);
 874  			return;
 875  		}
 876  	}
 877  
 878  	if (NULL != m_processedData)
 879  	{
 880          SendAttribute(kSecTransformOutputAttributeName, m_processedData);
 881  		CFReleaseNull(m_processedData);
 882  		m_processedData = NULL;
 883  	}
 884  
 885  	if (inFinal)
 886  	{
 887          if (m_oaep_padding && m_forEncryption == false) {
 888              CFTypeRef unpadded = remove_oaep_padding(m_accumulator);
 889              SendAttribute(kSecTransformOutputAttributeName, unpadded);
 890              CFReleaseNull(unpadded);
 891          }
 892  		SendAttribute(kSecTransformOutputAttributeName, NULL);
 893  	}
 894  
 895  
 896  }
 897  
 898  /* --------------------------------------------------------------------------
 899   method: 		CopyState
 900   description: 	Copy the current state of this transform
 901   -------------------------------------------------------------------------- */
 902  CFDictionaryRef EncryptDecryptBase::CopyState()
 903  {
 904  	// make a dictionary for our state
 905  	CFMutableDictionaryRef state = (CFMutableDictionaryRef) CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 906  	CFStringRef paddingStr = (CFStringRef) GetAttribute(kSecPaddingKey);
 907  	CFStringRef modeStr = (CFStringRef) GetAttribute (kSecEncryptionMode);
 908  	CFDataRef ivData = (CFDataRef) GetAttribute(kSecIVKey);
 909  	if (NULL != paddingStr)
 910  	{
 911  		CFDictionaryAddValue(state, kSecPaddingKey, paddingStr);
 912  	}
 913  
 914  	if (NULL != modeStr)
 915  	{
 916  		CFDictionaryAddValue(state, kSecEncryptionMode, modeStr);
 917  	}
 918  
 919  	if (NULL != ivData)
 920  	{
 921  		CFDictionaryAddValue(state, kSecIVKey, ivData);
 922  	}
 923  
 924  	return state;
 925  }
 926  
 927  /* --------------------------------------------------------------------------
 928   method: 		RestoreState
 929   description: 	Restore the state of this transform from a dictionary
 930   -------------------------------------------------------------------------- */
 931  void EncryptDecryptBase::RestoreState(CFDictionaryRef state)
 932  {
 933  	if (NULL == state)
 934  	{
 935  		return;
 936  	}
 937  
 938  	CFStringRef paddingStr = (CFStringRef)CFDictionaryGetValue(state, kSecPaddingKey);
 939  	CFStringRef modeStr = (CFStringRef)CFDictionaryGetValue(state, kSecEncryptionMode);
 940  	CFDataRef ivData = (CFDataRef)CFDictionaryGetValue(state, kSecIVKey);
 941  
 942  	if (NULL != paddingStr)
 943  	{
 944  		SetAttribute(kSecPaddingKey, paddingStr);
 945  	}
 946  
 947  	if (NULL != modeStr)
 948  	{
 949  		SetAttribute(kSecEncryptionMode, modeStr);
 950  	}
 951  
 952  	if (NULL != ivData)
 953  	{
 954  		SetAttribute(kSecIVKey, ivData);
 955  	}
 956  
 957  }
 958  
 959  /* --------------------------------------------------------------------------
 960   Implementation of the EncryptTransform
 961   -------------------------------------------------------------------------- */
 962  
 963  /* --------------------------------------------------------------------------
 964   method: 		EncryptTransform (Constructor)
 965   description: 	Make a new EncryptTransform
 966   -------------------------------------------------------------------------- */
 967  EncryptTransform::EncryptTransform() : EncryptDecryptBase(kEncryptTransformType)
 968  {
 969  }
 970  
 971  /* --------------------------------------------------------------------------
 972   method: 		~EncryptTransform (Destructor)
 973   description: 	Clean up the memory of anEncryptTransform
 974   -------------------------------------------------------------------------- */
 975  EncryptTransform::~EncryptTransform()
 976  {
 977  }
 978  
 979  /* --------------------------------------------------------------------------
 980   method: 		[static] Make
 981   description: 	Make a new instance of this class
 982   -------------------------------------------------------------------------- */
 983  SecTransformRef EncryptTransform::Make()
 984  {
 985  	EncryptTransform* tr = new EncryptTransform();
 986  	SecTransformRef str = (SecTransformRef) CoreFoundationHolder::MakeHolder(kEncryptTransformType, tr);
 987  	return str;
 988  }
 989  
 990  /* --------------------------------------------------------------------------
 991   Interface and implementation of the EncryptTransformFactory
 992   -------------------------------------------------------------------------- */
 993  
 994  class EncryptTransformFactory : public TransformFactory
 995  {
 996  public:
 997  	EncryptTransformFactory();
 998  	CFTypeRef Make();
 999  };
1000  
1001  
1002  /* --------------------------------------------------------------------------
1003   method: 		EncryptTransformFactory (Constructor)
1004   description:
1005   -------------------------------------------------------------------------- */
1006  EncryptTransformFactory::EncryptTransformFactory() :
1007  TransformFactory(kEncryptTransformType)
1008  {}
1009  
1010  
1011  /* --------------------------------------------------------------------------
1012   method: 		MakeTransformFactory
1013   description: 	Make an instance of this factory class
1014   -------------------------------------------------------------------------- */
1015  TransformFactory* EncryptTransform::MakeTransformFactory()
1016  {
1017  	return new EncryptTransformFactory;
1018  }
1019  
1020  /* --------------------------------------------------------------------------
1021   method: 		Make
1022   description: 	Create an instance of this class
1023   -------------------------------------------------------------------------- */
1024  CFTypeRef EncryptTransformFactory::Make()
1025  {
1026  	return EncryptTransform::Make();
1027  }
1028  
1029  
1030  /* --------------------------------------------------------------------------
1031   method: 		DecryptTransform (Constructor)
1032   description: 	Make a new DecryptTransform
1033   -------------------------------------------------------------------------- */
1034  DecryptTransform::DecryptTransform() : EncryptDecryptBase(kDecryptTransformType)
1035  {
1036  }
1037  
1038  /* --------------------------------------------------------------------------
1039   method: 		~DecryptTransform (Destructor)
1040   description: 	Clean up the memory of anDecryptTransform
1041   -------------------------------------------------------------------------- */
1042  DecryptTransform::~DecryptTransform()
1043  {
1044  }
1045  
1046  
1047  /* --------------------------------------------------------------------------
1048   method: 		[static] Make
1049   description: 	Make a new instance of this class
1050   -------------------------------------------------------------------------- */
1051  SecTransformRef DecryptTransform::Make()
1052  {
1053  	DecryptTransform* tr = new DecryptTransform();
1054  	SecTransformRef str = (SecTransformRef) CoreFoundationHolder::MakeHolder(kDecryptTransformType, tr);
1055  	return str;
1056  }
1057  
1058  /* --------------------------------------------------------------------------
1059   Interface and implementation of the DecryptTransformFactory
1060   -------------------------------------------------------------------------- */
1061  
1062  class DecryptTransformFactory : public TransformFactory
1063  {
1064  public:
1065  	DecryptTransformFactory();
1066  	CFTypeRef Make();
1067  };
1068  
1069  
1070  /* --------------------------------------------------------------------------
1071   method: 		DecryptTransformFactory (Constructor)
1072   description:
1073   -------------------------------------------------------------------------- */
1074  DecryptTransformFactory::DecryptTransformFactory() :
1075  TransformFactory(kDecryptTransformType)
1076  {}
1077  
1078  
1079  /* --------------------------------------------------------------------------
1080   method: 		MakeTransformFactory
1081   description: 	Make an instance of this factory class
1082   -------------------------------------------------------------------------- */
1083  TransformFactory* DecryptTransform::MakeTransformFactory()
1084  {
1085  	return new DecryptTransformFactory;
1086  }
1087  
1088  /* --------------------------------------------------------------------------
1089   method: 		Make
1090   description: 	Create an instance of this class
1091   -------------------------------------------------------------------------- */
1092  CFTypeRef DecryptTransformFactory::Make()
1093  {
1094  	return DecryptTransform::Make();
1095  }
1096