AeroGear, cryptography and iOS

In the last year I’ve started to explore the dirty field of cryptography for mobile devices, the plan was to provide a symmetric API on AeroGear with the bare minimum foundation like hash functions, public key algorithms, digital signatures, symmetric encryption and key derivation functions to benefit Android, iOS and JavaScript developers.

Unlike Android and JavaScript, the iOS environment is problematic when it comes to cryptography, popular APIs like: PollarSSL and OpenSSL had presented portability issues and license restrictions, leading us to stick with wrappers on top of Common Crypto

Key derivation

For offline authentication and encrypted, cache key derivation functions (KDF) play an important role in the project to prevent dictionary attacks when in conjunction with AES. KDF is tricky for newcomers to make the right choice and find the correct parameters like number of iterations or salt

NSString * const PASSWORD = @"My Bonnie lies over the ocean, my Bonnie lies over the sea";
NSData *salt = [AGRandomGenerator randomBytes];
NSData *rawPassword = [pbkdf2 deriveKey:PASSWORD salt:salt];

Is important to notice that in the example above the API sets the number of iterations to 20000 by default, in addition the API arguments were restricted to accept values higher than 10000 only. AGRandomGenerator generates a 16 bytes non-deterministic Salt taking into consideration NIST recommendations.

Symmetric encryption

From KDF functions was possible to generate the key material from the source password along with the IV for local encryption. The first idea was to provide AES and GCM mode to prevent message tampering, but it seems like Common Crypto API doesn’t support it, forcing us to move forward with CBC mode last year.

NSString* stringToEncrypt = @"My message";
NSData* encryptionIV = [AGRandomGenerator randomBytes];
NSData* dataToEncrypt = [stringToEncrypt dataUsingEncoding:NSUTF8StringEncoding];

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

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

Like the salt in the previous example, initialization vectors (IV) is created with 16 non-deterministic random bytes coming from AGRandomGenerator, otherwise you could experience the similar behavior present on ECB mode. In other words if the IV is predictable two identical inputs could produce exactly the same ciphertext, something really bad.

Public-key encryption

Symmetric key algorithms such as AES can be handy for local encryption, however, in scenarios like data synchronization where mobile applications want to send and receive sensitive data from the server, exchange private keys could compromise the whole system. Public key cryptography is more efficient in this situation, once it solves two problems: key distribution and nonrepudiation.

Asymmetric encryption

Elliptic Curves (ECC) were chosen over RSA, because it performs algebraic operations way faster than RSA, which means less memory consumption, less bandwidth and is more secure, NSA has a comparative analysis about it. Make use of Elliptic Curves from Common Crypto was bummer, the complicated design, the lack of proper documentation frustrated the idea.

Looking for alternatives libsodium presented as good alternative. This month I’ve started to replace Common Crypto and land Curve25519 on AeroGear with the help of my friend Christos.

NSData *alicePublicKey = [AGUtil hexStringToBytes:ALICE_PUBLIC_KEY];
NSData *alicePrivateKey = [AGUtil hexStringToBytes:ALICE_PRIVATE_KEY];
NSData *bobPrivateKey = [AGUtil hexStringToBytes:BOB_PRIVATE_KEY];
NSData *bobPublicKey = [AGUtil hexStringToBytes:BOB_PUBLIC_KEY];

NSData *nonce = [AGUtil hexStringToBytes:BOX_NONCE];
NSData *message = [AGUtil hexStringToBytes:BOX_MESSAGE];

AGCryptoBox *cryptoBox = [[AGCryptoBox alloc] initWithKey:alicePublicKey privateKey:bobPrivateKey];
NSData *cipherText = [cryptoBox encrypt:message nonce:nonce];

//Create a new box to test end to end asymmetric encryption
AGCryptoBox *pandora = [[AGCryptoBox alloc] initWithKey:bobPublicKey privateKey:alicePrivateKey];
NSData *plainText = [pandora decrypt:cipherText nonce:nonce];

The keys created are with 32-byte (256-bit) length for elliptic curves, which is equivalent to 3072-bit RSA according to NIST and the performance sufficient for mobile devices. AGCryptoBox provides authenticated encryption given key pair, it permit the encryption and decryption of messages.

Digital signatures

In addition, the support for Ed25519 was added to sign our HTTP requests against the server with the attempt to guarantee non-repudiation for mobile devices, the keys created are also 32-byte (256-bit) length.

NSData * const message = [@"My Bonnie lies over the ocean, my Bonnie lies over the sea"

NSData * signedMessage = [signingKey sign:message];
 [verifyKey verify:message signature:signedMessage];

The codebase on top of Common Crypto will me removed and libsodium will be fully integrated on AeroGear, that’s the right thing to do, hopefully our API won’t change too much. This is a work in progress and not something NSA proof, with military-grade encryption or whatever, but I’m very happy with the current state of the iOS library. Security is not a one-man land and that’s the reason why all projects on AeroGear are discussed in the open, if you have any question feel free to get in touch.

crypto iOS