2 * Copyright (c) 2010-2011,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 "Digest_block.h"
26 #include "SecCustomTransform.h"
27 #include <CommonCrypto/CommonDigest.h>
28 #include "Utilities.h"
30 extern const CFStringRef kSecDigestMD2
, kSecDigestMD4
, kSecDigestMD5
, kSecDigestSHA1
, kSecDigestSHA2
;
31 extern const CFStringRef kSecDigestTypeAttribute
, kSecDigestLengthAttribute
;
34 static CFStringRef kCustomDigestTransformName
= CFSTR("com.apple.security.digest");
36 SecTransformRef
SecDigestTransformCreate_block(SecProviderRef device
, CFTypeRef digestType
, CFIndex digestLength
, CFErrorRef
* error
) {
37 static dispatch_once_t inited
;
38 __block CFStringRef current_algo
;
39 __block CFIndex current_length
;
41 dispatch_once(&inited
, ^{
42 SecTransformRegister(kCustomDigestTransformName
, ^(CFStringRef name
, SecTransformRebindActionBlock rebind
) {
43 rebind(kSecTransformActionProcessData
, NULL
, ^(SecTransformRef tr
, CFDataRef d
, SecTransformSendAttribute set
) {
44 set(kSecDigestTypeAttribute
, kSecDigestSHA2
);
46 rebind(SecTransformSetAttributeAction
, NULL
, ^(SecTransformRef tr
, CFStringRef name
, CFTypeRef value
, SecTransformSendAttribute set
) {
47 Boolean algo_changed
= FALSE
;
48 if (name
== kSecDigestTypeAttribute
|| CFStringCompare(kSecDigestTypeAttribute
, name
, 0) == kCFCompareEqualTo
) {
50 current_algo
= CFStringCreateCopy(NULL
, (CFStringRef
)value
);
52 } else if (name
== kSecDigestLengthAttribute
|| CFStringCompare(kSecDigestLengthAttribute
, name
, 0) == kCFCompareEqualTo
) {
54 CFNumberGetValue(value
, kCFNumberCFIndexType
, ¤t_length
);
55 } else if (CFStringCompare(kSecTransformInputAttributeName
, name
, 0) == kCFCompareEqualTo
) {
56 return (CFTypeRef
)CreateSecTransformErrorRef(kSecTransformErrorInvalidType
, "The type %@ is invalid.", name
);
58 return (CFTypeRef
)CreateSecTransformErrorRef(kSecTransformErrorInvalidType
, "The type %@ is invalid.", name
);
64 if (current_algo
== kSecDigestSHA2
|| CFStringCompare(current_algo
, kSecDigestSHA2
, 0) == kCFCompareEqualTo
) {
65 switch (current_length
) {
68 __block CC_SHA512_CTX cc_context
;
69 CC_SHA512_Init(&cc_context
);
70 rebind(kSecTransformActionProcessData
, NULL
, ^(SecTransformRef tr
, CFDataRef d
, SecTransformSendAttribute set
) {
72 CC_SHA512_Update(&cc_context
, CFDataGetBytePtr(d
), CFDataGetLength(d
));
73 return SecTransformNoData();
75 u_int8_t digest_buffer
[CC_SHA512_DIGEST_LENGTH
];
77 CC_SHA512_Final(digest_buffer
, &cc_context
);
78 set(kSecTransformOutputAttributeName
, CFDataCreate(NULL
, digest_buffer
, CC_SHA512_DIGEST_LENGTH
));
85 return (CFTypeRef
)CreateSecTransformErrorRef(kSecTransformErrorInvalidLength
, "Invalid length.");
87 return (CFTypeRef
)CreateSecTransformErrorRef(kSecTransformErrorInvalidAlgorithm
, "Invalid algorithm.");
93 SecTransformRef dt
= SecTransformCreate(kCustomDigestTransformName
, NULL
);
94 SecTransformSetAttribute(dt
, kSecDigestTypeAttribute
, digestType
, error
);
95 CFNumberRef dlen
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &digestLength
);
96 SecTransformSetAttribute(dt
, kSecDigestLengthAttribute
, dlen
, error
);