]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_transform/lib/EncryptTransform.cpp
Security-58286.51.6.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/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