2 * Copyright (c) 2010-2014 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/SecRandomP.h>
32 #include <Security/SecKey.h>
33 #include "SecMaskGenerationFunctionTransform.h"
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
42 dispatch_once_t
EncryptDecryptBase::serializerSetUp
;
43 dispatch_queue_t
EncryptDecryptBase::serializerTransformStartingExecution
;
45 /* --------------------------------------------------------------------------
46 Implementation of the EncryptDecryptBase class
47 -------------------------------------------------------------------------- */
49 /* --------------------------------------------------------------------------
50 method: EncryptDecryptBase (Constructor)
51 description: Initialize a new instance of a EncryptDecryptBase class
52 -------------------------------------------------------------------------- */
53 EncryptDecryptBase::EncryptDecryptBase(CFStringRef type
) :
55 m_cssm_padding(CSSM_PADDING_NONE
),
56 m_mode(CSSM_ALGMODE_CBCPadIV8
),
58 m_handle((CSSM_CC_HANDLE
)0),
59 m_forEncryption(FALSE
),
60 m_processedData(NULL
),
63 m_forEncryption
= CFEqual(type
, kEncryptTransformType
);
64 inputAH
= transforms_assume(this->getAH(kSecTransformInputAttributeName
, false, false));
67 /* --------------------------------------------------------------------------
68 method: ~EncryptDecryptBase (pre-Destructor)
69 description: Clean m_handle, let Transform::Finalize() do the rest
70 -------------------------------------------------------------------------- */
71 void EncryptDecryptBase::Finalize()
73 if (m_handle
!= (CSSM_CC_HANDLE
)0)
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
79 dispatch_async(mDispatchQueue
, ^{
80 CSSM_DeleteContext(tmp_handle
);
82 m_handle
= ((CSSM_CC_HANDLE
)0);
85 Transform::Finalize();
89 /* --------------------------------------------------------------------------
90 method: ~EncryptDecryptBase (Destructor)
91 description: Clean up the memory of an EncryptDecryptBase object
92 -------------------------------------------------------------------------- */
93 EncryptDecryptBase::~EncryptDecryptBase()
95 if (NULL
!= m_processedData
)
97 CFReleaseNull(m_processedData
);
98 m_processedData
= NULL
;
100 if (NULL
!= m_accumulator
)
102 CFReleaseNull(m_accumulator
);
103 m_accumulator
= NULL
;
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
)
113 SetAttributeNoCallback(kSecEncryptKey
, key
);
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()
129 CFErrorRef result
= NULL
; // Assume all is well
130 SecKeyRef key
= (SecKeyRef
) GetAttribute(kSecEncryptKey
);
133 return CreateSecTransformErrorRef(kSecTransformErrorAttributeNotFound
, "The attribute %@ was not found.", kSecEncryptKey
);
136 OSStatus err
= errSecSuccess
;
137 err
= SecKeyGetCSSMKey(key
, (const CSSM_KEY
**)&m_cssm_key
);
138 if (errSecSuccess
!= err
)
140 CFStringRef result
= SecCopyErrorMessageString(err
, NULL
);
141 CFErrorRef retValue
= CreateSecTransformErrorRef(err
, "CDSA error (%@).", result
);
142 CFReleaseNull(result
);
147 err
= SecKeyGetCSPHandle(key
, &csp
);
148 if (errSecSuccess
!= err
)
150 CFStringRef result
= SecCopyErrorMessageString(err
, NULL
);
151 CFErrorRef retValue
= CreateSecTransformErrorRef(err
, "CDSA error (%@).", result
);
152 CFReleaseNull(result
);
156 CSSM_ALGORITHMS keyAlg
= m_cssm_key
->KeyHeader
.AlgorithmId
;
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
);
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
);
171 if (CSSM_ALGID_RSA
== keyAlg
|| CSSM_ALGID_ECDSA
== keyAlg
)
173 m_cssm_padding
= CSSM_PADDING_PKCS1
;
177 m_cssm_padding
= CSSM_PADDING_PKCS7
;
179 m_oaep_padding
= false;
183 if (CFStringCompare(kSecPaddingOAEPKey
, paddingStr
, kCFCompareAnchored
)) {
184 m_oaep_padding
= false;
185 m_cssm_padding
= ConvertPaddingStringToEnum(paddingStr
);
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();
198 m_mode
= (CSSM_PADDING_NONE
== m_cssm_padding
) ? CSSM_ALGMODE_CBC_IV8
: CSSM_ALGMODE_CBCPadIV8
;
202 m_mode
= ConvertEncryptModeStringToEnum(modeStr
, (CSSM_PADDING_NONE
!= m_cssm_padding
));
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
));
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
)
217 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
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
;
229 initVector
.Length
= CFDataGetLength(ivData
);
230 initVector
.Data
= const_cast<uint8_t*>(CFDataGetBytePtr(ivData
));
234 initVector
.Length
= gKeySalt
.Length
;
235 initVector
.Data
= (uint8
*)malloc(initVector
.Length
);
236 initVector
.Data
= gKeySalt
.Data
;
239 crtn
= CSSM_CSP_CreateSymmetricContext(csp
, keyAlg
, m_mode
, credPtr
, m_cssm_key
,
240 &initVector
, m_cssm_padding
, NULL
, &m_handle
);
242 // Need better error here
245 CFStringRef result
= SecCopyErrorMessageString(crtn
, NULL
);
246 CFErrorRef retValue
= CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly
, "CDSA error (%@).", result
);
247 CFReleaseNull(result
);
254 crtn
= CSSM_CSP_CreateAsymmetricContext(csp
, keyAlg
, credPtr
, m_cssm_key
, m_cssm_padding
, &m_handle
);
256 // Need better error here
259 CFStringRef result
= SecCopyErrorMessageString(crtn
, NULL
);
260 CFErrorRef retValue
= CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly
, "CDSA error (%@).", result
);
261 CFReleaseNull(result
);
267 crtn
= (m_forEncryption
) ? CSSM_EncryptDataInit(m_handle
) : CSSM_DecryptDataInit(m_handle
);
268 // Need better error here
271 CFStringRef result
= SecCopyErrorMessageString(crtn
, NULL
);
272 CFErrorRef retValue
= CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly
, "CDSA encrypt/decrypt init error (%@).", result
);
273 CFReleaseNull(result
);
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()
292 dispatch_once(&serializerSetUp
, ^{
293 serializerTransformStartingExecution
= dispatch_queue_create("com.apple.security.EncryptDecrypt.key-setup", NULL
);
296 __block CFErrorRef result
= NULL
; // Assume all is well
298 dispatch_sync(serializerTransformStartingExecution
, ^{
299 result
= SerializedTransformStartingExecution();
304 /* --------------------------------------------------------------------------
305 method: TransformCanExecute
306 description: Do we have a key?
307 -------------------------------------------------------------------------- */
308 Boolean
EncryptDecryptBase::TransformCanExecute()
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
);
316 void EncryptDecryptBase::SendCSSMError(CSSM_RETURN retCode
)
318 // make a CFErrorRef for the error message
319 CFStringRef errorString
= SecCopyErrorMessageString(retCode
, NULL
);
320 CFErrorRef errorRef
= CreateGenericErrorRef(kCFErrorDomainOSStatus
, retCode
, "%@", errorString
);
321 CFReleaseNull(errorString
);
323 SendAttribute(kSecTransformOutputAttributeName
, errorRef
);
324 CFReleaseNull(errorRef
);
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
)
330 // NOTE: this can be made faster, but see if we already have a faster version somewhere first.
332 // _mm_xor_ps would be nice here
333 // failing that, getting to an aligned boundry and switching to uint64_t
337 *dst
++ = *src1
++ ^ *src2
++;
342 extern CFDataRef
oaep_unpadding_via_c(CFDataRef encodedMessage
);
345 CFDataRef
EncryptDecryptBase::remove_oaep_padding(CFDataRef encodedMessage
)
348 return oaep_unpadding_via_c(encodedMessage
);
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
;
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;
363 // The numbered steps below correspond to RSA Laboratories' RSAES-OAEP Encryption Scheme
364 // document's numbered steps.
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.
371 // (2) If emLen < 2hLen + 1, output ‘‘decoding error’’ and stop.
372 hashAlgo
= (CFStringRef
)this->GetAttribute(kSecOAEPMGF1DigestAlgorithmAttributeName
);
373 if (hashAlgo
== NULL
) {
374 hashAlgo
= kSecDigestSHA1
;
376 hLen
= Digest::LengthForType(hashAlgo
);
377 if (CFDataGetLength(encodedMessage
) < 2*hLen
+ 1) {
381 // (3) Let maskedSeed be the first hLen octets of EM and let maskedDB be the remaining emLen−hLen
383 maskedSeed
= CFDataCreateWithBytesNoCopy(NULL
, CFDataGetBytePtr(encodedMessage
) +extraPaddingLength
, hLen
, kCFAllocatorNull
);
384 maskedDB
= CFDataCreateWithBytesNoCopy(NULL
, CFDataGetBytePtr(encodedMessage
) + hLen
+extraPaddingLength
, CFDataGetLength(encodedMessage
) - hLen
-extraPaddingLength
, kCFAllocatorNull
);
386 // (4) Let seedMask = MGF(maskedDB, hLen).
387 mgf_maskedDB
= SecCreateMaskGenerationFunctionTransform(hashAlgo
, hLen
, &error
);
391 if (!SecTransformSetAttribute(mgf_maskedDB
, kSecTransformInputAttributeName
, maskedDB
, &error
)) {
394 seedMask
= (CFDataRef
)SecTransformExecute(mgf_maskedDB
, &error
);
398 (void)transforms_assume(hLen
== CFDataGetLength(seedMask
));
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
);
406 error
= GetNoMemoryErrorAndRetain();
409 // (6) Let dbMask = MGF (seed, emLen − hLen).
410 mgf_dbMask
= SecCreateMaskGenerationFunctionTransform(hashAlgo
, CFDataGetLength(encodedMessage
) - hLen
, &error
);
414 if (!SecTransformSetAttribute(mgf_dbMask
, kSecTransformInputAttributeName
, seed
, &error
)) {
417 dbMask
= (CFDataRef
)SecTransformExecute(mgf_dbMask
, &error
);
422 // (7) Let DB = maskedDB ⊕ dbMask.
423 raw_DB
= (UInt8
*)malloc(CFDataGetLength(dbMask
));
424 xor_bytes(raw_DB
, CFDataGetBytePtr(maskedDB
), CFDataGetBytePtr(dbMask
), CFDataGetLength(dbMask
));
426 // (8) Let pHash = Hash(P), an octet string of length hLen.
427 hash
= SecDigestTransformCreate(hashAlgo
, 0, &error
);
431 EncodingParameters
= (CFDataRef
)this->GetAttribute(kSecOAEPEncodingParametersAttributeName
);
432 if (EncodingParameters
) {
433 CFRetain(EncodingParameters
);
435 EncodingParameters
= CFDataCreate(NULL
, (UInt8
*)"", 0);
436 if (!EncodingParameters
) {
440 if (!SecTransformSetAttribute(hash
, kSecTransformInputAttributeName
, EncodingParameters
, &error
)) {
444 pHash
= (CFDataRef
)transforms_assume(SecTransformExecute(hash
, &error
));
448 (void)transforms_assume(hLen
== CFDataGetLength(pHash
));
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
);
460 message
= CFDataCreate(NULL
, addr01
+ 1, (CFDataGetLength(dbMask
) - ((addr01
- raw_DB
) + 1)) -extraPaddingLength
);
462 // (10) If pHash’ does not equal pHash, output ‘‘decoding error’’ and stop.
469 error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
, "decoding error");
471 SetAttributeNoCallback(kSecTransformOutputAttributeName
, error
);
474 // Release eveything except:
475 // hashAlgo (obtained via get)
476 // message (return value)
477 CFSafeRelease(maskedSeed
);
478 CFSafeRelease(maskedDB
);
479 CFSafeRelease(seedMask
);
481 CFSafeRelease(dbMask
);
482 CFSafeRelease(pHash
);
483 CFSafeRelease(pHashPrime
);
484 CFSafeRelease(mgf_dbMask
);
485 CFSafeRelease(mgf_maskedDB
);
487 CFSafeRelease(EncodingParameters
);
488 // raw_seed is free'd via CFData, addr01 was never allocated, so raw_DB is our lot
497 extern CFDataRef
oaep_padding_via_c(int desired_message_length
, CFDataRef dataValue
);
500 CFDataRef
EncryptDecryptBase::apply_oaep_padding(CFDataRef dataValue
)
503 // MGF1 w/ SHA1 assumed here
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
;
512 if (desired_message_length_cf
) {
513 CFNumberGetValue(desired_message_length_cf
, kCFNumberIntType
, &desired_message_length
);
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
);
527 (void)transforms_assume(RSA_size
.SizeInputBlock
<= RSA_size
.SizeOutputBlock
);
528 desired_message_length
= RSA_size
.SizeOutputBlock
;
530 CFDataRef returnData
= oaep_padding_via_c(desired_message_length
, dataValue
);
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;
544 CSSM_QUERY_SIZE_DATA RSA_size
;
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.
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
;
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
);
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
);
572 (void)transforms_assume(RSA_size
.SizeInputBlock
<= RSA_size
.SizeOutputBlock
);
573 desired_message_length
= RSA_size
.SizeOutputBlock
-1;
575 padLen
= (desired_message_length
- (2*hLen
) -1) - CFDataGetLength(dataValue
);
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
);
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);
584 error
= GetNoMemoryErrorAndRetain();
587 padZeros
= CFDataCreateWithBytesNoCopy(NULL
, raw_padZeros
, padLen
, kCFAllocatorMalloc
);
590 error
= GetNoMemoryErrorAndRetain();
594 // (4) Let pHash = Hash(P), an octet string of length hLen.
595 hash
= SecDigestTransformCreate(hashAlgo
, 0, &error
);
599 EncodingParameters
= (CFDataRef
)this->GetAttribute(kSecOAEPEncodingParametersAttributeName
);
600 if (EncodingParameters
) {
601 CFRetain(EncodingParameters
);
603 EncodingParameters
= CFDataCreate(NULL
, (UInt8
*)"", 0);
604 if (!EncodingParameters
) {
605 error
= GetNoMemoryErrorAndRetain();
609 if (!SecTransformSetAttribute(hash
, kSecTransformInputAttributeName
, EncodingParameters
, &error
)) {
613 padHash
= (CFDataRef
)transforms_assume(SecTransformExecute(hash
, &error
));
617 (void)transforms_assume(hLen
== CFDataGetLength(padHash
));
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
));
622 error
= GetNoMemoryErrorAndRetain();
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
));
630 // (6) Generate a random octet string seed of length hLen.
631 seed
= (CFDataRef
)this->GetAttribute(CFSTR("FixedSeedForOAEPTesting"));
634 (void)transforms_assume(hLen
== CFDataGetLength(seed
));
637 seed
= SecRandomCopyData(kSecRandomDefault
, hLen
);
639 error
= GetNoMemoryErrorAndRetain();
643 raw_seed
= (UInt8
*)CFDataGetBytePtr(seed
);
645 // (7) Let dbMask = MGF (seed, emLen − hLen).
646 mgf_dbMask
= transforms_assume(SecCreateMaskGenerationFunctionTransform(hashAlgo
, desired_message_length
- hLen
, &error
));
650 if (!SecTransformSetAttribute(mgf_dbMask
, kSecTransformInputAttributeName
, seed
, &error
)) {
653 dbMask
= (CFDataRef
)SecTransformExecute(mgf_dbMask
, &error
);
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
658 raw_maskedDB
= (UInt8
*)malloc(CFDataGetLength(dbMask
));
660 error
= GetNoMemoryErrorAndRetain();
663 xor_bytes(raw_maskedDB
, CFDataGetBytePtr(dbMask
), CFDataGetBytePtr(dataBlob
), CFDataGetLength(dbMask
));
664 maskedDB
= CFDataCreateWithBytesNoCopy(NULL
, raw_maskedDB
, CFDataGetLength(dataBlob
), kCFAllocatorMalloc
);
667 error
= GetNoMemoryErrorAndRetain();
671 // (9) Let seedMask = MGF(maskedDB, hLen).
672 mgf_seedMask
= transforms_assume(SecCreateMaskGenerationFunctionTransform(hashAlgo
, hLen
, &error
));
676 if (!SecTransformSetAttribute(mgf_seedMask
, kSecTransformInputAttributeName
, maskedDB
, &error
)) {
679 seedMask
= transforms_assume((CFDataRef
)SecTransformExecute(mgf_seedMask
, &error
));
684 // (10) Let maskedSeed = seed ⊕ seedMask
685 raw_maskedSeed
= (UInt8
*)malloc(hLen
);
686 if (!raw_maskedSeed
) {
687 error
= GetNoMemoryErrorAndRetain();
690 xor_bytes(raw_maskedSeed
, raw_seed
, CFDataGetBytePtr(seedMask
), hLen
);
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);
699 EM
= CFDataCreateMutable(NULL
, CFDataGetLength(maskedDB
) + hLen
+ paddingNeeded
);
701 error
= GetNoMemoryErrorAndRetain();
704 while(paddingNeeded
--) {
705 CFDataAppendBytes(EM
, (UInt8
*)"", 1);
708 CFDataAppendBytes(EM
, raw_maskedSeed
, hLen
);
709 CFDataAppendBytes(EM
, raw_maskedDB
, CFDataGetLength(maskedDB
));
712 SetAttributeNoCallback(kSecTransformOutputAttributeName
, error
);
713 (void)transforms_assume_zero(EM
);
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
);
729 // raw_* are all freed by their associated CFDatas, except raw_maskedSeed
730 free(raw_maskedSeed
);
737 /* --------------------------------------------------------------------------
738 method: AttributeChanged
739 description: deal with input
740 -------------------------------------------------------------------------- */
741 void EncryptDecryptBase::AttributeChanged(SecTransformAttributeRef ah
, CFTypeRef value
)
743 // sanity check our arguments
746 return; // we only deal with input
751 CFTypeID valueType
= CFGetTypeID(value
);
752 if (valueType
!= CFDataGetTypeID())
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
);
761 if (m_forEncryption
&& m_accumulator
) {
762 CFDataRef d
= (CFDataRef
)value
;
763 CFDataAppendBytes(m_accumulator
, CFDataGetBytePtr(d
), CFDataGetLength(d
));
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
);
775 this->Pushback(inputAH
, NULL
);
777 if (m_oaep_padding
) {
778 value
= apply_oaep_padding((CFDataRef
)value
);
779 dispatch_async(this->mDispatchQueue
, ^{
780 CFSafeRelease(value
);
785 // add the input to our cryptor
786 CFDataRef valueRef
= (CFDataRef
) value
;
787 CSSM_RETURN crtn
= CSSM_OK
;
788 Boolean inFinal
= FALSE
;
790 if (valueRef
!= NULL
)
792 // Convert to A CSSM_DATA
793 CSSM_DATA dataStruct
;
794 dataStruct
.Length
= CFDataGetLength(valueRef
);
795 dataStruct
.Data
= const_cast<uint8_t*>(CFDataGetBytePtr(valueRef
));
797 CSSM_DATA intermediateDataStruct
;
798 memset(&intermediateDataStruct
, 0, sizeof(intermediateDataStruct
));
800 CSSM_SIZE bytesProcessed
= 0;
804 crtn
= CSSM_EncryptDataUpdate(m_handle
,
807 &intermediateDataStruct
,
813 crtn
= CSSM_DecryptDataUpdate(m_handle
,
816 &intermediateDataStruct
,
828 if (intermediateDataStruct
.Length
> 0)
830 if (NULL
== m_processedData
)
832 m_processedData
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
835 CFDataAppendBytes(m_processedData
, intermediateDataStruct
.Data
, bytesProcessed
);
836 free(intermediateDataStruct
.Data
);
845 memset(&remData
, 0, sizeof(remData
));
847 crtn
= (m_forEncryption
) ? CSSM_EncryptDataFinal(m_handle
, &remData
) : CSSM_DecryptDataFinal(m_handle
, &remData
);
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
);
857 if (NULL
== m_processedData
)
859 m_processedData
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
862 if (remData
.Length
> 0)
864 CFDataAppendBytes(m_processedData
, remData
.Data
, remData
.Length
);
878 if (NULL
!= m_processedData
)
880 SendAttribute(kSecTransformOutputAttributeName
, m_processedData
);
881 CFReleaseNull(m_processedData
);
882 m_processedData
= NULL
;
887 if (m_oaep_padding
&& m_forEncryption
== false) {
888 CFTypeRef unpadded
= remove_oaep_padding(m_accumulator
);
889 SendAttribute(kSecTransformOutputAttributeName
, unpadded
);
890 CFReleaseNull(unpadded
);
892 SendAttribute(kSecTransformOutputAttributeName
, NULL
);
898 /* --------------------------------------------------------------------------
900 description: Copy the current state of this transform
901 -------------------------------------------------------------------------- */
902 CFDictionaryRef
EncryptDecryptBase::CopyState()
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
)
911 CFDictionaryAddValue(state
, kSecPaddingKey
, paddingStr
);
916 CFDictionaryAddValue(state
, kSecEncryptionMode
, modeStr
);
921 CFDictionaryAddValue(state
, kSecIVKey
, ivData
);
927 /* --------------------------------------------------------------------------
929 description: Restore the state of this transform from a dictionary
930 -------------------------------------------------------------------------- */
931 void EncryptDecryptBase::RestoreState(CFDictionaryRef state
)
938 CFStringRef paddingStr
= (CFStringRef
)CFDictionaryGetValue(state
, kSecPaddingKey
);
939 CFStringRef modeStr
= (CFStringRef
)CFDictionaryGetValue(state
, kSecEncryptionMode
);
940 CFDataRef ivData
= (CFDataRef
)CFDictionaryGetValue(state
, kSecIVKey
);
942 if (NULL
!= paddingStr
)
944 SetAttribute(kSecPaddingKey
, paddingStr
);
949 SetAttribute(kSecEncryptionMode
, modeStr
);
954 SetAttribute(kSecIVKey
, ivData
);
959 /* --------------------------------------------------------------------------
960 Implementation of the EncryptTransform
961 -------------------------------------------------------------------------- */
963 /* --------------------------------------------------------------------------
964 method: EncryptTransform (Constructor)
965 description: Make a new EncryptTransform
966 -------------------------------------------------------------------------- */
967 EncryptTransform::EncryptTransform() : EncryptDecryptBase(kEncryptTransformType
)
971 /* --------------------------------------------------------------------------
972 method: ~EncryptTransform (Destructor)
973 description: Clean up the memory of anEncryptTransform
974 -------------------------------------------------------------------------- */
975 EncryptTransform::~EncryptTransform()
979 /* --------------------------------------------------------------------------
980 method: [static] Make
981 description: Make a new instance of this class
982 -------------------------------------------------------------------------- */
983 SecTransformRef
EncryptTransform::Make()
985 EncryptTransform
* tr
= new EncryptTransform();
986 SecTransformRef str
= (SecTransformRef
) CoreFoundationHolder::MakeHolder(kEncryptTransformType
, tr
);
990 /* --------------------------------------------------------------------------
991 Interface and implementation of the EncryptTransformFactory
992 -------------------------------------------------------------------------- */
994 class EncryptTransformFactory
: public TransformFactory
997 EncryptTransformFactory();
1002 /* --------------------------------------------------------------------------
1003 method: EncryptTransformFactory (Constructor)
1005 -------------------------------------------------------------------------- */
1006 EncryptTransformFactory::EncryptTransformFactory() :
1007 TransformFactory(kEncryptTransformType
)
1011 /* --------------------------------------------------------------------------
1012 method: MakeTransformFactory
1013 description: Make an instance of this factory class
1014 -------------------------------------------------------------------------- */
1015 TransformFactory
* EncryptTransform::MakeTransformFactory()
1017 return new EncryptTransformFactory
;
1020 /* --------------------------------------------------------------------------
1022 description: Create an instance of this class
1023 -------------------------------------------------------------------------- */
1024 CFTypeRef
EncryptTransformFactory::Make()
1026 return EncryptTransform::Make();
1030 /* --------------------------------------------------------------------------
1031 method: DecryptTransform (Constructor)
1032 description: Make a new DecryptTransform
1033 -------------------------------------------------------------------------- */
1034 DecryptTransform::DecryptTransform() : EncryptDecryptBase(kDecryptTransformType
)
1038 /* --------------------------------------------------------------------------
1039 method: ~DecryptTransform (Destructor)
1040 description: Clean up the memory of anDecryptTransform
1041 -------------------------------------------------------------------------- */
1042 DecryptTransform::~DecryptTransform()
1047 /* --------------------------------------------------------------------------
1048 method: [static] Make
1049 description: Make a new instance of this class
1050 -------------------------------------------------------------------------- */
1051 SecTransformRef
DecryptTransform::Make()
1053 DecryptTransform
* tr
= new DecryptTransform();
1054 SecTransformRef str
= (SecTransformRef
) CoreFoundationHolder::MakeHolder(kDecryptTransformType
, tr
);
1058 /* --------------------------------------------------------------------------
1059 Interface and implementation of the DecryptTransformFactory
1060 -------------------------------------------------------------------------- */
1062 class DecryptTransformFactory
: public TransformFactory
1065 DecryptTransformFactory();
1070 /* --------------------------------------------------------------------------
1071 method: DecryptTransformFactory (Constructor)
1073 -------------------------------------------------------------------------- */
1074 DecryptTransformFactory::DecryptTransformFactory() :
1075 TransformFactory(kDecryptTransformType
)
1079 /* --------------------------------------------------------------------------
1080 method: MakeTransformFactory
1081 description: Make an instance of this factory class
1082 -------------------------------------------------------------------------- */
1083 TransformFactory
* DecryptTransform::MakeTransformFactory()
1085 return new DecryptTransformFactory
;
1088 /* --------------------------------------------------------------------------
1090 description: Create an instance of this class
1091 -------------------------------------------------------------------------- */
1092 CFTypeRef
DecryptTransformFactory::Make()
1094 return DecryptTransform::Make();