2 // SecMaskGenerationFunctionTransform.c
3 // libsecurity_transform
5 // Created by Josh Osborne on 10/6/11.
6 // Copyright 2011 Apple. All rights reserved.
10 #include <CoreFoundation/CoreFoundation.h>
11 #include "SecMaskGenerationFunctionTransform.h"
12 #include "SecCustomTransform.h"
13 #include "SecDigestTransform.h"
15 #include "Utilities.h"
17 static const CFStringRef kMaskGenerationFunctionTransformName
= CFSTR("com.apple.security.MGF1");
18 static const CFStringRef kLengthName
= CFSTR("Length");
20 static SecTransformInstanceBlock
MaskGenerationFunctionTransform(CFStringRef name
,
21 SecTransformRef newTransform
,
22 SecTransformImplementationRef ref
)
24 __block CFMutableDataRef accumulator
= CFDataCreateMutable(NULL
, 0);
25 __block
int32_t outputLength
= 0;
27 SecTransformInstanceBlock instanceBlock
= ^{
28 SecTransformSetTransformAction(ref
, kSecTransformActionFinalize
, ^{
29 CFRelease(accumulator
);
31 return (CFTypeRef
)NULL
;
34 // XXX: be a good citizen, put a validator in for the types.
36 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kLengthName
, ^CFTypeRef(SecTransformAttributeRef attribute
, CFTypeRef value
) {
37 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &outputLength
);
38 if (outputLength
<= 0) {
39 SecTransformCustomSetAttribute(ref
, kSecTransformAbortAttributeName
, kSecTransformMetaAttributeValue
, CreateSecTransformErrorRef(kSecTransformErrorInvalidLength
, "MaskGenerationFunction Length must be one or more (not %@)", value
));
42 return (CFTypeRef
)NULL
;
45 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecTransformInputAttributeName
, ^CFTypeRef(SecTransformAttributeRef attribute
, CFTypeRef value
) {
48 CFDataAppendBytes(accumulator
, CFDataGetBytePtr(d
), CFDataGetLength(d
));
51 (void)transforms_assume(outputLength
> 0);
52 CFStringRef digestType
= SecTranformCustomGetAttribute(ref
, kSecDigestTypeAttribute
, kSecTransformMetaAttributeValue
);
53 SecTransformRef digest0
= transforms_assume(SecDigestTransformCreate(digestType
, 0, NULL
));
54 int32_t digestLength
= 0;
56 CFNumberRef digestLengthAsCFNumber
= SecTransformGetAttribute(digest0
, kSecDigestLengthAttribute
);
57 CFNumberGetValue(transforms_assume(digestLengthAsCFNumber
), kCFNumberSInt32Type
, &digestLength
);
59 (void)transforms_assume(digestLength
>= 0);
61 UInt8
*buffer
= malloc(outputLength
+ digestLength
);
63 SecTransformCustomSetAttribute(ref
, kSecTransformAbortAttributeName
, kSecTransformMetaAttributeValue
, GetNoMemoryErrorAndRetain());
64 return (CFErrorRef
)NULL
;
67 dispatch_group_t all_hashed
= dispatch_group_create();
68 dispatch_group_enter(all_hashed
);
69 for(; l
< outputLength
; l
+= digestLength
, i
++) {
70 dispatch_group_enter(all_hashed
);
71 CFErrorRef err
= NULL
;
72 SecTransformRef digest
= NULL
;
76 digest
= SecDigestTransformCreate(digestType
, 0, &err
);
78 SecTransformCustomSetAttribute(ref
, kSecTransformAbortAttributeName
, kSecTransformMetaAttributeValue
, err
);
79 return (CFErrorRef
)NULL
;
83 // NOTE: we shuld be able to do this without the copy, make a transform that takes an
84 // array and outputs each item in the array followed by a NULL ought to be quicker.
85 CFMutableDataRef accumulatorPlusCounter
= CFDataCreateMutableCopy(NULL
, CFDataGetLength(accumulator
) + sizeof(uint32_t), accumulator
);
86 int32_t bigendian_i
= htonl(i
);
87 CFDataAppendBytes(accumulatorPlusCounter
, (UInt8
*)&bigendian_i
, sizeof(bigendian_i
));
88 SecTransformSetAttribute(digest
, kSecTransformInputAttributeName
, accumulatorPlusCounter
, &err
);
89 CFRelease(accumulatorPlusCounter
);
91 UInt8
*buf
= buffer
+ l
;
92 SecTransformExecuteAsync(digest
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(CFTypeRef message
, CFErrorRef error
, Boolean isFinal
) {
94 CFIndex messageLen
= CFDataGetLength(message
);
95 CFDataGetBytes(message
, CFRangeMake(0, messageLen
), buf
);
98 SecTransformCustomSetAttribute(ref
, kSecTransformAbortAttributeName
, kSecTransformMetaAttributeValue
, error
);
101 dispatch_group_leave(all_hashed
);
107 dispatch_group_leave(all_hashed
);
108 dispatch_group_wait(all_hashed
, DISPATCH_TIME_FOREVER
);
109 CFDataRef out
= CFDataCreateWithBytesNoCopy(NULL
, buffer
, outputLength
, kCFAllocatorMalloc
);
110 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, out
);
112 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, NULL
);
114 return (CFErrorRef
)NULL
;
117 return (CFErrorRef
)NULL
;
120 return Block_copy(instanceBlock
);
123 SecTransformRef
SecCreateMaskGenerationFunctionTransform(CFStringRef hashType
, int length
, CFErrorRef
*error
)
125 static dispatch_once_t once
;
126 __block Boolean ok
= TRUE
;
130 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidLength
, "MaskGenerationFunction Length must be one or more (not %d)", length
);
135 dispatch_once(&once
, ^(void) {
136 ok
= SecTransformRegister(kMaskGenerationFunctionTransformName
, MaskGenerationFunctionTransform
, error
);
143 SecTransformRef ret
= SecTransformCreate(kMaskGenerationFunctionTransformName
, error
);
148 if (!SecTransformSetAttribute(ret
, kSecDigestTypeAttribute
, hashType
? hashType
: kSecDigestSHA1
, error
)) {
153 CFNumberRef len
= CFNumberCreate(NULL
, kCFNumberIntType
, &length
);
154 ok
= SecTransformSetAttribute(ret
, kLengthName
, len
, error
);