Here’s the contents of the presentation i gave last night at cocoaheads sydney, for anyone who’s interested. Exclamation marks are slide separators, to suit my presentation app, Impromptu (

Also the source can be found here:

Skeleton Key

* Dropbox
* Cryptography
* Marketing



* Background sync
* Fully automatic
* Suppresses errors
* One folder, yaml files


Sync strategy

* Compare folders
* Both, same: nothing
* Both, different date: newer wins
* Different: depends on last sync state



If missing locally:

Present at last sync = it's been deleted locally, so delete remotely

Missing at last sync = it's been added remotely, so download.


Different 2

If missing remotely:

Present at last sync = it's been deleted remotely, so delete locally

Missing at last sync = it's been added locally, so upload.


Edge cases

Since the last sync data is only ever used to justify a
deletion, safe to clear it any time to avoid edge cases.

Eg clearing dropbox, linking, unlinking.



* Master password is validated using bCrypt
* All passwords are encrypted by AES
* The AES key is derived from the master pass using PBKDF2



Only used to verify the master pass, nothing else. One way
slow hash designed to not be GPU-able.

Uses JFBCrypt:

5 rounds takes ~0.1s on iPhone 4


Storing a password

    salt = [JFBCrypt generateSaltWithNumberOfRounds:5];
    hash = [JFBCrypt hashPassword:clearPassword withSalt:salt];

Store both the above strings



    test = [JFBCrypt hashPassword:clearPassword
    valid = [test isEqualToString:hash];



An industry-standard (eg OpenSSL) way to derive a key
from a passphrase/word.

Using Security framework, and CommonCrypto/CommonKeyDerivation.h

We're making a 32byte / 256bit key.



So that we know how many rounds to make it take ~0.1s:

    int rounds = CCCalibratePBKDF(kCCPBKDF2,
       clearPassword.length, keySalt.length,
       kCCPRFHmacAlgSHA256, 32, 100);



    - (NSData*)generateSalt256 {
        unsigned char salt[32];
        for (int i=0; i<32; i++) {
            salt[i] = (unsigned char)arc4random();
        return [NSData dataWithBytes:salt length:32];



    NSData* myPassData = [clearPassword

    unsigned char rawKey[32];
    CCKeyDerivationPBKDF(kCCPBKDF2, myPassData.bytes,
        myPassData.length, keySalt.bytes, keySalt.length,
        kCCPRFHmacAlgSHA256, rounds, rawKey, 32);
    return [NSMutableData dataWithBytes:rawKey length:32];



Also using Apple's Security framework's CommonCrypto

Using NSData+CommonCrypto helpers:



    - (NSString*)encrypt:(NSString*)clear {    
        NSData* clearData = [clear

        NSData* crypto = [clearData
            AES256EncryptedDataUsingKey:key error:nil];

        return [crypto base64EncodedString];



    - (NSString*)decrypt:(NSString*)crypto {
        NSData* cryptoData = [NSData

        NSData* clearData = [cryptoData

        return [[NSString alloc] initWithData:clearData



* Nobody responds to requests for reviews.
* Ads driving people to your promo-site costs more than income.
* Promo site with videos, screenshots, and features.
* Sells best when free!


So I got some advice..

Patio11 (HN)


Next time

* Find popular forum
* Working with them, make app
* Make placeholder page, collect emails, have shareables
* Determine if worth proceeding
* Attract via forums and ads
* Emails with updates
* Done
* Post launch, still interact, and email updates
* Emails link to forum for discussion


Please visit



Thanks for reading! And if you want to get in touch, I'd love to hear from you: chris.hulbert at gmail.

Chris Hulbert

(Comp Sci, Hons - UTS)

iOS Developer in Sydney.

I have worked at places such as Google, Cochlear, News Corp, Fox Sports, NineMSN, FetchTV, Woolworths, and Westpac, among others. If you're looking for a good iOS developer, drop me a line!

Get in touch:
[email protected]
my resume

 Subscribe via RSS