--- /dev/null
+/*
+ * Copyright (c) 2010-2011,2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+#include "SecTransform.h"
+#include "SecCustomTransform.h"
+#include "SecDigestTransform.h"
+#include <assert.h>
+#include <unistd.h>
+
+const CFStringRef kCaesarCipher = CFSTR("com.yourcompany.caesarcipher");
+const CFStringRef kKeyAttributeName = CFSTR("key");
+
+// =========================================================================
+// Registration function for a ROT-N (caesar cipher)
+// =========================================================================
+Boolean RegisterMyCustomTransform()
+{
+ static dispatch_once_t once;
+ __block Boolean ok = FALSE;
+ __block CFErrorRef error = NULL;
+
+ SecTransformCreateBlock createCaesar = NULL;
+
+ // Create the SecTransformCreateBlock block that will be used to
+ // register this custom transform
+ createCaesar =^(CFStringRef name, SecTransformRef new_transform,
+ const SecTransformCreateBlockParameters* parameters)
+ {
+
+ CFErrorRef result = NULL;
+
+ // Some basic parameter checking.
+ if (NULL == name || NULL == new_transform )
+ {
+ // return the error
+ result = CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
+ kSecTransformErrorInvalidInput, NULL);
+
+ return result;
+ }
+ // Every time a new instance of this custom transform class is
+ // created, this block will be called. This behavior means that any
+ // block variables created in this block will act like instance
+ // variables for the new custom transform instance. In this case
+ // the key variable will be in every instance of this custom
+ // caesar transform
+
+ __block int _key;
+
+ // Use the overrideAttribute block to have our custom transform
+ // be notified if the 'key' attribute is set
+
+ parameters->overrideAttribute(
+ kSecCustomTransformAttributeSetNotification,
+ kKeyAttributeName,
+ ^(SecTransformAttributeRef name, CFTypeRef d)
+ {
+ CFTypeRef result = NULL;
+
+ if (NULL == d)
+ {
+ _key = 0;
+ return result;
+ }
+
+ // Ensure the correct data type for this attribute
+ if (CFGetTypeID(d) == CFNumberGetTypeID())
+ {
+ _key = 0;
+
+ if (!CFNumberGetValue((CFNumberRef)d,
+ kCFNumberIntType, &_key))
+ {
+ _key = 0;
+ // return the error
+ result = (CFTypeRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
+ kSecTransformErrorInvalidInput, NULL);
+
+ return result;
+ }
+ else
+ {
+ result = d;
+ }
+ }
+
+ return result;
+
+ });
+
+ // Use the overrideAttribute to change the processing of the data
+ // for this transform
+ parameters->overrideAttribute(kSecCustomTransformProcessData,
+ NULL,
+ ^(SecTransformAttributeRef name, CFTypeRef d)
+ {
+ CFTypeRef result = NULL;
+ if (NULL == d)
+ {
+ // return the error
+ result = (CFTypeRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
+ kSecTransformErrorInvalidInput, NULL);
+
+ return result;
+ }
+
+ if (CFGetTypeID(d) != CFDataGetTypeID())
+ {
+ // return the error
+ result = (CFTypeRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
+ kSecTransformErrorInvalidInput, NULL);
+
+ return result;
+ }
+
+ CFDataRef theData = (CFDataRef)d;
+
+ CFIndex dataLength = CFDataGetLength(theData);
+
+ // Do the processing in memory. There are better ways to do
+ // this but for showing how custom transforms work this is fine.
+ char* buffer = (char*)malloc(dataLength);
+ if (NULL == buffer)
+ {
+ //return the error
+ result = (CFErrorRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
+ kSecTransformErrorInvalidInput, NULL);
+
+ return result;
+ }
+
+ const char* dataPtr = (const char* )CFDataGetBytePtr(theData);
+ if (NULL == dataPtr)
+ {
+ free(buffer);
+ //return the error
+ result = (CFErrorRef)CFErrorCreate(kCFAllocatorDefault, SECTRANSFORM_ERROR_DOMAIN,
+ kSecTransformErrorInvalidInput, NULL);
+
+ return result;
+ }
+ // Do the work of the caesar cipher (Rot(n))
+
+ char rotValue = (char)_key;
+ CFIndex iCnt;
+ for (iCnt = 0; iCnt < dataLength; iCnt++)
+ {
+ buffer[iCnt] = dataPtr[iCnt] + rotValue;
+ }
+
+ result = (CFTypeRef)CFDataCreate(kCFAllocatorDefault,
+ (const UInt8 *)buffer, dataLength);
+ free(buffer);
+ return result;
+
+ });
+ };
+
+ // Make sure the custom transform is only registered once
+ dispatch_once(&once,
+ ^{
+ (void)SecCustomTransformRegister(kCaesarCipher, &error,
+ createCaesar);
+ });
+
+ return (error == NULL);
+}
+
+//The second function show how to use the this custom transform:
+
+// =========================================================================
+// Use a custom ROT-N (caesar cipher) transform
+// =========================================================================
+CFStringRef DoCaesar(CFStringRef clearTest, int rotNumber)
+{
+ CFStringRef result = NULL;
+
+ if (NULL == clearTest)
+ {
+ return result;
+ }
+
+ if (!RegisterMyCustomTransform())
+ {
+ return result;
+ }
+
+ CFErrorRef error = NULL;
+
+ SecTransformRef caesarCipher =
+ SecCustomTransformCreate(kCaesarCipher, &error);
+ if (NULL == caesarCipher || NULL != error)
+ {
+ return result;
+ }
+
+ CFDataRef data =
+ CFStringCreateExternalRepresentation(kCFAllocatorDefault,
+ clearTest, kCFStringEncodingUTF8, 0);
+ if (NULL == data)
+ {
+ CFRelease(caesarCipher);
+ return result;
+ }
+
+ SecTransformSetAttribute(caesarCipher,
+ kSecTransformInputAttributeName, data, &error);
+ CFRelease(data);
+ if (NULL != error)
+ {
+ CFRelease(caesarCipher);
+ return result;
+ }
+
+ CFNumberRef keyNumber =
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &rotNumber);
+ if (NULL == keyNumber)
+ {
+ CFRelease(caesarCipher);
+ return result;
+ }
+
+ SecTransformSetAttribute(caesarCipher, kKeyAttributeName,
+ keyNumber, &error);
+ CFRelease(keyNumber);
+ if (NULL != error)
+ {
+ CFRelease(caesarCipher);
+ return result;
+ }
+
+ CFDataRef dataResult =
+ (CFDataRef)SecTransformExecute(caesarCipher, &error);
+ CFRelease(caesarCipher);
+ if (NULL != dataResult && NULL == error)
+ {
+ result =
+ CFStringCreateFromExternalRepresentation(kCFAllocatorDefault,
+ dataResult, kCFStringEncodingUTF8);
+ CFRelease(dataResult);
+ }
+
+ return result;
+}
+
+int main(int argc, char *argv[])
+{
+ if (!RegisterMyCustomTransform())
+ {
+ return -1;
+ }
+
+ CFStringRef testStr = CFSTR("When in the course of human event");
+ CFStringRef aStr = DoCaesar(testStr, 4);
+ CFStringRef clearStr = DoCaesar(aStr, -4);
+ if (CFEqual(testStr, clearStr))
+ {
+ CFShow(CFSTR("All is right with the world"));
+ return 0;
+ }
+
+ CFShow(CFSTR("Bummer!"));
+ return -1;
+
+}
+
+
+
+/*
+CFReadStreamRef CFReadStreamCreateWithFD(CFAllocatorRef a, int fd) {
+ char *fname;
+ asprintf(&fname, "/dev/fd/%d", fd);
+ CFURLRef f = CFURLCreateFromFileSystemRepresentation(a, (UInt8*)fname, strlen(fname), FALSE);
+ CFReadStreamRef rd = CFReadStreamCreateWithFile(a, f);
+ CFRelease(f);
+
+ return rd;
+}
+
+void pair_CFReadStream_fd(CFReadStreamRef *sr, int *fd) {
+ int fds[2];
+ int rc = pipe(fds);
+ assert(rc >= 0);
+ *fd = fds[1];
+ *sr = CFReadStreamCreateWithFD(NULL, fds[0]);
+}
+
+CFReadStreamRef many_zeros(uint64_t goal) {
+ CFReadStreamRef rd;
+ int fd;
+ pair_CFReadStream_fd(&rd, &fd);
+
+ // XXX: replace with a dispatch_source and non-blocking I/O...
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
+ uint64_t nwrites = 0;
+ char buf[1024*8];
+ bzero(buf, sizeof(buf));
+ uint64_t left = goal;
+
+ while (left) {
+ size_t try = (sizeof(buf) < left) ? sizeof(buf) : left;
+ ssize_t sz = write(fd, buf, try);
+ if (sz <= 0) {
+ fprintf(stderr, "Write return %zd, errno=%d\n", sz, errno);
+ }
+ assert(sz >= 0);
+ left -= sz;
+ nwrites++;
+ }
+
+ close(fd);
+ });
+
+
+ return rd;
+}
+
+int main(int argc, char *argv[]) {
+ CFReadStreamRef rd = many_zeros(1024*1024 *100LL);
+ Boolean ok = CFReadStreamOpen(rd);
+ assert(ok);
+
+ SecTransformRef dt = SecDigestTransformCreate(kSecDigestSHA2, 512, NULL);
+ SecTransformSetAttribute(dt, kSecTransformInputAttributeName, rd, NULL);
+
+ CFDataRef d = SecTransformExecute(dt, NULL);
+
+ return 0;
+}
+*/