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