]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_transform/lib/EncryptTransform.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_transform / lib / 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/SecRandom.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 CFRelease(m_processedData);
98 m_processedData = NULL;
99 }
100 if (NULL != m_accumulator)
101 {
102 CFRelease(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 CFRelease(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 CFRelease(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 CSSM_DATA initVector;
224 if (hasIVData)
225 {
226 initVector.Length = CFDataGetLength(ivData);
227 initVector.Data = const_cast<uint8_t*>(CFDataGetBytePtr(ivData));
228 }
229 else
230 {
231 initVector.Length = gKeySalt.Length;
232 initVector.Data = (uint8 *)malloc(initVector.Length);
233 initVector.Data = gKeySalt.Data;
234 }
235
236 crtn = CSSM_CSP_CreateSymmetricContext(csp, keyAlg, m_mode, credPtr, m_cssm_key,
237 &initVector, m_cssm_padding, NULL, &m_handle);
238
239 // Need better error here
240 if (crtn != CSSM_OK)
241 {
242 CFStringRef result = SecCopyErrorMessageString(crtn, NULL);
243 CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA error (%@).", result);
244 CFRelease(result);
245 return retValue;
246 }
247 }
248 else
249 {
250 crtn = CSSM_CSP_CreateAsymmetricContext(csp, keyAlg, credPtr, m_cssm_key, m_cssm_padding, &m_handle);
251
252 // Need better error here
253 if (crtn != CSSM_OK)
254 {
255 CFStringRef result = SecCopyErrorMessageString(crtn, NULL);
256 CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA error (%@).", result);
257 CFRelease(result);
258 return retValue;
259 }
260 }
261
262 // Encryption
263 crtn = (m_forEncryption) ? CSSM_EncryptDataInit(m_handle) : CSSM_DecryptDataInit(m_handle);
264 // Need better error here
265 if (crtn != CSSM_OK)
266 {
267 CFStringRef result = SecCopyErrorMessageString(crtn, NULL);
268 CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA encrypt/decrypt init error (%@).", result);
269 CFRelease(result);
270 return retValue;
271 }
272
273
274 return result;
275 }
276
277 /* --------------------------------------------------------------------------
278 method: TransformStartingExecution()
279 description: Get this transform ready to run.
280 NOTE: the encrypt/decrypt setup is not safe to call for a single
281 key from multiple threads at once, TransformStartingExecution is
282 responsable making sure this doesn't happen,
283 SerializedTransformStartingExecution() does the real set up work.
284 -------------------------------------------------------------------------- */
285 CFErrorRef EncryptDecryptBase::TransformStartingExecution()
286 {
287
288 dispatch_once(&serializerSetUp, ^{
289 serializerTransformStartingExecution = dispatch_queue_create("com.apple.security.EncryptDecrypt.key-setup", NULL);
290 });
291
292 __block CFErrorRef result = NULL; // Assume all is well
293
294 dispatch_sync(serializerTransformStartingExecution, ^{
295 result = SerializedTransformStartingExecution();
296 });
297 return result;
298 }
299
300 /* --------------------------------------------------------------------------
301 method: TransformCanExecute
302 description: Do we have a key?
303 -------------------------------------------------------------------------- */
304 Boolean EncryptDecryptBase::TransformCanExecute()
305 {
306 // make sure we have a key -- there may be some circumstance when one isn't available
307 // and besides, it helps test this logic
308 SecKeyRef key = (SecKeyRef) GetAttribute(kSecEncryptKey);
309 return key != NULL;
310 }
311
312 void EncryptDecryptBase::SendCSSMError(CSSM_RETURN retCode)
313 {
314 // make a CFErrorRef for the error message
315 CFStringRef errorString = SecCopyErrorMessageString(retCode, NULL);
316 CFErrorRef errorRef = CreateGenericErrorRef(kCFErrorDomainOSStatus, retCode, "%@", errorString);
317 CFRelease(errorString);
318
319 SendAttribute(kSecTransformOutputAttributeName, errorRef);
320 CFRelease(errorRef);
321 }
322
323 void xor_bytes(UInt8 *dst, const UInt8 *src1, const UInt8 *src2, CFIndex length);
324 void 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
337 extern "C" {
338 extern CFDataRef oaep_unpadding_via_c(CFDataRef encodedMessage);
339 }
340
341 CFDataRef 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
462 out:
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
492 extern "C" {
493 extern CFDataRef oaep_padding_via_c(int desired_message_length, CFDataRef dataValue);
494 }
495
496 CFDataRef 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));
712 out:
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 -------------------------------------------------------------------------- */
743 void 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 -------------------------------------------------------------------------- */
904 CFDictionaryRef 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 -------------------------------------------------------------------------- */
933 void 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 -------------------------------------------------------------------------- */
969 EncryptTransform::EncryptTransform() : EncryptDecryptBase(kEncryptTransformType)
970 {
971 }
972
973 /* --------------------------------------------------------------------------
974 method: ~EncryptTransform (Destructor)
975 description: Clean up the memory of anEncryptTransform
976 -------------------------------------------------------------------------- */
977 EncryptTransform::~EncryptTransform()
978 {
979 }
980
981 /* --------------------------------------------------------------------------
982 method: [static] Make
983 description: Make a new instance of this class
984 -------------------------------------------------------------------------- */
985 SecTransformRef 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
996 class EncryptTransformFactory : public TransformFactory
997 {
998 public:
999 EncryptTransformFactory();
1000 CFTypeRef Make();
1001 };
1002
1003
1004 /* --------------------------------------------------------------------------
1005 method: EncryptTransformFactory (Constructor)
1006 description:
1007 -------------------------------------------------------------------------- */
1008 EncryptTransformFactory::EncryptTransformFactory() :
1009 TransformFactory(kEncryptTransformType)
1010 {}
1011
1012
1013 /* --------------------------------------------------------------------------
1014 method: MakeTransformFactory
1015 description: Make an instance of this factory class
1016 -------------------------------------------------------------------------- */
1017 TransformFactory* EncryptTransform::MakeTransformFactory()
1018 {
1019 return new EncryptTransformFactory;
1020 }
1021
1022 /* --------------------------------------------------------------------------
1023 method: Make
1024 description: Create an instance of this class
1025 -------------------------------------------------------------------------- */
1026 CFTypeRef EncryptTransformFactory::Make()
1027 {
1028 return EncryptTransform::Make();
1029 }
1030
1031
1032 /* --------------------------------------------------------------------------
1033 method: DecryptTransform (Constructor)
1034 description: Make a new DecryptTransform
1035 -------------------------------------------------------------------------- */
1036 DecryptTransform::DecryptTransform() : EncryptDecryptBase(kDecryptTransformType)
1037 {
1038 }
1039
1040 /* --------------------------------------------------------------------------
1041 method: ~DecryptTransform (Destructor)
1042 description: Clean up the memory of anDecryptTransform
1043 -------------------------------------------------------------------------- */
1044 DecryptTransform::~DecryptTransform()
1045 {
1046 }
1047
1048
1049 /* --------------------------------------------------------------------------
1050 method: [static] Make
1051 description: Make a new instance of this class
1052 -------------------------------------------------------------------------- */
1053 SecTransformRef 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
1064 class DecryptTransformFactory : public TransformFactory
1065 {
1066 public:
1067 DecryptTransformFactory();
1068 CFTypeRef Make();
1069 };
1070
1071
1072 /* --------------------------------------------------------------------------
1073 method: DecryptTransformFactory (Constructor)
1074 description:
1075 -------------------------------------------------------------------------- */
1076 DecryptTransformFactory::DecryptTransformFactory() :
1077 TransformFactory(kDecryptTransformType)
1078 {}
1079
1080
1081 /* --------------------------------------------------------------------------
1082 method: MakeTransformFactory
1083 description: Make an instance of this factory class
1084 -------------------------------------------------------------------------- */
1085 TransformFactory* DecryptTransform::MakeTransformFactory()
1086 {
1087 return new DecryptTransformFactory;
1088 }
1089
1090 /* --------------------------------------------------------------------------
1091 method: Make
1092 description: Create an instance of this class
1093 -------------------------------------------------------------------------- */
1094 CFTypeRef DecryptTransformFactory::Make()
1095 {
1096 return DecryptTransform::Make();
1097 }
1098