Wednesday, November 27, 2013

AeroGear iOS lib - 1.3.0 Release

Today, we are happy to announce the immediate availability of 1.3.0 of the AeroGear iOS library. As with our JS and Android supported platforms, main focus of this release was enabling local data encryption. Further, welcome additions such as multipart upload support and new SQLite adapter for our DataManager interface made onto this release.
Let's dive in..

"Crypto for Humans"

Applying cryptographic techniques is hard. iOS platform makes it even harder, firstly by having the functionality dispersed across different frameworks and secondly (and most important), interacting with those frameworks is not the most easy task in the world.  This became clear evidence, as we started to build local data encryption support for our DataManager.  So, we decided to spin off a new iOS library, aerogear-crypto-ios. As stated in the project's web site, main aim is to provide useful and easy to use API interfaces for performing advanced cryptographic techniques in the iOS platform.

Let's see an example on how you can encrypt/decrypt a simple String object:

NSString *stringToEncrypt = @"I want to keep it secret";
// encode string into data
NSData *dataToEncrypt = [stringToEncrypt dataUsingEncoding:NSUTF8StringEncoding];

// set up crypto params..
// generate symmetric key
NSData *encryptionKey = [pbkdf2 deriveKey:@"password4me" salt:[AGRandomGenerator randomBytes]];
// ..and a random Initialisation Vector (IV)
NSData *IV = [AGRandomGenerator randomBytes;

// init the crypto engine
AGCryptoBox *cryptoBox = [[AGCryptoBox alloc] initWithKey:encryptionKey];

// encrypt
NSData *encryptedData = [cryptoBox encrypt:dataToEncrypt IV:IV];

// decrypt
NSData *decryptedData = [cryptoBox decrypt:encryptedData IV:IV];

You will appreciate the 'cleanness' of the code. In four lines (excluding the declarations), we derived a PBKDF2 based encryption key, initialised our encryption engine for Symmetric Encryption, and use it to encrypt/decrypt our data.

That is our major aim for our next items to come. Provide as much as possible cleaner interfaces to the underlying crypto functionality offered by the platform (but not limited to), so the developer can stay focus on what is important, an easy-to-easy API to add crypto in their own applications. If you are interested in Crypto and got frustrated by the number of hoops you needed to jump to implement it in your own iOS applications, that's the perfect time to jump in. We love to hear your ideas and suggestions to help shape the project and move forward.

For detailed information on the API, check our iOS cookbook guide. Further, since Christmas is coming, we built a demo application that utilises the crypto library to encrypt your present wishes! My colleague Corinne has already blogged about it, so head to her blog post for more information.


Encrypted Plist/Memory

Built on the security foundation provided by the crypto library, this release adds encrypted variants of the existing in-memory and plist based data stores (with an sqlite variant coming next release).  If you have been using the existing data stores to persist your data, you will be happy to know that you can easily switch to an encrypted variant by simple changing the type and some small (really!) amount of code to provide the necessary crypto params.

Let's see a example of using an encrypted plist:

// randomly generate salt
NSData *salt = [AGRandomGenerator randomBytes];

// set up crypto params configuration object
AGPassphraseCryptoConfig *config = [[AGPassphraseCryptoConfig alloc] init];
[config setSalt:salt];
[config setPassphrase:self.password.text];

// initialize the encryption service passing the config
id<AGEncryptionService> encService = [[AGKeyManager manager] keyService:config];

// access Store Manager
AGDataManager *manager = [AGDataManager manager];

// create store
store = [manager store:^(id<AGStoreConfig> config) {
    [config setName:@"CredentialsStorage"];
    [config setType:@"ENCRYPTED_PLIST"];
    [config setEncryptionService:encService];

// ok time to attempt reading..
NSArray *data = [store readAll])

if (data)
    // decryption succeeded!

Detailed description of the API can be found on our iOS cookbook guide. In a nutshell, we introduced a new configuration parameter in the store that accepts an encryption service. The store will then use the service to transparently encrypt/decrypt data as they pass in. Currently a default symmetric encryption service based on PBKDF2 is implemented, but we have more plans in the future so stay tuned!

To showcase the crypto store, we built a "Password Manager" that allows a user to store passwords encrypted. Head over to the demo page to try it out yourself or watch a small video demonstrating it in action!

SQLite Adapter

A new adapter has been added on our DataManager that utilises an SQLite database as its backend. Simply specify 'SQLite' when creating a store and you can start using it immediately:

// create the datamanager
AGDataManager* dm = [AGDataManager manager];
// add a new SQLite store object
id<AGStore> = [dm store:^(id<AGStoreConfig> config) {
   [config setName:@"tasks"];
   [config setType:@"SQLITE"];

The read, reset or remove API behave the same, as on our other store types, but this time objects are persisted in the sqlite database.

Don't forget to checkout our 'Recipe' application on our ios-cookbook, for example usage of the SQLite to store your favourite recipes!


Multipart upload

Support has been added on the Pipe interface to perform a multipart upload. No new API has been introduced, but instead we utilise the existing 'save' operation checking if the dictionary passed in contains instances of NSURL objects that point to local files. If that is the case, we kickstart the upload process.

Here is an example snippet, which uploads two images files on a server:

 // the files to be uploaded
 NSURL *file1 = [[NSBundle mainBundle] URLForResource:@"picture1" withExtension:@"jpg"];
 NSURL *file2 = [[NSBundle mainBundle] URLForResource:@"picture2" withExtension:@"jpg"];

 // construct the data to sent with the files added
 NSDictionary *dict = @{@"somekey": @"somevalue", @"jboss.jpg":file1, @"jboss2.jpg":file2 };

 // set an (optional) progress block
 [pipe setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
    NSLog(@"Sent bytesWritten=%d totalBytesWritten=%qi of totalBytesExpectedToWrite=%qi bytes", bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);

// upload data
[[pipe save:dict success:^(id responseObject) {
    NSLog(@"Successfully uploaded!");

} failure:^(NSError *error) {
    NSLog(@"An error has occured during upload! \n%@", error);

Note the ‘key’ in the dictionary is used as the ‘name’ field in the multipart request and is required. Further, you don’t need to specify the ‘Content-type’ or the ‘filename’ fields as they are automatically determined internally by the last path component of the NSURL object passed in. If the mime-type can’t be determined an ‘application-octet-stream’ would be sent instead.

To sum up, we think that you will enjoy this release. We have already laid our foundation for crypto, an area we are particularly interested in to moving forward as it adds significant value in the iOS community. So go ahead and give the libraries a spin. Download and explore our demos, play and have fun! We will be happy to hear your thoughts, suggestions and ways to improve it better. Join our mailing list, hangout on our #aerogear IRC channel and better, file us bugs!