Mobile apps can do all sorts of really cool things. As an app is used, it often generates data. This data often includes a plethora of different types of information: personally identifiable, user preferences, game high scores, proprietary app data; with all the different types of apps, this list could be really long.
So what are app developers doing to protect this information? The choice is as much a legal issue as it is a technical issue. If the app in question is created by a US based company and exported, if the app consumes personally identifiable information, and probably many other cases, then it is a good idea to seek legal advice regarding how encryption can and/or should be used. I’m not a lawyer, so I cannot really comment on the legal issues in any detail, but I am an engineer and I do know a bit about using cryptography.
Apple Provides the CommonCrypto Libray
For a long time Apple has provided a low level cryptography library in their developer SDK as part of libSystem called CommonCrypto. Apple also has other options and some cool new cryptography stuff, but I have not come across a case yet where the CommonCrypto didn’t meet my needs. I believe this is primarily because the only way that I have used encryption thus far, other than SSL communication, is to protect proprietary app data. For cases of protecting personally identifiable information and other user generated data, Apple’s Security Framework is probably a better solution.
CommonCrypto provides a C based API for symmetric key encryption services such as AES and digital signature/hash services such as SHA-1. It also provides other less effective algorithms such as MD5 for hashes and DES and 3DES for symmetric key encryption. However, unless performance is an issue or a legal reason dictate you not to use AES and SHA-1, then you are likely better off using these. MD5 can cause problems because as a signature it can ‘collide’ by having to different sources of data have the same signature/hash. DES and 3DES are known to not be as secure as AES.
How To Encrypt Data and Validate Data Integrity
I am going to make this one easy by providing an Objective C static class that provides the ability to:
- AES encrypt and persist an NSDictionary to the documents directory,
- Create SHA-1 hashes of data in a file and provide the hash in an NString format,
- Create SHA-1 hashes of data in an NSData object and provide the hash in an NSData format,
- Load an NSDictionary object from an AES encrypted file in the documents directory or the resource bundle,
- Write raw data from an NSData object to a file in the documents directory,
- Load raw data from a file in the documents directory or resource bundle into an NSData object.
The static class that provides this is available to download here and is named EncryptedFileManager.zip.
The MD5 hash of the file EncryptedFileManager.zip is:
The SHA-1 hash of the file EncryptedFileManager.zip is:
The following is a excerpt from the interface file that is included in the EncryptedFileManager.zip file.
// Load unencrypted dictionaries +(NSDictionary*) loadDictionaryFromDocuments:(NSString*) plistFileName; +(NSDictionary*) loadDictionaryFromResourceBundle:(NSString*) plistFileName; // Load encrypted dictionaries +(NSMutableDictionary*) loadFromDocumentsDirectoryEncryptedDictionaryNamed:(NSString*)fileName; +(NSMutableDictionary*) loadFromResourceBundleEncryptedDictionaryNamed:(NSString*)fileName; // Write dictionary to encrypted file. +(BOOL) encryptAndWriteDictionary:(NSDictionary*)dictionary toDocumentsDirectoryWithFileName:(NSString*)fileName; // Delete a file from the documents directory. +(BOOL) deleteFileFromDocumentsDirectory:(NSString*)baseFileName; // File helpers +(BOOL) doesFileExistInDocuments:(NSString*)fileName; +(BOOL) doesFileExistInResourceBundle:(NSString*)fileName; // SHA-1 Hash +(NSData*)generateSHA1UsingProductKeyForData:(NSData*)sendData; +(NSString*)getSHA1HashForFileNamed:(NSString*)fileName; // Raw data i/o // Read data from either the documents directory or the resourcd bundle, // trying the documents directory first and if failure, then the resource bundle. +(NSData*) loadDataFromFile:(NSString*)fileName; // Write raw data to documents directory. +(BOOL) writeData:(NSData*)data toDocumentsDirectoryWithFileName:(NSString*)fileName; +(NSData*) loadDataFromDocumentsDirectoryWithFileName:(NSString*)fileName; +(NSData*) loadDataFromResourceBundleWithFileName:(NSString*)fileName;
Here are some examples of how this class could be used.
Persist a dictionary to an encrypted file in the Documents directory
[EncryptedFileManager encryptAndWriteDictionary:dict toDocumentsDirectoryWithFileName:@”fileName”];
Load a dictionary from an encrypted file from the Documents directory
NSDictionary* dict = [EncryptedFileManager loadFromDocumentsDirectoryEncryptedDictionaryNamed:@”fileName”];
Load a dictionary from an encrypted file in the resource bundle
NSDictionary* dict = [EncryptedFileManager loadFromResourceBundleEncryptedDictionaryNamed:@”fileName”];
Get an NSString representation of a SHA-1 hash of the data in a file
NSString* hashStr = [EncryptedFileManager getSHA1HashForFileNamed:@”infoplist”];
Get an NSData representation of a SHA-1 hash of an NSData object
NSData* hashData = [EncryptedFileManager generateSHA1UsingProductKeyForData:theDataToSign];
This class could easily be extended to include encrypting other object types such as strings or arrays.
One note on the resource bundle. You cannot write to it, but you can of course read from it. When you are creating your app, you can create code to write proprietary encrypted app data to the simulator’s Document directory and then add this to the resource bundle. This way your can AES encrypt sensitive resource data.
Don’t forget to create a unique encryption key and product ID in the class or update the selectors to accept being passed the encryption key and product id where necessary.
Let me know what you think of this solution for securing data.