As IPA structure is just a zipped file containing compiled codes & media contents like images & audio, how can I protect the contents from being extracted and stolen by others? Is there any encryption I can add into the IPA?
This answer mentions that the application is already encrypted by the time it gets onto your users' devices: Does Apple modify iOS application executables on apps submitted to the App Store?
Sorry, that's only the application binary. The other media are not encrypted, and no, there's no way to encrypt the .ipa. You could try encrypting your images and other media on your system, providing a bunch of application code to decrypt those resources when the app runs, and then your decryption code will become a part of the encrypted application binary. You can't submit an encrypted IPA though, it needs to be the file directly output from Xcode.
In response to your comment, the one I've used in the past is CommonCrypto. You can use this crypto library as a starting point.
Simple usage example of the above:
NSError *error;
NSMutableData *encryptedData = [NSMutableData dataWithContentsOfFile:pathToEncryptedFile];
NSData *decryptedData = [RNDecryptor decryptData:encryptedData
withPassword:#"SuperSecretDecryptionKey"
error:&error];
UIImage *decryptedImage = [UIImage imageWithData:decryptedData];
IMPORTANT NOTE HERE: IF someone was to run the strings utility on your .app on a jailbroken iphone, or even on an iPhone they have filesystem access to via USB, they will get a list of all strings declared in your app. This includes "SuperSecretDecryptionKey". So you may want to use an integer, floating-point or other constant to do on-the-fly generation of a string decryption key, or make sure that the string you use to decrypt things is exactly the same as a normal system string so no-one suspects it as the true key. Security through obscurity, in this case, is advantageous.
To encrypt/decrypt *.strings files, you should encrypt the key and value strings in some manner (maybe one which gives you hexadecimal back, or any alphanumeric characters), and when you want to access a given value, say LicenceNumber, do this:
NSError *error;
NSData *unencryptedKey = [#"LicenceNumber"
dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedKey = [RNEncryptor encryptData:unencryptedKey
withSettings:kRNCryptorAES256Settings
password:#"SuperSecretEncryptionKey"
error:&error]
NSData *encryptedValue = [[NSBundle mainBundle]
localizedStringForKey:[NSString
stringWithUTF8String:[encryptedKey bytes]]
value:#"No licence"
table:#"EncryptedStringsFile"];
NSData *decryptedValue = [RNDecryptor decryptData:encryptedValue
withPassword:#"SuperSecretDecryptionKey"
error:&error];
Related
I am building a mobile iOS app for a web backend. I retrieve the JSON response using the following code:
NSError *error;
NSString *url_string = [NSString stringWithFormat: #"https://myURL"];
NSData *data = [NSData dataWithContentsOfURL: [NSURL URLWithString:url_string]];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
What would be the best/simplest way to store this data locally so that I can use a local database when internet connectivity is not available? The intention is to check web connectivity at launch of the app. If connection is available, get JSON response, parse and update local copy, if connection is not available parse the data from local storage.
Thanks in advance.
If you wish to cache the JSON data so you can still use it offline, I would write the JSON dictionary (or the data) to a file in your app's sandbox. A subfolder of the "Application Support" folder would be a good place. You don't want to use the Caches folder in this case because the files could be purged by iOS when you need them offline.
The trick is to map a given URL to a filename. You need this mapping to both save a file for a given URL and to later load the file if offline. You should be able convert a URL to a useful filename simply by converting all / characters to something else such as an underscore.
You probably don't want these files backed up when a user backups their iOS device so be sure you mark the files with the "do not backup" attribute. There are many existing question covering that topic.
The best way is CoreData and
the simplest way is NSUserDefaults
NSUserDefaults Class Reference
[[NSUserDefaults standardUserDefaults] setObject: jsonDict forKey:#"dictionaryKey"];
//...
NSDictionary * myDictionary = [[NSUserDefaults standardUserDefaults] dictionaryForKey:#"dictionaryKey"];
My app creates some back-up files as Packages (in fact as directories with an extension, and an Exported UTI that conforms to com.apple.package).
I would like to be able to read them as NSData, that I can attach to an email in a MFMailComposeViewController. Actually, it doesn't work because dataWithContentsOfURL: returns nil when I try to read the package (I think because it's a directory, not a regular file).
I know my package files are fine because I can access them on my Mac when I download the "app container" from my iPhone.
I generate them using NSFileWrappers, and calling the writeToURL:options:originalContentsURL:error: method.
I don't want to use serializedRepresentation because it generates NSData that can be read only by NSFileWrapper (and I would like to be able to open them on my Mac, by clicking on "Show Packages Contents").
Here is the part of code that doesn't work:
NSURL *finalBackupURL = [outputDirectoryURL URLByAppendingPathExtension:#"ext"];
if (![packageWrapper writeToURL:finalBackupURL options:0 originalContentsURL:nil error:error])
#throw [NSException exceptionWithError:*error];
NSData *data = [NSData dataWithContentsOfURL:finalBackupURL];
(data = nil whereas the file has well been created)
Thank you for your help
When I use the terminal version of RNCryptor to encrypt a file and then try to decrypt this file in Objective-C using RNDecryptor, I always get the error "unknown header".
I understand this is because my first byte is 'A' instead of '2' or the kRNCryptorFileVersion, but I don't know why this is.
If I decrypt the file using the terminal version, it works like expected.
I encrypt the file using:
./rncrypt -p someKey "$(cat test.txt)" > encr.txt
This gives output like:
AwHcVbXbpyI7S/RBXlVhRP1coKqFmSEFDtgFaj/JGJ181qEb024uVdt7lHWqUvUvm1rwdM4yQQ+gsMepHhR58v054qvhO4yu98N2bHGuV28aUA==
To decrypt it in iOS I'm doing the following:
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"encr" ofType:#"txt"];
NSData *data = [NSData dataWithContentsOfFile:resourcePath];
NSError *error;
NSData *uncrypted = [RNDecryptor decryptData:data withPassword:#"someKey" error:&error];
What am I doing wrong?
The rncrypt test program outputs base64 encoded data. You need to decode it before passing it to the decryptor. See [NSData initWithBase64EncodedData:options:].
Note that if kRNCryptorFileVersion is 2, you're using a slightly broken version of RNCryptor that has poor security for multibyte passwords (Chinese for example). I highly recommend using a later version with the v3 format.
I need to store third-party username/password in my iOS application, what is the best and most secure way to do this? When my app first runs, it will need to talk to Google's Picasa to download private pictures to use for the app. To talk to Picasa, I have to provide my username/password and storing in the code is not secure at all.
I've search the web, I see Keychain came up a lot, but how exactly do I pre-load my password into keychain?
Is there a configuration file in xCode somewhere to store passwords needed for web-services?
Thanks
Think that you need to store the password in encrypted form. Pick some encrypting algorithm, generate the encrypted details. And in code have some method to decrypt it when needed.
You just don't want someone who would read your code as plain text to see the password.
Think that something as simple as splitting the password into separate strings and later joining them could be enough.
Here for example You have encrypted in code "My1Password":
#define R1 #"My"
#define R2 #"Password"
+ (NSString *)generatePass{ return [NSString stringWithFormat:#"%#%#%#, R1, #(1), R2]; }
This is a response to krzysztof above:
I'm in a catch-22 situation here as I can't seem to grasp the concept of feeding the password as parameter to another function. Aside from avoid others reading the source code in plain text, can't hackers obtain the binary file and reverse engineer to read the password in the source code (R1 & R2 in this case)???
Back to encryption, lets take the following line of code which Encrypt/Decrypt data:
NSData *encryptedImage = [RNEncryptor encryptData:imageData withSettings:kRNCryptorAES256Settings password:#"A_SECRET_PASSWORD" error:nil];
NSData *decryptedData = [RNDecryptor decryptData:data withSettings:kRNCryptorAES256Settings password:#"A_SECRET_PASSWORD" error:nil];
This is where I'm stuck... where do I store A_SECRET_PASSWORD?
What is the best practice to store sensitive(not secure) data on iOS devices?
Where should I store information that user bought something in app? For example where should I store BOOL showAds variable if user bought "Remove Ads"?
I do understand that everything breakable, especially on jailbroken devices, I just asking what is the best practice.
My variants:
.plist in App Documents -- Editable using iFunBox, for example
NSUserDefaults -- Same here, I guess
Keychain -- best variant in my opinion so far
You can store you data in NSUserDefaults using base 64 encoding data to keep safe it.
The code is very simple:
NSUserDefaults *persistValues;
persistValues = [NSUserDefaults standardUserDefaults];
To set data (encoding it using base 64):
// Create NSData object
NSData *nsdata = [#"iOS Developer Tips encoded in Base64" dataUsingEncoding:NSUTF8StringEncoding];
// Get NSString from NSData object in Base64
NSString *base64Encoded = [nsdata base64EncodedStringWithOptions:0];
[persistValues setObject:base64Encoded forKey:#"some_key"];
To get data:
base64Encoded = [persistValues stringForKey:#"some_key"];
NSData *nsdataFromBase64String = [[NSData alloc]
initWithBase64EncodedString:base64Encoded options:0];
// Decoded NSString from the NSData
NSString *base64Decoded = [[NSString alloc]
initWithData:nsdataFromBase64String encoding:NSUTF8StringEncoding];
And if you data is bigger I suggest you uses web services and store it in a web server
Keychain is best option to store sensitive data.
Other than sensitive data below are 2 options :
Small data can be stored in NSUserDefault as its best way as physical file will not be available for changing data.
Bigger data can be stored in database with encryption