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 CFRelease(m_processedData
);
98 m_processedData
= NULL
;
100 if (NULL
!= m_accumulator
)
102 CFRelease(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
);
147 err
= SecKeyGetCSPHandle(key
, &csp
);
148 if (errSecSuccess
!= err
)
150 CFStringRef result
= SecCopyErrorMessageString(err
, NULL
);
151 CFErrorRef retValue
= CreateSecTransformErrorRef(err
, "CDSA error (%@).", 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 CSSM_DATA initVector
;
226 initVector
.Length
= CFDataGetLength(ivData
);
227 initVector
.Data
= const_cast<uint8_t*>(CFDataGetBytePtr(ivData
));
231 initVector
.Length
= gKeySalt
.Length
;
232 initVector
.Data
= (uint8
*)malloc(initVector
.Length
);
233 initVector
.Data
= gKeySalt
.Data
;
236 crtn
= CSSM_CSP_CreateSymmetricContext(csp
, keyAlg
, m_mode
, credPtr
, m_cssm_key
,
237 &initVector
, m_cssm_padding
, NULL
, &m_handle
);
239 // Need better error here
242 CFStringRef result
= SecCopyErrorMessageString(crtn
, NULL
);
243 CFErrorRef retValue
= CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly
, "CDSA error (%@).", result
);
250 crtn
= CSSM_CSP_CreateAsymmetricContext(csp
, keyAlg
, credPtr
, m_cssm_key
, m_cssm_padding
, &m_handle
);
252 // Need better error here
255 CFStringRef result
= SecCopyErrorMessageString(crtn
, NULL
);
256 CFErrorRef retValue
= CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly
, "CDSA error (%@).", result
);
263 crtn
= (m_forEncryption
) ? CSSM_EncryptDataInit(m_handle
) : CSSM_DecryptDataInit(m_handle
);
264 // Need better error here
267 CFStringRef result
= SecCopyErrorMessageString(crtn
, NULL
);
268 CFErrorRef retValue
= CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly
, "CDSA encrypt/decrypt init error (%@).", result
);
277 /* --------------------------------------------------------------------------
278 method: TransformStartingExecution()
279 description: Get this transform ready to run.
280 NOTE: the encrypt/decrypt setup is not safe to call for a single
281 key from multiple threads at once, TransformStartingExecution is
282 responsable making sure this doesn't happen,
283 SerializedTransformStartingExecution() does the real set up work.
284 -------------------------------------------------------------------------- */
285 CFErrorRef
EncryptDecryptBase::TransformStartingExecution()
288 dispatch_once(&serializerSetUp
, ^{
289 serializerTransformStartingExecution
= dispatch_queue_create("com.apple.security.EncryptDecrypt.key-setup", NULL
);
292 __block CFErrorRef result
= NULL
; // Assume all is well
294 dispatch_sync(serializerTransformStartingExecution
, ^{
295 result
= SerializedTransformStartingExecution();
300 /* --------------------------------------------------------------------------
301 method: TransformCanExecute
302 description: Do we have a key?
303 -------------------------------------------------------------------------- */
304 Boolean
EncryptDecryptBase::TransformCanExecute()
306 // make sure we have a key -- there may be some circumstance when one isn't available
307 // and besides, it helps test this logic
308 SecKeyRef key
= (SecKeyRef
) GetAttribute(kSecEncryptKey
);
312 void EncryptDecryptBase::SendCSSMError(CSSM_RETURN retCode
)
314 // make a CFErrorRef for the error message
315 CFStringRef errorString
= SecCopyErrorMessageString(retCode
, NULL
);
316 CFErrorRef errorRef
= CreateGenericErrorRef(kCFErrorDomainOSStatus
, retCode
, "%@", errorString
);
317 CFRelease(errorString
);
319 SendAttribute(kSecTransformOutputAttributeName
, errorRef
);
323 void xor_bytes(UInt8
*dst
, const UInt8
*src1
, const UInt8
*src2
, CFIndex length
);
324 void xor_bytes(UInt8
*dst
, const UInt8
*src1
, const UInt8
*src2
, CFIndex length
)
326 // NOTE: this can be made faster, but see if we already have a faster version somewhere first.
328 // _mm_xor_ps would be nice here
329 // failing that, getting to an aligned boundry and switching to uint64_t
333 *dst
++ = *src1
++ ^ *src2
++;
338 extern CFDataRef
oaep_unpadding_via_c(CFDataRef encodedMessage
);
341 CFDataRef
EncryptDecryptBase::remove_oaep_padding(CFDataRef encodedMessage
)
344 return oaep_unpadding_via_c(encodedMessage
);
346 CFStringRef hashAlgo
= NULL
;
347 CFDataRef message
= NULL
, maskedSeed
= NULL
, maskedDB
= NULL
, seedMask
= NULL
, seed
= NULL
, dbMask
= NULL
;
348 CFDataRef pHash
= NULL
, pHashPrime
= NULL
;
349 CFDataRef EncodingParameters
= NULL
;
350 CFErrorRef error
= NULL
;
351 UInt8
*raw_seed
= NULL
, *raw_DB
= NULL
, *addr01
= NULL
;
352 SecTransformRef mgf_maskedDB
= NULL
, mgf_dbMask
= NULL
, hash
= NULL
;
354 // RSA's OAEP documentation assumes the crypto layer will remove the leading (partial) byte,
355 // but CDSA leaves that responsability to us (we did ask it for "no padding" after all).
356 // (use extraPaddingLength = 0 when using a layer that does strip that byte)
357 const int extraPaddingLength
= 1;
359 // The numbered steps below correspond to RSA Laboratories' RSAES-OAEP Encryption Scheme
360 // document's numbered steps.
362 // NOTE: we omit step 1: "If the length of P is greater than the input limitation for the hash
363 // function (2^61 − 1 octets for SHA-1) then output ‘‘decoding error’’ and stop."; we don't have
364 // ready access to the input limits of the hash functions, and in the real world we won't be
365 // seeing messages that long anyway.
367 // (2) If emLen < 2hLen + 1, output ‘‘decoding error’’ and stop.
368 hashAlgo
= (CFStringRef
)this->GetAttribute(kSecOAEPMGF1DigestAlgorithmAttributeName
);
369 if (hashAlgo
== NULL
) {
370 hashAlgo
= kSecDigestSHA1
;
372 hLen
= Digest::LengthForType(hashAlgo
);
373 if (CFDataGetLength(encodedMessage
) < 2*hLen
+ 1) {
377 // (3) Let maskedSeed be the first hLen octets of EM and let maskedDB be the remaining emLen−hLen
379 maskedSeed
= CFDataCreateWithBytesNoCopy(NULL
, CFDataGetBytePtr(encodedMessage
) +extraPaddingLength
, hLen
, kCFAllocatorNull
);
380 maskedDB
= CFDataCreateWithBytesNoCopy(NULL
, CFDataGetBytePtr(encodedMessage
) + hLen
+extraPaddingLength
, CFDataGetLength(encodedMessage
) - hLen
-extraPaddingLength
, kCFAllocatorNull
);
382 // (4) Let seedMask = MGF(maskedDB, hLen).
383 mgf_maskedDB
= SecCreateMaskGenerationFunctionTransform(hashAlgo
, hLen
, &error
);
387 if (!SecTransformSetAttribute(mgf_maskedDB
, kSecTransformInputAttributeName
, maskedDB
, &error
)) {
390 seedMask
= (CFDataRef
)SecTransformExecute(mgf_maskedDB
, &error
);
394 (void)transforms_assume(hLen
== CFDataGetLength(seedMask
));
396 // (5) Let seed = maskedSeed ⊕ seedMask.
397 raw_seed
= (UInt8
*)malloc(hLen
);
398 xor_bytes(raw_seed
, CFDataGetBytePtr(maskedSeed
), CFDataGetBytePtr(seedMask
), hLen
);
399 seed
= CFDataCreateWithBytesNoCopy(NULL
, raw_seed
, hLen
, kCFAllocatorNull
);
402 error
= GetNoMemoryErrorAndRetain();
405 // (6) Let dbMask = MGF (seed, emLen − hLen).
406 mgf_dbMask
= SecCreateMaskGenerationFunctionTransform(hashAlgo
, CFDataGetLength(encodedMessage
) - hLen
, &error
);
410 if (!SecTransformSetAttribute(mgf_dbMask
, kSecTransformInputAttributeName
, seed
, &error
)) {
413 dbMask
= (CFDataRef
)SecTransformExecute(mgf_dbMask
, &error
);
418 // (7) Let DB = maskedDB ⊕ dbMask.
419 raw_DB
= (UInt8
*)malloc(CFDataGetLength(dbMask
));
420 xor_bytes(raw_DB
, CFDataGetBytePtr(maskedDB
), CFDataGetBytePtr(dbMask
), CFDataGetLength(dbMask
));
422 // (8) Let pHash = Hash(P), an octet string of length hLen.
423 hash
= SecDigestTransformCreate(hashAlgo
, 0, &error
);
427 EncodingParameters
= (CFDataRef
)this->GetAttribute(kSecOAEPEncodingParametersAttributeName
);
428 if (EncodingParameters
) {
429 CFRetain(EncodingParameters
);
431 EncodingParameters
= CFDataCreate(NULL
, (UInt8
*)"", 0);
432 if (!EncodingParameters
) {
436 if (!SecTransformSetAttribute(hash
, kSecTransformInputAttributeName
, EncodingParameters
, &error
)) {
440 pHash
= (CFDataRef
)transforms_assume(SecTransformExecute(hash
, &error
));
444 (void)transforms_assume(hLen
== CFDataGetLength(pHash
));
447 // (9) Separate DB into an octet string pHash’ consisting of the first hLen octets of DB, a
448 // (possibly empty) octet string PS consisting of consecutive zero octets following pHash’,
449 // and a message M as If there is no 01 octet to separate PS from M , output ‘‘decoding error’’ and stop.
450 pHashPrime
= CFDataCreateWithBytesNoCopy(NULL
, raw_DB
, hLen
, kCFAllocatorNull
);
451 if (CFEqual(pHash
, pHashPrime
)) {
452 addr01
= (UInt8
*)memchr(raw_DB
+ hLen
, 0x01, CFDataGetLength(dbMask
) - hLen
);
456 message
= CFDataCreate(NULL
, addr01
+ 1, (CFDataGetLength(dbMask
) - ((addr01
- raw_DB
) + 1)) -extraPaddingLength
);
458 // (10) If pHash’ does not equal pHash, output ‘‘decoding error’’ and stop.
465 error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
, "decoding error");
467 SetAttributeNoCallback(kSecTransformOutputAttributeName
, error
);
470 // Release eveything except:
471 // hashAlgo (obtained via get)
472 // message (return value)
473 CFSafeRelease(maskedSeed
);
474 CFSafeRelease(maskedDB
);
475 CFSafeRelease(seedMask
);
477 CFSafeRelease(dbMask
);
478 CFSafeRelease(pHash
);
479 CFSafeRelease(pHashPrime
);
480 CFSafeRelease(mgf_dbMask
);
481 CFSafeRelease(mgf_maskedDB
);
483 CFSafeRelease(EncodingParameters
);
484 // raw_seed is free'd via CFData, addr01 was never allocated, so raw_DB is our lot
493 extern CFDataRef
oaep_padding_via_c(int desired_message_length
, CFDataRef dataValue
);
496 CFDataRef
EncryptDecryptBase::apply_oaep_padding(CFDataRef dataValue
)
499 // MGF1 w/ SHA1 assumed here
501 CFErrorRef error
= NULL
;
502 int hLen
= Digest::LengthForType(kSecDigestSHA1
);
503 CFNumberRef desired_message_length_cf
= (CFNumberRef
)this->GetAttribute(kSecOAEPMessageLengthAttributeName
);
504 int desired_message_length
= 0;
505 CSSM_QUERY_SIZE_DATA RSA_size
;
508 if (desired_message_length_cf
) {
509 CFNumberGetValue(desired_message_length_cf
, kCFNumberIntType
, &desired_message_length
);
511 // take RSA (or whatever crypto) block size onto account too
512 RSA_size
.SizeInputBlock
= (uint32
)(CFDataGetLength(dataValue
) + 2*hLen
+1);
513 RSA_size
.SizeOutputBlock
= 0;
514 OSStatus status
= CSSM_QuerySize(m_handle
, CSSM_TRUE
, 1, &RSA_size
);
515 if (status
!= errSecSuccess
) {
516 CFStringRef errorString
= SecCopyErrorMessageString(status
, NULL
);
517 error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation
, "CDSA error (%@).", errorString
);
518 CFRelease(errorString
);
519 SetAttributeNoCallback(kSecTransformOutputAttributeName
, error
);
520 (void)transforms_assume_zero(EM
);
523 (void)transforms_assume(RSA_size
.SizeInputBlock
<= RSA_size
.SizeOutputBlock
);
524 desired_message_length
= RSA_size
.SizeOutputBlock
;
526 CFDataRef returnData
= oaep_padding_via_c(desired_message_length
, dataValue
);
530 CFDataRef seed
= NULL
, dbMask
= NULL
, maskedDB
= NULL
, seedMask
= NULL
, padHash
= NULL
, padZeros
= NULL
;
531 CFDataRef EncodingParameters
= NULL
;
532 CFMutableDataRef EM
= NULL
, dataBlob
= NULL
;
533 CFNumberRef desired_message_length_cf
= NULL
;
534 CFErrorRef error
= NULL
;
535 CFStringRef hashAlgo
= NULL
;
536 UInt8
*raw_padZeros
= NULL
, *raw_seed
= NULL
, *raw_maskedSeed
= NULL
, *raw_maskedDB
= NULL
;
537 SecTransformRef mgf_dbMask
= NULL
, mgf_seedMask
= NULL
, hash
= NULL
;
538 CFIndex paddingNeeded
= -1, padLen
= -1;
540 CSSM_QUERY_SIZE_DATA RSA_size
;
542 // NOTE: we omit (1) If the length of P is greater than the input limitation for the hash function
543 // (2^61 − 1 octets for SHA-1) then output ‘‘parameter string too long’’ and stop.
544 // We don't have ready access to the input limit of the hash functions, and in the real world
545 // we won't be seeing a message that long anyway.
547 // (2) If mLen > emLen − 2hLen − 1, output ‘‘message too long’’ and stop.
548 hashAlgo
= (CFStringRef
)this->GetAttribute(kSecOAEPMGF1DigestAlgorithmAttributeName
);
549 if (hashAlgo
== NULL
) {
550 hashAlgo
= kSecDigestSHA1
;
552 hLen
= Digest::LengthForType(hashAlgo
);
553 desired_message_length_cf
= (CFNumberRef
)this->GetAttribute(kSecOAEPMessageLengthAttributeName
);
554 int desired_message_length
= 0;
555 if (desired_message_length_cf
) {
556 CFNumberGetValue(desired_message_length_cf
, kCFNumberIntType
, &desired_message_length
);
558 // take RSA (or whatever crypto) block size onto account too
559 RSA_size
.SizeInputBlock
= CFDataGetLength(dataValue
) + 2*hLen
+1;
560 RSA_size
.SizeOutputBlock
= 0;
561 OSStatus status
= CSSM_QuerySize(m_handle
, CSSM_TRUE
, 1, &RSA_size
);
562 if (status
!= errSecSuccess
) {
563 CFStringRef errorString
= SecCopyErrorMessageString(status
, NULL
);
564 error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation
, "CDSA error (%@).", errorString
);
565 CFRelease(errorString
);
568 (void)transforms_assume(RSA_size
.SizeInputBlock
<= RSA_size
.SizeOutputBlock
);
569 desired_message_length
= RSA_size
.SizeOutputBlock
-1;
571 padLen
= (desired_message_length
- (2*hLen
) -1) - CFDataGetLength(dataValue
);
573 error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidLength
, "Your message is too long for your message length, it needs to be %d bytes shorter, or you need to adjust the kSecOAEPMessageLengthAttributeName attribute", -padLen
);
577 // (3) Generate an octet string PS consisting of emLen − mLen − 2hLen − 1 zero octets. The length of PS may be 0.
578 raw_padZeros
= (UInt8
*)calloc(padLen
, 1);
580 error
= GetNoMemoryErrorAndRetain();
583 padZeros
= CFDataCreateWithBytesNoCopy(NULL
, raw_padZeros
, padLen
, kCFAllocatorMalloc
);
586 error
= GetNoMemoryErrorAndRetain();
590 // (4) Let pHash = Hash(P), an octet string of length hLen.
591 hash
= SecDigestTransformCreate(hashAlgo
, 0, &error
);
595 EncodingParameters
= (CFDataRef
)this->GetAttribute(kSecOAEPEncodingParametersAttributeName
);
596 if (EncodingParameters
) {
597 CFRetain(EncodingParameters
);
599 EncodingParameters
= CFDataCreate(NULL
, (UInt8
*)"", 0);
600 if (!EncodingParameters
) {
601 error
= GetNoMemoryErrorAndRetain();
605 if (!SecTransformSetAttribute(hash
, kSecTransformInputAttributeName
, EncodingParameters
, &error
)) {
609 padHash
= (CFDataRef
)transforms_assume(SecTransformExecute(hash
, &error
));
613 (void)transforms_assume(hLen
== CFDataGetLength(padHash
));
615 // (5) Concatenate pHash,PS, the message M, and other padding to form a data block DB as DB = pHash∥PS∥01∥M.
616 dataBlob
= CFDataCreateMutable(NULL
, CFDataGetLength(padHash
) + padLen
+ 1 + CFDataGetLength(dataValue
));
618 error
= GetNoMemoryErrorAndRetain();
621 CFDataAppendBytes(dataBlob
, CFDataGetBytePtr(padHash
), hLen
);
622 CFDataAppendBytes(dataBlob
, raw_padZeros
, padLen
);
623 CFDataAppendBytes(dataBlob
, (UInt8
*)"\01", 1);
624 CFDataAppendBytes(dataBlob
, CFDataGetBytePtr(dataValue
), CFDataGetLength(dataValue
));
626 // (6) Generate a random octet string seed of length hLen.
627 seed
= (CFDataRef
)this->GetAttribute(CFSTR("FixedSeedForOAEPTesting"));
630 (void)transforms_assume(hLen
== CFDataGetLength(seed
));
633 seed
= SecRandomCopyData(kSecRandomDefault
, hLen
);
635 error
= GetNoMemoryErrorAndRetain();
639 raw_seed
= (UInt8
*)CFDataGetBytePtr(seed
);
641 // (7) Let dbMask = MGF (seed, emLen − hLen).
642 mgf_dbMask
= transforms_assume(SecCreateMaskGenerationFunctionTransform(hashAlgo
, desired_message_length
- hLen
, &error
));
646 if (!SecTransformSetAttribute(mgf_dbMask
, kSecTransformInputAttributeName
, seed
, &error
)) {
649 dbMask
= (CFDataRef
)SecTransformExecute(mgf_dbMask
, &error
);
651 // (8) Let maskedDB = DB ⊕ dbMask.
652 // NOTE: we do some allocations above...you know, we should be able to malloc ONE buffer of the
654 raw_maskedDB
= (UInt8
*)malloc(CFDataGetLength(dbMask
));
656 error
= GetNoMemoryErrorAndRetain();
659 xor_bytes(raw_maskedDB
, CFDataGetBytePtr(dbMask
), CFDataGetBytePtr(dataBlob
), CFDataGetLength(dbMask
));
660 maskedDB
= CFDataCreateWithBytesNoCopy(NULL
, raw_maskedDB
, CFDataGetLength(dataBlob
), kCFAllocatorMalloc
);
663 error
= GetNoMemoryErrorAndRetain();
667 // (9) Let seedMask = MGF(maskedDB, hLen).
668 mgf_seedMask
= transforms_assume(SecCreateMaskGenerationFunctionTransform(hashAlgo
, hLen
, &error
));
672 if (!SecTransformSetAttribute(mgf_seedMask
, kSecTransformInputAttributeName
, maskedDB
, &error
)) {
675 seedMask
= transforms_assume((CFDataRef
)SecTransformExecute(mgf_seedMask
, &error
));
680 // (10) Let maskedSeed = seed ⊕ seedMask
681 raw_maskedSeed
= (UInt8
*)malloc(hLen
);
682 if (!raw_maskedSeed
) {
683 error
= GetNoMemoryErrorAndRetain();
686 xor_bytes(raw_maskedSeed
, raw_seed
, CFDataGetBytePtr(seedMask
), hLen
);
688 // (11) Let EM = maskedSeed∥maskedDB (if we didn't have to pushback the NULL we could do this without physically concatanating)
689 // (figure out amount of leading zero padding we need)
690 RSA_size
.SizeInputBlock
= hLen
+ CFDataGetLength(maskedDB
);
691 CSSM_QuerySize(m_handle
, CSSM_TRUE
, 1, &RSA_size
);
692 paddingNeeded
= RSA_size
.SizeOutputBlock
- RSA_size
.SizeInputBlock
;
693 (void)transforms_assume(paddingNeeded
>= 0);
695 EM
= CFDataCreateMutable(NULL
, CFDataGetLength(maskedDB
) + hLen
+ paddingNeeded
);
697 error
= GetNoMemoryErrorAndRetain();
700 while(paddingNeeded
--) {
701 CFDataAppendBytes(EM
, (UInt8
*)"", 1);
704 CFDataAppendBytes(EM
, raw_maskedSeed
, hLen
);
705 CFDataAppendBytes(EM
, raw_maskedDB
, CFDataGetLength(maskedDB
));
708 SetAttributeNoCallback(kSecTransformOutputAttributeName
, error
);
709 (void)transforms_assume_zero(EM
);
712 CFSafeRelease(seed
); // via get??
713 CFSafeRelease(dbMask
);
714 CFSafeRelease(maskedDB
);
715 CFSafeRelease(seedMask
);
716 CFSafeRelease(padHash
);
717 CFSafeRelease(padZeros
);
718 CFSafeRelease(EncodingParameters
);
719 CFSafeRelease(dataBlob
);
720 // desired_message_length_cf -- via get
721 // hashAlgo -- via get
722 CFSafeRelease(mgf_dbMask
);
723 CFSafeRelease(mgf_seedMask
);
725 // raw_* are all freed by their associated CFDatas, except raw_maskedSeed
726 free(raw_maskedSeed
);
733 /* --------------------------------------------------------------------------
734 method: AttributeChanged
735 description: deal with input
736 -------------------------------------------------------------------------- */
737 void EncryptDecryptBase::AttributeChanged(SecTransformAttributeRef ah
, CFTypeRef value
)
739 // sanity check our arguments
742 return; // we only deal with input
747 CFTypeID valueType
= CFGetTypeID(value
);
748 if (valueType
!= CFDataGetTypeID())
750 CFStringRef realType
= CFCopyTypeIDDescription(valueType
);
751 CFErrorRef error
= CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly
, "Value is not a CFDataRef -- this one is a %@", realType
);
753 SetAttributeNoCallback(kSecTransformOutputAttributeName
, error
);
757 if (m_forEncryption
&& m_accumulator
) {
758 CFDataRef d
= (CFDataRef
)value
;
759 CFDataAppendBytes(m_accumulator
, CFDataGetBytePtr(d
), CFDataGetLength(d
));
764 if (m_forEncryption
&& m_accumulator
) {
765 (void)transforms_assume_zero(value
);
766 value
= m_accumulator
;
767 m_accumulator
= NULL
;
768 dispatch_async(this->mDispatchQueue
, ^{
769 CFSafeRelease(value
);
771 this->Pushback(inputAH
, NULL
);
773 if (m_oaep_padding
) {
774 value
= apply_oaep_padding((CFDataRef
)value
);
775 dispatch_async(this->mDispatchQueue
, ^{
776 CFSafeRelease(value
);
781 // add the input to our cryptor
782 CFDataRef valueRef
= (CFDataRef
) value
;
783 CSSM_RETURN crtn
= CSSM_OK
;
784 Boolean inFinal
= FALSE
;
786 if (valueRef
!= NULL
)
788 // Convert to A CSSM_DATA
789 CSSM_DATA dataStruct
;
790 dataStruct
.Length
= CFDataGetLength(valueRef
);
791 dataStruct
.Data
= const_cast<uint8_t*>(CFDataGetBytePtr(valueRef
));
793 CSSM_DATA intermediateDataStruct
;
794 memset(&intermediateDataStruct
, 0, sizeof(intermediateDataStruct
));
796 CSSM_SIZE bytesProcessed
= 0;
800 crtn
= CSSM_EncryptDataUpdate(m_handle
,
803 &intermediateDataStruct
,
809 crtn
= CSSM_DecryptDataUpdate(m_handle
,
812 &intermediateDataStruct
,
824 if (intermediateDataStruct
.Length
> 0)
826 if (NULL
== m_processedData
)
828 m_processedData
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
831 CFDataAppendBytes(m_processedData
, intermediateDataStruct
.Data
, bytesProcessed
);
832 free(intermediateDataStruct
.Data
);
841 memset(&remData
, 0, sizeof(remData
));
843 crtn
= (m_forEncryption
) ? CSSM_EncryptDataFinal(m_handle
, &remData
) : CSSM_DecryptDataFinal(m_handle
, &remData
);
847 if (m_forEncryption
== false && m_accumulator
) {
848 (void)transforms_assume_zero(m_processedData
);
849 if (remData
.Length
> 0) {
850 CFDataAppendBytes(m_accumulator
, remData
.Data
, remData
.Length
);
853 if (NULL
== m_processedData
)
855 m_processedData
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
858 if (remData
.Length
> 0)
860 CFDataAppendBytes(m_processedData
, remData
.Data
, remData
.Length
);
874 if (NULL
!= m_processedData
)
876 SendAttribute(kSecTransformOutputAttributeName
, m_processedData
);
877 CFRelease(m_processedData
);
878 m_processedData
= NULL
;
883 if (m_oaep_padding
&& m_forEncryption
== false) {
884 CFTypeRef unpadded
= remove_oaep_padding(m_accumulator
);
885 SendAttribute(kSecTransformOutputAttributeName
, unpadded
);
888 SendAttribute(kSecTransformOutputAttributeName
, NULL
);
894 /* --------------------------------------------------------------------------
896 description: Copy the current state of this transform
897 -------------------------------------------------------------------------- */
898 CFDictionaryRef
EncryptDecryptBase::CopyState()
900 // make a dictionary for our state
901 CFMutableDictionaryRef state
= (CFMutableDictionaryRef
) CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
902 CFStringRef paddingStr
= (CFStringRef
) GetAttribute(kSecPaddingKey
);
903 CFStringRef modeStr
= (CFStringRef
) GetAttribute (kSecEncryptionMode
);
904 CFDataRef ivData
= (CFDataRef
) GetAttribute(kSecIVKey
);
905 if (NULL
!= paddingStr
)
907 CFDictionaryAddValue(state
, kSecPaddingKey
, paddingStr
);
912 CFDictionaryAddValue(state
, kSecEncryptionMode
, modeStr
);
917 CFDictionaryAddValue(state
, kSecIVKey
, ivData
);
923 /* --------------------------------------------------------------------------
925 description: Restore the state of this transform from a dictionary
926 -------------------------------------------------------------------------- */
927 void EncryptDecryptBase::RestoreState(CFDictionaryRef state
)
934 CFStringRef paddingStr
= (CFStringRef
)CFDictionaryGetValue(state
, kSecPaddingKey
);
935 CFStringRef modeStr
= (CFStringRef
)CFDictionaryGetValue(state
, kSecEncryptionMode
);
936 CFDataRef ivData
= (CFDataRef
)CFDictionaryGetValue(state
, kSecIVKey
);
938 if (NULL
!= paddingStr
)
940 SetAttribute(kSecPaddingKey
, paddingStr
);
945 SetAttribute(kSecEncryptionMode
, modeStr
);
950 SetAttribute(kSecIVKey
, ivData
);
955 /* --------------------------------------------------------------------------
956 Implementation of the EncryptTransform
957 -------------------------------------------------------------------------- */
959 /* --------------------------------------------------------------------------
960 method: EncryptTransform (Constructor)
961 description: Make a new EncryptTransform
962 -------------------------------------------------------------------------- */
963 EncryptTransform::EncryptTransform() : EncryptDecryptBase(kEncryptTransformType
)
967 /* --------------------------------------------------------------------------
968 method: ~EncryptTransform (Destructor)
969 description: Clean up the memory of anEncryptTransform
970 -------------------------------------------------------------------------- */
971 EncryptTransform::~EncryptTransform()
975 /* --------------------------------------------------------------------------
976 method: [static] Make
977 description: Make a new instance of this class
978 -------------------------------------------------------------------------- */
979 SecTransformRef
EncryptTransform::Make()
981 EncryptTransform
* tr
= new EncryptTransform();
982 SecTransformRef str
= (SecTransformRef
) CoreFoundationHolder::MakeHolder(kEncryptTransformType
, tr
);
986 /* --------------------------------------------------------------------------
987 Interface and implementation of the EncryptTransformFactory
988 -------------------------------------------------------------------------- */
990 class EncryptTransformFactory
: public TransformFactory
993 EncryptTransformFactory();
998 /* --------------------------------------------------------------------------
999 method: EncryptTransformFactory (Constructor)
1001 -------------------------------------------------------------------------- */
1002 EncryptTransformFactory::EncryptTransformFactory() :
1003 TransformFactory(kEncryptTransformType
)
1007 /* --------------------------------------------------------------------------
1008 method: MakeTransformFactory
1009 description: Make an instance of this factory class
1010 -------------------------------------------------------------------------- */
1011 TransformFactory
* EncryptTransform::MakeTransformFactory()
1013 return new EncryptTransformFactory
;
1016 /* --------------------------------------------------------------------------
1018 description: Create an instance of this class
1019 -------------------------------------------------------------------------- */
1020 CFTypeRef
EncryptTransformFactory::Make()
1022 return EncryptTransform::Make();
1026 /* --------------------------------------------------------------------------
1027 method: DecryptTransform (Constructor)
1028 description: Make a new DecryptTransform
1029 -------------------------------------------------------------------------- */
1030 DecryptTransform::DecryptTransform() : EncryptDecryptBase(kDecryptTransformType
)
1034 /* --------------------------------------------------------------------------
1035 method: ~DecryptTransform (Destructor)
1036 description: Clean up the memory of anDecryptTransform
1037 -------------------------------------------------------------------------- */
1038 DecryptTransform::~DecryptTransform()
1043 /* --------------------------------------------------------------------------
1044 method: [static] Make
1045 description: Make a new instance of this class
1046 -------------------------------------------------------------------------- */
1047 SecTransformRef
DecryptTransform::Make()
1049 DecryptTransform
* tr
= new DecryptTransform();
1050 SecTransformRef str
= (SecTransformRef
) CoreFoundationHolder::MakeHolder(kDecryptTransformType
, tr
);
1054 /* --------------------------------------------------------------------------
1055 Interface and implementation of the DecryptTransformFactory
1056 -------------------------------------------------------------------------- */
1058 class DecryptTransformFactory
: public TransformFactory
1061 DecryptTransformFactory();
1066 /* --------------------------------------------------------------------------
1067 method: DecryptTransformFactory (Constructor)
1069 -------------------------------------------------------------------------- */
1070 DecryptTransformFactory::DecryptTransformFactory() :
1071 TransformFactory(kDecryptTransformType
)
1075 /* --------------------------------------------------------------------------
1076 method: MakeTransformFactory
1077 description: Make an instance of this factory class
1078 -------------------------------------------------------------------------- */
1079 TransformFactory
* DecryptTransform::MakeTransformFactory()
1081 return new DecryptTransformFactory
;
1084 /* --------------------------------------------------------------------------
1086 description: Create an instance of this class
1087 -------------------------------------------------------------------------- */
1088 CFTypeRef
DecryptTransformFactory::Make()
1090 return DecryptTransform::Make();