So
lets get started. You will need XCode
beta 6 to work with Swift so if you have not already downloaded/installed it
you will need to do so now. You will
also need to download the RNCryptor code, you can do that from GitHub here. Once
you have XCode 6 beta set up start a new project and select the Single View
Application template.
On
the next option screen, enter the name of your project and then select Swift as
the language.
Finally
select the location of your project and now you are ready to start. The first thing you will want to do is to copy
the RNCryptor source files to your project.
You can do this by highlighting the files to copy and then drag them
into your project.
After
you drop the files into your project, XCode will ask if you would like to
configure an Objective-C bridging header, select Yes to create the header. The bridging header will be named like this
{project name}-Bridging-Header.h.
Now
we will need to add two of the RNCryptor header files to the bridging header
file, this will make the classes available to our Swift classes. Add the following lines to you bridging
header:
#import
"RNEncryptor.h"
#import
"RNDecryptor.h"
I ran into two problems adding RNCryptor to
my Swift project. The first problem was
I could not access the constants defined in the RNCryptor.h header file even if
I added it to the bridging header. I am
encrypting the data using the encryptData:withSettings:password:error: method
from the RNEncryptor class. This method
takes an RNCryptorSettings object for the withSettings parameter
however these settings are defined as constants in the RNCryptor header file
which I was unable to access. The second
problem I had was trying to convert an NSData object to a NSString.
I am unsure if there is a better “Swift” way to solve these problems
but as a work around I created a MyRNEncryptor Objective-C class that extends
the RNEncryptor class. The MyRNEncryptor
header file should contain the following code:
#import
"RNEncryptor.h"
@interface
MyRNEncryptor : RNEncryptor
+
(NSData *)encryptData:(NSData *)data password:(NSString *)password
error:(NSError **)error;
+
(NSString *)stringFromData:(NSData *)data;
@end
While the RNEncryptor implementation file should contain
this code:
#import
"MyRNEncryptor.h"
@implementation
MyRNEncryptor
+
(NSData *)encryptData:(NSData *)data password:(NSString *)password
error:(NSError **)error {
return [self encryptData:data
withSettings:kRNCryptorAES256Settings password:password error:error];
}
+
(NSString *)stringFromData:(NSData *)data {
return [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
}
@end
The encryptData:password:error:
method simply calls the encryptData:withSettings:password:error:
method but adds the RNCryptorSettings. This
solves our first problem defined above.
The second function stringFromData:
uses the NSString initWithData:encoding:
constructor to convert the NSData object
to a NSString.
Now we need to create our Encryption API class with
Swift. Create a new Cocoa Touch Class
named MyCrypt and make sure that the language is set to Swift.
In the MyCrypt.swift class we will create two functions, one
to encrypt a NSString object and the other
to decrypt a NSData object. We will also define one constant that will be
our encryption key. In a production
application you would not want to define your encryption key as a constant like
this since it is very easy for someone to get it but this post is written mainly
to show how to integrate the RNCryptor with your Swift product so hardcoding
our key makes the example a lot simpler to read and understand. Add the following code the MyCrypt.swift
file:
let key
= "MySecretPassword"
func encryptString(estring: String) ->
NSData {
var edata =
MyRNEncryptor.encryptData(estring.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true), password:
key, error: nil)
return edata
}
func decryptData(edata: NSData) ->
String {
var pdata =
RNDecryptor.decryptData(edata, withPassword: key, error: nil)
var pstring: String =
MyRNEncryptor.stringFromData(pdata)
return pstring
}
The first line creates a constant key that contains our encryption key. We then define a function called encryptString that accepts one String parameter and returns an NSData object.
This function calls our encryptData:password:error:
method that we created in the MyRNEncryptor
class. This is where things get a little
weird, if you ask me. Normally if we
were to call this method from an Objective-C class we would use this syntax:
NSError
*error;
[MyRNEncryptor
encryptData:myData password:myPass error:&error];
In the code above we use the following syntax to call our encryptData:password:error: method (Note: I
simplified the above code, by taking out the NSString
to NSData conversion, to make it easier to
see how we are calling the Objective-C method):
MyRNEncryptor.encryptData(myData,
password: key, error: nil)
It is pretty easy to see the difference between the two
calls. The way that you call functions
in Swift is a lot closer to how other languages (like Java and C) however Apple
did keep how Objective-C defines the parameters that you are sending. Personally, I like how Apple did this but I
know that others will not. It is a
matter of personal preference.
Now that we have our encryptString
and decryptData API methods, lets open up
our ViewController.swift file and try to use them. Add the following code to the viewDidLoad function of the ViewController.swift
file.
var
crypt = MyCrypt()
var
edata: NSData = crypt.encryptString("Hello from swift my little swifty")
println(edata)
var
pdata: String = crypt.decryptData(edata)
println(pdata)
The first line creates an instance of the MyCrypt
class. We then encrypt the string “Hello
from swift my little swifty” and print the NSData
object to the screen. We then decrypt
the data and print the decrypted string.
This post documents my first attempt to use an Objective-C
library with Swift. If anyone else has
played with this and found better ways to do anything documented here, please
leave a comment.
Hello Jon
ReplyDeleteThanks for posting something valuable on here in regards to Swift and RNCryptor. I was banging my head against the wall. While I still haven't go it to work, it looks like there is hope.
Would you mind attaching a hello world demonstrating this? I tried following your instructions and I couldn't get it to work. I tried it in iOS and OS X. If possible could you provide an OS X sample? I really would appreciate it.
Nevermind, I'm a dumb ass. Tweaked it some for the OS X hello world project and I'm well now.
DeleteTHANK YOU VERY MUCH for your posting!
No problem. That seems to happen to me too, as soon as I post a question I seem to figure it out. Glad that the post helped you.
DeleteI want to download RNCryptor Library in Objective C.
ReplyDeleteAnybody can give me a link?
Thanks in advance!
Look at the github page here: https://github.com/RNCryptor/RNCryptor
ReplyDeleteThis Library is working fine for latest Swift version?
ReplyDelete