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