2 * Copyright (c) 2010 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include "EncryptTransform.h"
26 #include "SecEncryptTransform.h"
27 #include "EncryptTransformUtilities.h"
28 #include "Utilities.h"
29 #include "SecDigestTransform.h"
31 #include <Security/SecRandom.h>
32 #include "SecMaskGenerationFunctionTransform.h"
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
41 dispatch_once_t
EncryptDecryptBase::serializerSetUp
;
42 dispatch_queue_t
EncryptDecryptBase::serializerTransformStartingExecution
;
44 /* --------------------------------------------------------------------------
45 Implementation of the EncryptDecryptBase class
46 -------------------------------------------------------------------------- */
48 /* --------------------------------------------------------------------------
49 method: EncryptDecryptBase (Constructor)
50 description: Initialize a new instance of a EncryptDecryptBase class
51 -------------------------------------------------------------------------- */
52 EncryptDecryptBase::EncryptDecryptBase(CFStringRef type
) :
54 m_cssm_padding(CSSM_PADDING_NONE
),
55 m_mode(CSSM_ALGMODE_CBCPadIV8
),
57 m_handle((CSSM_CC_HANDLE
)0),
58 m_forEncryption(FALSE
),
59 m_processedData(NULL
),
62 m_forEncryption
= CFEqual(type
, kEncryptTransformType
);
63 inputAH
= transforms_assume(this->getAH(kSecTransformInputAttributeName
, false, false));
66 /* --------------------------------------------------------------------------
67 method: ~EncryptDecryptBase (pre-Destructor)
68 description: Clean m_handle, let Transform::Finalize() do the rest
69 -------------------------------------------------------------------------- */
70 void EncryptDecryptBase::Finalize()
72 if (m_handle
!= (CSSM_CC_HANDLE
)0)
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
78 dispatch_async(mDispatchQueue
, ^{
79 CSSM_DeleteContext(tmp_handle
);
81 m_handle
= ((CSSM_CC_HANDLE
)0);
84 Transform::Finalize();
88 /* --------------------------------------------------------------------------
89 method: ~EncryptDecryptBase (Destructor)
90 description: Clean up the memory of an EncryptDecryptBase object
91 -------------------------------------------------------------------------- */
92 EncryptDecryptBase::~EncryptDecryptBase()
94 if (NULL
!= m_processedData
)
96 CFRelease(m_processedData
);
97 m_processedData
= NULL
;
99 if (NULL
!= m_accumulator
)
101 CFRelease(m_accumulator
);
102 m_accumulator
= NULL
;
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
)
112 SetAttributeNoCallback(kSecEncryptKey
, key
);
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()
128 CFErrorRef result
= NULL
; // Assume all is well
129 SecKeyRef key
= (SecKeyRef
) GetAttribute(kSecEncryptKey
);
132 return CreateSecTransformErrorRef(kSecTransformErrorAttributeNotFound
, "The attribute %@ was not found.", kSecEncryptKey
);
135 OSStatus err
= errSecSuccess
;
136 err
= SecKeyGetCSSMKey(key
, (const CSSM_KEY
**)&m_cssm_key
);
137 if (errSecSuccess
!= err
)
139 CFStringRef result
= SecCopyErrorMessageString(err
, NULL
);
140 CFErrorRef retValue
= CreateSecTransformErrorRef(err
, "CDSA error (%@).", result
);
146 err
= SecKeyGetCSPHandle(key
, &csp
);
147 if (errSecSuccess
!= err
)
149 CFStringRef result
= SecCopyErrorMessageString(err
, NULL
);
150 CFErrorRef retValue
= CreateSecTransformErrorRef(err
, "CDSA error (%@).", result
);
155 CSSM_ALGORITHMS keyAlg
= m_cssm_key
->KeyHeader
.AlgorithmId
;
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
);
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
);
170 if (CSSM_ALGID_RSA
== keyAlg
|| CSSM_ALGID_ECDSA
== keyAlg
)
172 m_cssm_padding
= CSSM_PADDING_PKCS1
;
176 m_cssm_padding
= CSSM_PADDING_PKCS7
;
178 m_oaep_padding
= false;
182 if (CFStringCompare(kSecPaddingOAEPKey
, paddingStr
, kCFCompareAnchored
)) {
183 m_oaep_padding
= false;
184 m_cssm_padding
= ConvertPaddingStringToEnum(paddingStr
);
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();
197 m_mode
= (CSSM_PADDING_NONE
== m_cssm_padding
) ? CSSM_ALGMODE_CBC_IV8
: CSSM_ALGMODE_CBCPadIV8
;
201 m_mode
= ConvertEncryptModeStringToEnum(modeStr
, (CSSM_PADDING_NONE
!= m_cssm_padding
));
205 CSSM_RETURN crtn
= CSSM_OK
;
208 CSSM_DATA initVector
;
211 initVector
.Length
= CFDataGetLength(ivData
);
212 initVector
.Data
= const_cast<uint8_t*>(CFDataGetBytePtr(ivData
));
216 initVector
.Length
= gKeySalt
.Length
;
217 initVector
.Data
= (uint8
*)malloc(initVector
.Length
);
218 initVector
.Data
= gKeySalt
.Data
;
221 crtn
= CSSM_CSP_CreateSymmetricContext(csp
, keyAlg
, m_mode
, NULL
, m_cssm_key
,
222 &initVector
, m_cssm_padding
, NULL
, &m_handle
);
224 // Need better error here
227 CFStringRef result
= SecCopyErrorMessageString(crtn
, NULL
);
228 CFErrorRef retValue
= CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly
, "CDSA error (%@).", result
);
236 CSSM_ACCESS_CREDENTIALS creds
;
237 CSSM_ACCESS_CREDENTIALS
* credPtr
= NULL
;
238 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
240 err
= SecKeyGetCredentials(key
,
241 (m_forEncryption
) ? CSSM_ACL_AUTHORIZATION_ENCRYPT
: CSSM_ACL_AUTHORIZATION_DECRYPT
,
242 kSecCredentialTypeDefault
,
243 (const CSSM_ACCESS_CREDENTIALS
**)&credPtr
);
245 if (errSecSuccess
!= err
)
247 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
252 crtn
= CSSM_CSP_CreateAsymmetricContext(csp
, keyAlg
, credPtr
, m_cssm_key
, m_cssm_padding
, &m_handle
);
253 // Need better error here
256 CFStringRef result
= SecCopyErrorMessageString(crtn
, NULL
);
257 CFErrorRef retValue
= CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly
, "CDSA error (%@).", result
);
264 crtn
= (m_forEncryption
) ? CSSM_EncryptDataInit(m_handle
) : CSSM_DecryptDataInit(m_handle
);
265 // Need better error here
268 CFStringRef result
= SecCopyErrorMessageString(crtn
, NULL
);
269 CFErrorRef retValue
= CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly
, "CDSA encrypt/decrypt init error (%@).", result
);
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()
289 dispatch_once(&serializerSetUp
, ^{
290 serializerTransformStartingExecution
= dispatch_queue_create("com.apple.security.EncryptDecrypt.key-setup", NULL
);
293 __block CFErrorRef result
= NULL
; // Assume all is well
295 dispatch_sync(serializerTransformStartingExecution
, ^{
296 result
= SerializedTransformStartingExecution();
301 /* --------------------------------------------------------------------------
302 method: TransformCanExecute
303 description: Do we have a key?
304 -------------------------------------------------------------------------- */
305 Boolean
EncryptDecryptBase::TransformCanExecute()
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
);
313 void EncryptDecryptBase::SendCSSMError(CSSM_RETURN retCode
)
315 // make a CFErrorRef for the error message
316 CFStringRef errorString
= SecCopyErrorMessageString(retCode
, NULL
);
317 CFErrorRef errorRef
= CreateGenericErrorRef(kCFErrorDomainOSStatus
, retCode
, "%@", errorString
);
318 CFRelease(errorString
);
320 SendAttribute(kSecTransformOutputAttributeName
, errorRef
);
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
)
328 // NOTE: this can be made faster, but see if we already have a faster version somewhere first.
330 // _mm_xor_ps would be nice here
331 // failing that, getting to an aligned boundry and switching to uint64_t
335 *dst
++ = *src1
++ ^ *src2
++;
340 extern CFDataRef
oaep_unpadding_via_c(CFDataRef encodedMessage
);
343 CFDataRef
EncryptDecryptBase::remove_oaep_padding(CFDataRef encodedMessage
)
346 return oaep_unpadding_via_c(encodedMessage
);
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
;
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;
361 // The numbered steps below correspond to RSA Laboratories' RSAES-OAEP Encryption Scheme
362 // document's numbered steps.
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.
369 // (2) If emLen < 2hLen + 1, output ‘‘decoding error’’ and stop.
370 hashAlgo
= (CFStringRef
)this->GetAttribute(kSecOAEPMGF1DigestAlgorithmAttributeName
);
371 if (hashAlgo
== NULL
) {
372 hashAlgo
= kSecDigestSHA1
;
374 hLen
= Digest::LengthForType(hashAlgo
);
375 if (CFDataGetLength(encodedMessage
) < 2*hLen
+ 1) {
379 // (3) Let maskedSeed be the first hLen octets of EM and let maskedDB be the remaining emLen−hLen
381 maskedSeed
= CFDataCreateWithBytesNoCopy(NULL
, CFDataGetBytePtr(encodedMessage
) +extraPaddingLength
, hLen
, kCFAllocatorNull
);
382 maskedDB
= CFDataCreateWithBytesNoCopy(NULL
, CFDataGetBytePtr(encodedMessage
) + hLen
+extraPaddingLength
, CFDataGetLength(encodedMessage
) - hLen
-extraPaddingLength
, kCFAllocatorNull
);
384 // (4) Let seedMask = MGF(maskedDB, hLen).
385 mgf_maskedDB
= SecCreateMaskGenerationFunctionTransform(hashAlgo
, hLen
, &error
);
389 if (!SecTransformSetAttribute(mgf_maskedDB
, kSecTransformInputAttributeName
, maskedDB
, &error
)) {
392 seedMask
= (CFDataRef
)SecTransformExecute(mgf_maskedDB
, &error
);
396 (void)transforms_assume(hLen
== CFDataGetLength(seedMask
));
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
);
404 error
= GetNoMemoryErrorAndRetain();
407 // (6) Let dbMask = MGF (seed, emLen − hLen).
408 mgf_dbMask
= SecCreateMaskGenerationFunctionTransform(hashAlgo
, CFDataGetLength(encodedMessage
) - hLen
, &error
);
412 if (!SecTransformSetAttribute(mgf_dbMask
, kSecTransformInputAttributeName
, seed
, &error
)) {
415 dbMask
= (CFDataRef
)SecTransformExecute(mgf_dbMask
, &error
);
420 // (7) Let DB = maskedDB ⊕ dbMask.
421 raw_DB
= (UInt8
*)malloc(CFDataGetLength(dbMask
));
422 xor_bytes(raw_DB
, CFDataGetBytePtr(maskedDB
), CFDataGetBytePtr(dbMask
), CFDataGetLength(dbMask
));
424 // (8) Let pHash = Hash(P), an octet string of length hLen.
425 hash
= SecDigestTransformCreate(hashAlgo
, 0, &error
);
429 EncodingParameters
= (CFDataRef
)this->GetAttribute(kSecOAEPEncodingParametersAttributeName
);
430 if (EncodingParameters
) {
431 CFRetain(EncodingParameters
);
433 EncodingParameters
= CFDataCreate(NULL
, (UInt8
*)"", 0);
434 if (!EncodingParameters
) {
438 if (!SecTransformSetAttribute(hash
, kSecTransformInputAttributeName
, EncodingParameters
, &error
)) {
442 pHash
= (CFDataRef
)transforms_assume(SecTransformExecute(hash
, &error
));
446 (void)transforms_assume(hLen
== CFDataGetLength(pHash
));
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
);
458 message
= CFDataCreate(NULL
, addr01
+ 1, (CFDataGetLength(dbMask
) - ((addr01
- raw_DB
) + 1)) -extraPaddingLength
);
460 // (10) If pHash’ does not equal pHash, output ‘‘decoding error’’ and stop.
467 error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
, "decoding error");
469 SetAttributeNoCallback(kSecTransformOutputAttributeName
, error
);
472 // Release eveything except:
473 // hashAlgo (obtained via get)
474 // message (return value)
475 CFSafeRelease(maskedSeed
);
476 CFSafeRelease(maskedDB
);
477 CFSafeRelease(seedMask
);
479 CFSafeRelease(dbMask
);
480 CFSafeRelease(pHash
);
481 CFSafeRelease(pHashPrime
);
482 CFSafeRelease(mgf_dbMask
);
483 CFSafeRelease(mgf_maskedDB
);
485 CFSafeRelease(EncodingParameters
);
486 // raw_seed is free'd via CFData, addr01 was never allocated, so raw_DB is our lot
495 extern CFDataRef
oaep_padding_via_c(int desired_message_length
, CFDataRef dataValue
);
498 CFDataRef
EncryptDecryptBase::apply_oaep_padding(CFDataRef dataValue
)
501 // MGF1 w/ SHA1 assumed here
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
;
510 if (desired_message_length_cf
) {
511 CFNumberGetValue(desired_message_length_cf
, kCFNumberIntType
, &desired_message_length
);
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
);
525 (void)transforms_assume(RSA_size
.SizeInputBlock
<= RSA_size
.SizeOutputBlock
);
526 desired_message_length
= RSA_size
.SizeOutputBlock
;
528 CFDataRef returnData
= oaep_padding_via_c(desired_message_length
, dataValue
);
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;
542 CSSM_QUERY_SIZE_DATA RSA_size
;
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.
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
;
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
);
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
);
570 (void)transforms_assume(RSA_size
.SizeInputBlock
<= RSA_size
.SizeOutputBlock
);
571 desired_message_length
= RSA_size
.SizeOutputBlock
-1;
573 padLen
= (desired_message_length
- (2*hLen
) -1) - CFDataGetLength(dataValue
);
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
);
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);
582 error
= GetNoMemoryErrorAndRetain();
585 padZeros
= CFDataCreateWithBytesNoCopy(NULL
, raw_padZeros
, padLen
, kCFAllocatorMalloc
);
588 error
= GetNoMemoryErrorAndRetain();
592 // (4) Let pHash = Hash(P), an octet string of length hLen.
593 hash
= SecDigestTransformCreate(hashAlgo
, 0, &error
);
597 EncodingParameters
= (CFDataRef
)this->GetAttribute(kSecOAEPEncodingParametersAttributeName
);
598 if (EncodingParameters
) {
599 CFRetain(EncodingParameters
);
601 EncodingParameters
= CFDataCreate(NULL
, (UInt8
*)"", 0);
602 if (!EncodingParameters
) {
603 error
= GetNoMemoryErrorAndRetain();
607 if (!SecTransformSetAttribute(hash
, kSecTransformInputAttributeName
, EncodingParameters
, &error
)) {
611 padHash
= (CFDataRef
)transforms_assume(SecTransformExecute(hash
, &error
));
615 (void)transforms_assume(hLen
== CFDataGetLength(padHash
));
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
));
620 error
= GetNoMemoryErrorAndRetain();
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
));
628 // (6) Generate a random octet string seed of length hLen.
629 seed
= (CFDataRef
)this->GetAttribute(CFSTR("FixedSeedForOAEPTesting"));
632 raw_seed
= (UInt8
*)CFDataGetBytePtr(seed
);
633 (void)transforms_assume(hLen
== CFDataGetLength(seed
));
636 raw_seed
= (UInt8
*)malloc(hLen
);
638 error
= GetNoMemoryErrorAndRetain();
641 SecRandomCopyBytes(kSecRandomDefault
, hLen
, raw_seed
);
642 seed
= CFDataCreateWithBytesNoCopy(NULL
, raw_seed
, hLen
, kCFAllocatorMalloc
);
645 error
= GetNoMemoryErrorAndRetain();
649 // (7) Let dbMask = MGF (seed, emLen − hLen).
650 mgf_dbMask
= transforms_assume(SecCreateMaskGenerationFunctionTransform(hashAlgo
, desired_message_length
- hLen
, &error
));
654 if (!SecTransformSetAttribute(mgf_dbMask
, kSecTransformInputAttributeName
, seed
, &error
)) {
657 dbMask
= (CFDataRef
)SecTransformExecute(mgf_dbMask
, &error
);
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
662 raw_maskedDB
= (UInt8
*)malloc(CFDataGetLength(dbMask
));
664 error
= GetNoMemoryErrorAndRetain();
667 xor_bytes(raw_maskedDB
, CFDataGetBytePtr(dbMask
), CFDataGetBytePtr(dataBlob
), CFDataGetLength(dbMask
));
668 maskedDB
= CFDataCreateWithBytesNoCopy(NULL
, raw_maskedDB
, CFDataGetLength(dataBlob
), kCFAllocatorMalloc
);
671 error
= GetNoMemoryErrorAndRetain();
675 // (9) Let seedMask = MGF(maskedDB, hLen).
676 mgf_seedMask
= transforms_assume(SecCreateMaskGenerationFunctionTransform(hashAlgo
, hLen
, &error
));
680 if (!SecTransformSetAttribute(mgf_seedMask
, kSecTransformInputAttributeName
, maskedDB
, &error
)) {
683 seedMask
= transforms_assume((CFDataRef
)SecTransformExecute(mgf_seedMask
, &error
));
688 // (10) Let maskedSeed = seed ⊕ seedMask
689 raw_maskedSeed
= (UInt8
*)malloc(hLen
);
690 if (!raw_maskedSeed
) {
691 error
= GetNoMemoryErrorAndRetain();
694 xor_bytes(raw_maskedSeed
, raw_seed
, CFDataGetBytePtr(seedMask
), hLen
);
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);
703 EM
= CFDataCreateMutable(NULL
, CFDataGetLength(maskedDB
) + hLen
+ paddingNeeded
);
705 error
= GetNoMemoryErrorAndRetain();
708 while(paddingNeeded
--) {
709 CFDataAppendBytes(EM
, (UInt8
*)"", 1);
712 CFDataAppendBytes(EM
, raw_maskedSeed
, hLen
);
713 CFDataAppendBytes(EM
, raw_maskedDB
, CFDataGetLength(maskedDB
));
716 SetAttributeNoCallback(kSecTransformOutputAttributeName
, error
);
717 (void)transforms_assume_zero(EM
);
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
);
733 // raw_* are all freed by their associated CFDatas, except raw_maskedSeed
734 free(raw_maskedSeed
);
741 /* --------------------------------------------------------------------------
742 method: AttributeChanged
743 description: deal with input
744 -------------------------------------------------------------------------- */
745 void EncryptDecryptBase::AttributeChanged(SecTransformAttributeRef ah
, CFTypeRef value
)
747 // sanity check our arguments
750 return; // we only deal with input
755 CFTypeID valueType
= CFGetTypeID(value
);
756 if (valueType
!= CFDataGetTypeID())
758 CFStringRef realType
= CFCopyTypeIDDescription(valueType
);
759 CFErrorRef error
= CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly
, "Value is not a CFDataRef -- this one is a %@", realType
);
761 SetAttributeNoCallback(kSecTransformOutputAttributeName
, error
);
765 if (m_forEncryption
&& m_accumulator
) {
766 CFDataRef d
= (CFDataRef
)value
;
767 CFDataAppendBytes(m_accumulator
, CFDataGetBytePtr(d
), CFDataGetLength(d
));
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
);
779 this->Pushback(inputAH
, NULL
);
781 if (m_oaep_padding
) {
782 value
= apply_oaep_padding((CFDataRef
)value
);
783 dispatch_async(this->mDispatchQueue
, ^{
784 CFSafeRelease(value
);
789 // add the input to our cryptor
790 CFDataRef valueRef
= (CFDataRef
) value
;
791 CSSM_RETURN crtn
= CSSM_OK
;
792 Boolean inFinal
= FALSE
;
794 if (valueRef
!= NULL
)
796 // Convert to A CSSM_DATA
797 CSSM_DATA dataStruct
;
798 dataStruct
.Length
= CFDataGetLength(valueRef
);
799 dataStruct
.Data
= const_cast<uint8_t*>(CFDataGetBytePtr(valueRef
));
801 CSSM_DATA intermediateDataStruct
;
802 memset(&intermediateDataStruct
, 0, sizeof(intermediateDataStruct
));
804 CSSM_SIZE bytesProcessed
= 0;
808 crtn
= CSSM_EncryptDataUpdate(m_handle
,
811 &intermediateDataStruct
,
817 crtn
= CSSM_DecryptDataUpdate(m_handle
,
820 &intermediateDataStruct
,
832 if (intermediateDataStruct
.Length
> 0)
834 if (NULL
== m_processedData
)
836 m_processedData
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
839 CFDataAppendBytes(m_processedData
, intermediateDataStruct
.Data
, bytesProcessed
);
840 free(intermediateDataStruct
.Data
);
849 memset(&remData
, 0, sizeof(remData
));
851 crtn
= (m_forEncryption
) ? CSSM_EncryptDataFinal(m_handle
, &remData
) : CSSM_DecryptDataFinal(m_handle
, &remData
);
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
);
861 if (NULL
== m_processedData
)
863 m_processedData
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
866 if (remData
.Length
> 0)
868 CFDataAppendBytes(m_processedData
, remData
.Data
, remData
.Length
);
882 if (NULL
!= m_processedData
)
884 SendAttribute(kSecTransformOutputAttributeName
, m_processedData
);
885 CFRelease(m_processedData
);
886 m_processedData
= NULL
;
891 if (m_oaep_padding
&& m_forEncryption
== false) {
892 CFTypeRef unpadded
= remove_oaep_padding(m_accumulator
);
893 SendAttribute(kSecTransformOutputAttributeName
, unpadded
);
896 SendAttribute(kSecTransformOutputAttributeName
, NULL
);
902 /* --------------------------------------------------------------------------
904 description: Copy the current state of this transform
905 -------------------------------------------------------------------------- */
906 CFDictionaryRef
EncryptDecryptBase::CopyState()
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
)
915 CFDictionaryAddValue(state
, kSecPaddingKey
, paddingStr
);
920 CFDictionaryAddValue(state
, kSecEncryptionMode
, modeStr
);
925 CFDictionaryAddValue(state
, kSecIVKey
, ivData
);
931 /* --------------------------------------------------------------------------
933 description: Restore the state of this transform from a dictionary
934 -------------------------------------------------------------------------- */
935 void EncryptDecryptBase::RestoreState(CFDictionaryRef state
)
942 CFStringRef paddingStr
= (CFStringRef
)CFDictionaryGetValue(state
, kSecPaddingKey
);
943 CFStringRef modeStr
= (CFStringRef
)CFDictionaryGetValue(state
, kSecEncryptionMode
);
944 CFDataRef ivData
= (CFDataRef
)CFDictionaryGetValue(state
, kSecIVKey
);
946 if (NULL
!= paddingStr
)
948 SetAttribute(kSecPaddingKey
, paddingStr
);
953 SetAttribute(kSecEncryptionMode
, modeStr
);
958 SetAttribute(kSecIVKey
, ivData
);
963 /* --------------------------------------------------------------------------
964 Implementation of the EncryptTransform
965 -------------------------------------------------------------------------- */
967 /* --------------------------------------------------------------------------
968 method: EncryptTransform (Constructor)
969 description: Make a new EncryptTransform
970 -------------------------------------------------------------------------- */
971 EncryptTransform::EncryptTransform() : EncryptDecryptBase(kEncryptTransformType
)
975 /* --------------------------------------------------------------------------
976 method: ~EncryptTransform (Destructor)
977 description: Clean up the memory of anEncryptTransform
978 -------------------------------------------------------------------------- */
979 EncryptTransform::~EncryptTransform()
983 /* --------------------------------------------------------------------------
984 method: [static] Make
985 description: Make a new instance of this class
986 -------------------------------------------------------------------------- */
987 SecTransformRef
EncryptTransform::Make()
989 EncryptTransform
* tr
= new EncryptTransform();
990 SecTransformRef str
= (SecTransformRef
) CoreFoundationHolder::MakeHolder(kEncryptTransformType
, tr
);
994 /* --------------------------------------------------------------------------
995 Interface and implementation of the EncryptTransformFactory
996 -------------------------------------------------------------------------- */
998 class EncryptTransformFactory
: public TransformFactory
1001 EncryptTransformFactory();
1006 /* --------------------------------------------------------------------------
1007 method: EncryptTransformFactory (Constructor)
1009 -------------------------------------------------------------------------- */
1010 EncryptTransformFactory::EncryptTransformFactory() :
1011 TransformFactory(kEncryptTransformType
)
1015 /* --------------------------------------------------------------------------
1016 method: MakeTransformFactory
1017 description: Make an instance of this factory class
1018 -------------------------------------------------------------------------- */
1019 TransformFactory
* EncryptTransform::MakeTransformFactory()
1021 return new EncryptTransformFactory
;
1024 /* --------------------------------------------------------------------------
1026 description: Create an instance of this class
1027 -------------------------------------------------------------------------- */
1028 CFTypeRef
EncryptTransformFactory::Make()
1030 return EncryptTransform::Make();
1034 /* --------------------------------------------------------------------------
1035 method: DecryptTransform (Constructor)
1036 description: Make a new DecryptTransform
1037 -------------------------------------------------------------------------- */
1038 DecryptTransform::DecryptTransform() : EncryptDecryptBase(kDecryptTransformType
)
1042 /* --------------------------------------------------------------------------
1043 method: ~DecryptTransform (Destructor)
1044 description: Clean up the memory of anDecryptTransform
1045 -------------------------------------------------------------------------- */
1046 DecryptTransform::~DecryptTransform()
1051 /* --------------------------------------------------------------------------
1052 method: [static] Make
1053 description: Make a new instance of this class
1054 -------------------------------------------------------------------------- */
1055 SecTransformRef
DecryptTransform::Make()
1057 DecryptTransform
* tr
= new DecryptTransform();
1058 SecTransformRef str
= (SecTransformRef
) CoreFoundationHolder::MakeHolder(kDecryptTransformType
, tr
);
1062 /* --------------------------------------------------------------------------
1063 Interface and implementation of the DecryptTransformFactory
1064 -------------------------------------------------------------------------- */
1066 class DecryptTransformFactory
: public TransformFactory
1069 DecryptTransformFactory();
1074 /* --------------------------------------------------------------------------
1075 method: DecryptTransformFactory (Constructor)
1077 -------------------------------------------------------------------------- */
1078 DecryptTransformFactory::DecryptTransformFactory() :
1079 TransformFactory(kDecryptTransformType
)
1083 /* --------------------------------------------------------------------------
1084 method: MakeTransformFactory
1085 description: Make an instance of this factory class
1086 -------------------------------------------------------------------------- */
1087 TransformFactory
* DecryptTransform::MakeTransformFactory()
1089 return new DecryptTransformFactory
;
1092 /* --------------------------------------------------------------------------
1094 description: Create an instance of this class
1095 -------------------------------------------------------------------------- */
1096 CFTypeRef
DecryptTransformFactory::Make()
1098 return DecryptTransform::Make();