3 * libsecurity_transform
5 * Created by JOsborne on 2/20/10.
6 * Copyright 2010 Apple. All rights reserved.
11 #include "SecTransform.h"
12 #include "SecCustomTransform.h"
13 #include "SecDigestTransform.h"
17 const CFStringRef kCaesarCipher = CFSTR("com.yourcompany.caesarcipher");
18 const CFStringRef kKeyAttributeName = CFSTR("key");
20 // =========================================================================
21 // Registration function for a ROT-N (caesar cipher)
22 // =========================================================================
23 Boolean RegisterMyCustomTransform()
25 static dispatch_once_t once;
26 __block Boolean ok = FALSE;
27 __block CFErrorRef error = NULL;
29 SecTransformCreateBlock createCaesar = NULL;
31 // Create the SecTransformCreateBlock block that will be used to
32 // register this custom transform
33 createCaesar =^(CFStringRef name, SecTransformRef new_transform,
34 const SecTransformCreateBlockParameters* parameters)
37 CFErrorRef result = NULL;
39 // Some basic parameter checking.
40 if (NULL == name || NULL == new_transform )
43 result = CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
44 kSecTransformErrorInvalidInput, NULL);
48 // Every time a new instance of this custom transform class is
49 // created, this block will be called. This behavior means that any
50 // block variables created in this block will act like instance
51 // variables for the new custom transform instance. In this case
52 // the key variable will be in every instance of this custom
57 // Use the overrideAttribute block to have our custom transform
58 // be notified if the 'key' attribute is set
60 parameters->overrideAttribute(
61 kSecCustomTransformAttributeSetNotification,
63 ^(SecTransformAttributeRef name, CFTypeRef d)
65 CFTypeRef result = NULL;
73 // Ensure the correct data type for this attribute
74 if (CFGetTypeID(d) == CFNumberGetTypeID())
78 if (!CFNumberGetValue((CFNumberRef)d,
79 kCFNumberIntType, &_key))
83 result = (CFTypeRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
84 kSecTransformErrorInvalidInput, NULL);
98 // Use the overrideAttribute to change the processing of the data
100 parameters->overrideAttribute(kSecCustomTransformProcessData,
102 ^(SecTransformAttributeRef name, CFTypeRef d)
104 CFTypeRef result = NULL;
108 result = (CFTypeRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
109 kSecTransformErrorInvalidInput, NULL);
114 if (CFGetTypeID(d) != CFDataGetTypeID())
117 result = (CFTypeRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
118 kSecTransformErrorInvalidInput, NULL);
123 CFDataRef theData = (CFDataRef)d;
125 CFIndex dataLength = CFDataGetLength(theData);
127 // Do the processing in memory. There are better ways to do
128 // this but for showing how custom transforms work this is fine.
129 char* buffer = (char*)malloc(dataLength);
133 result = (CFErrorRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
134 kSecTransformErrorInvalidInput, NULL);
139 const char* dataPtr = (const char* )CFDataGetBytePtr(theData);
144 result = (CFErrorRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
145 kSecTransformErrorInvalidInput, NULL);
149 // Do the work of the caesar cipher (Rot(n))
151 char rotValue = (char)_key;
153 for (iCnt = 0; iCnt < dataLength; iCnt++)
155 buffer[iCnt] = dataPtr[iCnt] + rotValue;
158 result = (CFTypeRef)CFDataCreate(kCFAllocatorDefault,
159 (const UInt8 *)buffer, dataLength);
166 // Make sure the custom transform is only registered once
169 (void)SecCustomTransformRegister(kCaesarCipher, &error,
173 return (error == NULL);
176 //The second function show how to use the this custom transform:
178 // =========================================================================
179 // Use a custom ROT-N (caesar cipher) transform
180 // =========================================================================
181 CFStringRef DoCaesar(CFStringRef clearTest, int rotNumber)
183 CFStringRef result = NULL;
185 if (NULL == clearTest)
190 if (!RegisterMyCustomTransform())
195 CFErrorRef error = NULL;
197 SecTransformRef caesarCipher =
198 SecCustomTransformCreate(kCaesarCipher, &error);
199 if (NULL == caesarCipher || NULL != error)
205 CFStringCreateExternalRepresentation(kCFAllocatorDefault,
206 clearTest, kCFStringEncodingUTF8, 0);
209 CFRelease(caesarCipher);
213 SecTransformSetAttribute(caesarCipher,
214 kSecTransformInputAttributeName, data, &error);
218 CFRelease(caesarCipher);
222 CFNumberRef keyNumber =
223 CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &rotNumber);
224 if (NULL == keyNumber)
226 CFRelease(caesarCipher);
230 SecTransformSetAttribute(caesarCipher, kKeyAttributeName,
232 CFRelease(keyNumber);
235 CFRelease(caesarCipher);
239 CFDataRef dataResult =
240 (CFDataRef)SecTransformExecute(caesarCipher, &error);
241 CFRelease(caesarCipher);
242 if (NULL != dataResult && NULL == error)
245 CFStringCreateFromExternalRepresentation(kCFAllocatorDefault,
246 dataResult, kCFStringEncodingUTF8);
247 CFRelease(dataResult);
253 int main(int argc, char *argv[])
255 if (!RegisterMyCustomTransform())
260 CFStringRef testStr = CFSTR("When in the course of human event");
261 CFStringRef aStr = DoCaesar(testStr, 4);
262 CFStringRef clearStr = DoCaesar(aStr, -4);
263 if (CFEqual(testStr, clearStr))
265 CFShow(CFSTR("All is right with the world"));
269 CFShow(CFSTR("Bummer!"));
277 CFReadStreamRef CFReadStreamCreateWithFD(CFAllocatorRef a, int fd) {
279 asprintf(&fname, "/dev/fd/%d", fd);
280 CFURLRef f = CFURLCreateFromFileSystemRepresentation(a, (UInt8*)fname, strlen(fname), FALSE);
281 CFReadStreamRef rd = CFReadStreamCreateWithFile(a, f);
287 void pair_CFReadStream_fd(CFReadStreamRef *sr, int *fd) {
292 *sr = CFReadStreamCreateWithFD(NULL, fds[0]);
295 CFReadStreamRef many_zeros(uint64_t goal) {
298 pair_CFReadStream_fd(&rd, &fd);
300 // XXX: replace with a dispatch_source and non-blocking I/O...
301 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
302 uint64_t nwrites = 0;
304 bzero(buf, sizeof(buf));
305 uint64_t left = goal;
308 size_t try = (sizeof(buf) < left) ? sizeof(buf) : left;
309 ssize_t sz = write(fd, buf, try);
311 fprintf(stderr, "Write return %zd, errno=%d\n", sz, errno);
325 int main(int argc, char *argv[]) {
326 CFReadStreamRef rd = many_zeros(1024*1024 *100LL);
327 Boolean ok = CFReadStreamOpen(rd);
330 SecTransformRef dt = SecDigestTransformCreate(kSecDigestSHA2, 512, NULL);
331 SecTransformSetAttribute(dt, kSecTransformInputAttributeName, rd, NULL);
333 CFDataRef d = SecTransformExecute(dt, NULL);