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