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@
26 #include "SecTransform.h"
27 #include "SecCustomTransform.h"
28 #include "SecDigestTransform.h"
32 const CFStringRef kCaesarCipher = CFSTR("com.yourcompany.caesarcipher");
33 const CFStringRef kKeyAttributeName = CFSTR("key");
35 // =========================================================================
36 // Registration function for a ROT-N (caesar cipher)
37 // =========================================================================
38 Boolean RegisterMyCustomTransform()
40 static dispatch_once_t once;
41 __block Boolean ok = FALSE;
42 __block CFErrorRef error = NULL;
44 SecTransformCreateBlock createCaesar = NULL;
46 // Create the SecTransformCreateBlock block that will be used to
47 // register this custom transform
48 createCaesar =^(CFStringRef name, SecTransformRef new_transform,
49 const SecTransformCreateBlockParameters* parameters)
52 CFErrorRef result = NULL;
54 // Some basic parameter checking.
55 if (NULL == name || NULL == new_transform )
58 result = CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
59 kSecTransformErrorInvalidInput, NULL);
63 // Every time a new instance of this custom transform class is
64 // created, this block will be called. This behavior means that any
65 // block variables created in this block will act like instance
66 // variables for the new custom transform instance. In this case
67 // the key variable will be in every instance of this custom
72 // Use the overrideAttribute block to have our custom transform
73 // be notified if the 'key' attribute is set
75 parameters->overrideAttribute(
76 kSecCustomTransformAttributeSetNotification,
78 ^(SecTransformAttributeRef name, CFTypeRef d)
80 CFTypeRef result = NULL;
88 // Ensure the correct data type for this attribute
89 if (CFGetTypeID(d) == CFNumberGetTypeID())
93 if (!CFNumberGetValue((CFNumberRef)d,
94 kCFNumberIntType, &_key))
98 result = (CFTypeRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
99 kSecTransformErrorInvalidInput, NULL);
113 // Use the overrideAttribute to change the processing of the data
114 // for this transform
115 parameters->overrideAttribute(kSecCustomTransformProcessData,
117 ^(SecTransformAttributeRef name, CFTypeRef d)
119 CFTypeRef result = NULL;
123 result = (CFTypeRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
124 kSecTransformErrorInvalidInput, NULL);
129 if (CFGetTypeID(d) != CFDataGetTypeID())
132 result = (CFTypeRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
133 kSecTransformErrorInvalidInput, NULL);
138 CFDataRef theData = (CFDataRef)d;
140 CFIndex dataLength = CFDataGetLength(theData);
142 // Do the processing in memory. There are better ways to do
143 // this but for showing how custom transforms work this is fine.
144 char* buffer = (char*)malloc(dataLength);
148 result = (CFErrorRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
149 kSecTransformErrorInvalidInput, NULL);
154 const char* dataPtr = (const char* )CFDataGetBytePtr(theData);
159 result = (CFErrorRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
160 kSecTransformErrorInvalidInput, NULL);
164 // Do the work of the caesar cipher (Rot(n))
166 char rotValue = (char)_key;
168 for (iCnt = 0; iCnt < dataLength; iCnt++)
170 buffer[iCnt] = dataPtr[iCnt] + rotValue;
173 result = (CFTypeRef)CFDataCreate(kCFAllocatorDefault,
174 (const UInt8 *)buffer, dataLength);
181 // Make sure the custom transform is only registered once
184 (void)SecCustomTransformRegister(kCaesarCipher, &error,
188 return (error == NULL);
191 //The second function show how to use the this custom transform:
193 // =========================================================================
194 // Use a custom ROT-N (caesar cipher) transform
195 // =========================================================================
196 CFStringRef DoCaesar(CFStringRef clearTest, int rotNumber)
198 CFStringRef result = NULL;
200 if (NULL == clearTest)
205 if (!RegisterMyCustomTransform())
210 CFErrorRef error = NULL;
212 SecTransformRef caesarCipher =
213 SecCustomTransformCreate(kCaesarCipher, &error);
214 if (NULL == caesarCipher || NULL != error)
220 CFStringCreateExternalRepresentation(kCFAllocatorDefault,
221 clearTest, kCFStringEncodingUTF8, 0);
224 CFRelease(caesarCipher);
228 SecTransformSetAttribute(caesarCipher,
229 kSecTransformInputAttributeName, data, &error);
233 CFRelease(caesarCipher);
237 CFNumberRef keyNumber =
238 CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &rotNumber);
239 if (NULL == keyNumber)
241 CFRelease(caesarCipher);
245 SecTransformSetAttribute(caesarCipher, kKeyAttributeName,
247 CFRelease(keyNumber);
250 CFRelease(caesarCipher);
254 CFDataRef dataResult =
255 (CFDataRef)SecTransformExecute(caesarCipher, &error);
256 CFRelease(caesarCipher);
257 if (NULL != dataResult && NULL == error)
260 CFStringCreateFromExternalRepresentation(kCFAllocatorDefault,
261 dataResult, kCFStringEncodingUTF8);
262 CFRelease(dataResult);
268 int main(int argc, char *argv[])
270 if (!RegisterMyCustomTransform())
275 CFStringRef testStr = CFSTR("When in the course of human event");
276 CFStringRef aStr = DoCaesar(testStr, 4);
277 CFStringRef clearStr = DoCaesar(aStr, -4);
278 if (CFEqual(testStr, clearStr))
280 CFShow(CFSTR("All is right with the world"));
284 CFShow(CFSTR("Bummer!"));
292 CFReadStreamRef CFReadStreamCreateWithFD(CFAllocatorRef a, int fd) {
294 asprintf(&fname, "/dev/fd/%d", fd);
295 CFURLRef f = CFURLCreateFromFileSystemRepresentation(a, (UInt8*)fname, strlen(fname), FALSE);
296 CFReadStreamRef rd = CFReadStreamCreateWithFile(a, f);
302 void pair_CFReadStream_fd(CFReadStreamRef *sr, int *fd) {
307 *sr = CFReadStreamCreateWithFD(NULL, fds[0]);
310 CFReadStreamRef many_zeros(uint64_t goal) {
313 pair_CFReadStream_fd(&rd, &fd);
315 // XXX: replace with a dispatch_source and non-blocking I/O...
316 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
317 uint64_t nwrites = 0;
319 bzero(buf, sizeof(buf));
320 uint64_t left = goal;
323 size_t try = (sizeof(buf) < left) ? sizeof(buf) : left;
324 ssize_t sz = write(fd, buf, try);
326 fprintf(stderr, "Write return %zd, errno=%d\n", sz, errno);
340 int main(int argc, char *argv[]) {
341 CFReadStreamRef rd = many_zeros(1024*1024 *100LL);
342 Boolean ok = CFReadStreamOpen(rd);
345 SecTransformRef dt = SecDigestTransformCreate(kSecDigestSHA2, 512, NULL);
346 SecTransformSetAttribute(dt, kSecTransformInputAttributeName, rd, NULL);
348 CFDataRef d = SecTransformExecute(dt, NULL);