1/* 2 * Digest_block.cpp 3 * libsecurity_transform 4 * 5 * Created by JOsborne on 2/20/10. 6 * Copyright 2010 Apple. All rights reserved. 7 * 8 */ 9 10#include "Digest_block.h" 11#include "SecCustomTransform.h" 12#include <CommonCrypto/CommonDigest.h> 13#include "Utilities.h" 14 15extern const CFStringRef kSecDigestMD2, kSecDigestMD4, kSecDigestMD5, kSecDigestSHA1, kSecDigestSHA2; 16extern const CFStringRef kSecDigestTypeAttribute, kSecDigestLengthAttribute; 17 18 19static CFStringRef kCustomDigestTransformName = CFSTR("com.apple.security.digest"); 20 21SecTransformRef SecDigestTransformCreate_block(SecProviderRef device, CFTypeRef digestType, CFIndex digestLength, CFErrorRef* error) { 22 static dispatch_once_t inited; 23 __block CFStringRef current_algo; 24 __block CFIndex current_length; 25 26 dispatch_once(&inited, ^{ 27 SecTransformRegister(kCustomDigestTransformName, ^(CFStringRef name, SecTransformRebindActionBlock rebind) { 28 rebind(kSecTransformActionProcessData, NULL, ^(SecTransformRef tr, CFDataRef d, SecTransformSendAttribute set) { 29 set(kSecDigestTypeAttribute, kSecDigestSHA2); 30 }); 31 rebind(SecTransformSetAttributeAction, NULL, ^(SecTransformRef tr, CFStringRef name, CFTypeRef value, SecTransformSendAttribute set) { 32 Boolean algo_changed = FALSE; 33 if (name == kSecDigestTypeAttribute || CFStringCompare(kSecDigestTypeAttribute, name, 0) == kCFCompareEqualTo) { 34 algo_changed = TRUE; 35 current_algo = CFStringCreateCopy(NULL, (CFStringRef)value); 36 37 } else if (name == kSecDigestLengthAttribute || CFStringCompare(kSecDigestLengthAttribute, name, 0) == kCFCompareEqualTo) { 38 algo_changed = TRUE; 39 CFNumberGetValue(value, kCFNumberCFIndexType, ¤t_length); 40 } else if (CFStringCompare(kSecTransformInputAttributeName, name, 0) == kCFCompareEqualTo) { 41 return (CFTypeRef)CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "The type %@ is invalid.", name); 42 } else { 43 return (CFTypeRef)CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "The type %@ is invalid.", name); 44 } 45 if (!algo_changed) { 46 return value; 47 } 48 49 if (current_algo == kSecDigestSHA2 || CFStringCompare(current_algo, kSecDigestSHA2, 0) == kCFCompareEqualTo) { 50 switch (current_length) { 51 case 0: 52 case 512: { 53 __block CC_SHA512_CTX cc_context; 54 CC_SHA512_Init(&cc_context); 55 rebind(kSecTransformActionProcessData, NULL, ^(SecTransformRef tr, CFDataRef d, SecTransformSendAttribute set) { 56 if (d) { 57 CC_SHA512_Update(&cc_context, CFDataGetBytePtr(d), CFDataGetLength(d)); 58 return SecTransformNoData(); 59 } else { 60 u_int8_t digest_buffer[CC_SHA512_DIGEST_LENGTH]; 61 62 CC_SHA512_Final(digest_buffer, &cc_context); 63 set(kSecTransformOutputAttributeName, CFDataCreate(NULL, digest_buffer, CC_SHA512_DIGEST_LENGTH)); 64 return NULL; 65 } 66 }); 67 return value; 68 } 69 } 70 return (CFTypeRef)CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "Invalid length."); 71 } else { 72 return (CFTypeRef)CreateSecTransformErrorRef(kSecTransformErrorInvalidAlgorithm, "Invalid algorithm."); 73 } 74 }); 75 }, NULL); 76 }); 77 78 SecTransformRef dt = SecTransformCreate(kCustomDigestTransformName, NULL); 79 SecTransformSetAttribute(dt, kSecDigestTypeAttribute, digestType, error); 80 CFNumberRef dlen = CFNumberCreate(NULL, kCFNumberCFIndexType, &digestLength); 81 SecTransformSetAttribute(dt, kSecDigestLengthAttribute, dlen, error); 82 CFRelease(dlen); 83 84 return dt; 85} 86