I am attempting to implement some AES256 crypto routines in Apple Swift to kinda toy around with the interoperability between ObjC, C, and Swift code and data types, and have run into a bit of an issue and am hoping someone has some suggestions on something I've overlooked.
As most are familiar, common C-style pattern is to declare an uninitialized pointer and then pass that into a function, wherein the function call malloc()s an object and points the pointer to it; after the function call completes the pointer points to the newly-created object. The Common Crypto libraries use this in some places; most notably when creating a new CCCryptor object (really a struct behind the scenes, it looks like, typedef'ed to CCCryptorRef for an opaque reference) - the final argument to the call to CCCryptorCreate() is such a pointer and should, at the conclusion of the function call, contain a pointer to the CCCryptorRef.
Swift puts a wrinkle into this - variables cannot be uninitialized, they always either have a value or are nil(/optional), and thus I've run into a bit of a bump here. The following doesn't work because CCCryptorCreate (rightfully) acts as though I'm just passing nil as the last argument, which I am:
var myCryptorRef: CMutablePointer<Unmanaged<CCCryptorRef>?> = nil
CCCryptorCreate(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES128),
CCOptions(kCCOptionECBMode), seedData.bytes(), UInt(kCCKeySizeAES256),
nil, myCryptorRef)
But neither can you declare it as an optional, like so:
var myCryptorRef: CMutablePointer<Unmanaged<CCCryptorRef>?>?
Or as a non-pointer type:
var myCryptoRef: Unmanaged<CCCryptorRef>?
CCCryptorCreate(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES128),
CCOptions(kCCOptionECBMode), seedData.bytes(), UInt(kCCKeySizeAES256),
nil, &myCryptorRef)
Since what CCCryptorCreate expects is either an uninitialized pointer to a CCCryptorRef or an already-malloc()'ed CCCryptorRef, attempting to pass it the address of a not-yet-initialized object doesn't go very well as you might expect.
So, it comes down to this: can anyone come up with a way to initialize that CCCryptor struct before the call to CCCryptorCreate (the Swift-standard method of struct init by naming all variables inside the struct does not seem to work), or some alternate construction that would allow me to preserve the C concept of the uninitialized pointer for use in this way? Thank you for any suggestions you may have.
Adding for clarity from the comments: Swift interprets the call to CCCryptorCreate() as the following:
CCCryptorCreate(op: CCOperation, alg: CCAlgorithm, options: CCOptions,
key: CConstVoidPointer, keyLength: UInt, iv: CConstVoidPointer,
cryptorRef: CMutablePointer<Unmanaged<CCCryptor>?>)
An additional edit for some other things I've tried: Just to be truly absurd, I tried the following, but it also did not work (EXC_BAD_ACCESS on the call to fromOpaque):
var someMem = malloc(UInt(sizeof(CCCryptor)))
var crashTime = Unmanaged<CCCryptor>.fromOpaque(someMem)
Also, every place CCCryptor or CCCryptorRef is mentioned, I have tried either one - in CommonCrypto/CommonCryptor.h, CCCryptorRef is defined thusly:
typedef struct _CCCryptor *CCCryptorRef
So while existing Objective-C code examples use CCCryptorRef, I've been trying either.
Try this:
var myCryptor: Unmanaged<CCCryptor>?
CCCryptorCreate( .... , &myCryptor )
From Using Swift with Cocoa and Objective-C
If you have declared a function like this one:
func takesAMutablePointer(x: CMutablePointer<Float>) { /*...*/ }
You can call it in any of the following ways:
var x: Float = 0.0 var p: CMutablePointer<Float> = nil var a: Float[] = [1.0, 2.0, 3.0] takesAMutablePointer(nil) takesAMutablePointer(p) takesAMutablePointer(&x) takesAMutablePointer(&a)
You should also check out this and convert the Unmanaged
reference into something that is managed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With