AES128 encryption on iOS without loading entire NSData - ios

Using samples from Apple Dev library (https://developer.apple.com/library/prerelease/ios/samplecode/CryptoExercise/Listings/Classes_SecKeyWrapper_m.html),
in particular this method
- (NSData *)doCipher:(NSData *)plainText key:(NSData *)symmetricKey context:(CCOperation)encryptOrDecrypt padding:(CCOptions *)pkcs7 { return nil; }
I can decrypt and encrypt files by reading them to NSData and then passing to this method.
however, this has an unfortunate consequence of me having to use a lot of RAM for this process.
Is there any way to decrypt the file right on disk without loading the file to NSData?

You can use the individual Common Crypto routines: CCCrytorCreate(), CCCryptorUpdate(), CCCryptorFinal(), and CCCryptorRelease() repeating CCCryptorUpdate() for each chunk.
See Mike Ash's Friday on A Tour of CommonCrypto.

Related

Data encryption with AES

I'm building an app that will communicate with a server (php), and this communication (probably will be with json) i want to encrypt. After a lot of searching and reading i found the AESCrypt-Objc project.
While testing the encryption (i'm using a web tool AES Encryption test) i found that in the encryption result i'm missing 16 byte of data.
Here's the example i'm using
In the AES project:
String to be encrypted: "The quick brown fox jumped over the lazy dog".
Password: "12345678901234561234567890123456"
The result:
<7eda336b 82f3e279 ae7638fe cccfffc6 5fbef8da 6df76d97 67d8cfa8 5bce2ae9>
My Code:
self.strnToBeEnc = #"The quick brown fox jumped over the lazy dog";
self.appKey = #"12345678901234561234567890123456";
NSData *data2 = [self.strnToBeEnc dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"%#", data2);
NSData *s2 = [data2 AES256EncryptedDataUsingKey:self.appKey error:nil];
NSLog(#"%#", s2);
WEB Tool:
Same string and password
The result:
<7eda336b 82f3e279 ae7638fe cccfffc6 5fbef8da 6df76d97 67d8cfa8 5bce2ae9 ca2ed34a 48f85af2 909654d5 b0de0fb7>
As you can see i'm missing some bytes...:)
I've tried adding to the buffer in the algorithm, but with no success.
Any advice?
Thanks
(if the question is not Detailed enough please let me know)
I know you were trying to avoid this but I think you might need to spend some time in the source code of AESCrypt-Objc as I suspect it is somehow not encrypting the last block.
Step into the code and see if you actually get to the CCCryptorFinal call, and note its results. This can be found in the AESCrypt-ObjC/NSData+CommonCrypto.m _runCryptor:result: . Another thing to look into is the default padding type they are using which appears to be kCCOptionPKCS7Padding this will also have an effect on your ending bytes.
Do your testing first with non-arbitrary length bytes that are multiples of the AES block size, then once you have validated that move on to the variable length ones you have here.

decoding a HUGE NSString, running out of memory

I'm looking for ideas on how to improve a process of decoding a 40+MB NSString with base64 encoding and saving it to a file while being able to fit the process into iPad 1's 256 MB of RAM
I get the NSString from NSXMLParser:
id pointerToString;
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:#"myElement"])
{
pointerToString = [string retain];
}
}
Then I use the pointerToString in a callback:
[handler performSelector: action withObject: pointerToString];
In the callback (id value is the pointerToString). I initialize NSData with the pointerToString while decoding it with base64 encoding.
^(id value)
{
if ( [[value class] isSubclassOfClass:[NSString class]] )
{
NSData *data = [NSData dataFromBase64String:value];
[data writeToFile:file.path atomically:YES];
}
}
the iPad 1 device runs out of memory and gets killed by the iOS when the memory allocation reaches around 130MB after or during the NSData call.
I have determined that in order to process the 40+MB NSString this way, I'd need about 180+MB of RAM (this is what the maximum memory allocation is on iPad 2 & 3, where the process works because of more RAM)
Any ideas/tips ?
Thank you
Edit:
When dealing with a file of this size, you probably do not want to load the entire multi-megabyte file in memory at one time, neither the huge input file nor the almost-as-huge output file. You should be parsing this in a streaming fashion, decoding the data in your foundCharacters as you go along, not holding any significant portions in memory.
The traditional techniques, though, may hold your entire XML file memory in three phases of the process:
As you download the XML file from the server;
As the XML parser parses that file; and
As you do the Base64-decode of the file.
The trick is to employ a streaming technique, that does these three processes at once, for small chunks of the single, large XML file. Bottom line, as you're downloading the entire 50mb file, grab a few kb, parse the XML, and if you're parsing the Base64-encoded field, perform the Base64-decode for that few kb, and the proceed to the next chunk of data.
For an example of this (at least the streaming XML downloading-and-parsing, not including the Base64-decoding), please see Apple's XMLPerformance sample project. You'll see that it will demonstrate two XML parsers, the NSXMLParser that we're all familiar with, as well as the less familiar LibXML parser. The issue with NSXMLParser is that, left to it's own devices, will load the entire XML file in memory before it starts parsing, even if you use initWithContentsOfURL.
In my previous answer, I mistakenly claimed that by using initWithContentsOfURL, the NSXMLParser would parse the URL's contents in nice little packets as they were being downloaded. The foundCharacters method of NSXMLParserDelegate protocol seems so analogous to the NSURLConnectionDelegate method, didReceiveData, that I was sure that NSXMLParser was going to handle the stream just like NSURLConnection does, namely returning information as the download was in progress. Sadly, it doesn't.
By using LibXML, though, like the Apple XMLPerformance sample project, you can actually use the NSURLConnection ability of streaming, and thus parse the XML on the fly.
I have created a little test project, but I might suggest that you go through Apple's XMLPerformance sample project in some detail. But in my experiment, a 56mb XML file consumed well over 100mb when parsing and converting via NSXMLParser but only consumed 2mb when using LibXML2.
In your comments, you describe the desire to download the Base64-encoded data to a file and then decode that. That approach seems a lot less efficient, but certainly could work. By the way, on that initial download, you have the same memory problem (that I solve above). I urge you to make sure that your initial download of the Base64-encoded data does not blithely load it into RAM like most routines do. You want to, assuming you're using NSURLConnection, write the data to the NSOutputStream as you receive the data in didReceiveData, not hold it in RAM.
See the didReceiveResponse in AdvancedGetController.m of Apple's AdvancedURLConnections example for an example of how to write a file as it's being received, rather than typical patterns of adding it to a NSMutableData (because most of these routines just assume you're dealing with a reasonably sized file). (Ignore all the stuff in that AdvancedURLConnections sample about authentication and the like, but focus on understanding how it's writing to the NSOutputStream as it goes.) This technique will address the first of the three problems listed at the top of this answer, but not the latter two. For that, you'll have to contemplate using LibXML2 as illustrated in Apple's XMLPerformance sample project, or other similar techniques.
The method
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
is probably not receiving all the data at once.
Doc is saying
"Sent by a parser object to provide its delegate with a string representing all or part of the characters of the current element."
So it is called multiple times.
It looks like you are trying to write the whole string at once (sorry if I am wrong).
So you could append the received data to the file by doing the following:
You can use a combination of
-writeData:
and
-seekToEndOfFile
methods from NSFileHandle class for writing NSData to the end of a file.
But be carefull with your base64 encoding on partial data receivment!

How to upload a LARGE file by using box-ios-sdk?

everybody. I'm using BoxUploadOperation interface of box-ios-sdk to upload file on iOS platform. I initialized BoxUploadOperation instance by using below class method.
+ (BoxUploadOperation *)operationForUser:(BoxUser*)user
targetFolderId:(NSString*)folderId
data:(NSData *)data
fileName:(NSString *)fileName
contentType:(NSString *)contentType
shouldShare:(BOOL)shouldShare
message:(NSString *)message
emails:(NSArray *)emails;
The third parameter of this class method need be an NSData object, that's good idea for small size file, it's no problem for loading whole file into memory (NSData), but that's not good idea for loading a large file into memory, iOS device memory is so limited.
So how can i upload a large file to box.net?
I have no idea, if someone has suggestion then i appreciates.

Partial file reading and writing with iOS SDK

I want to get the first 8 bytes or so of a file without reading the whole file. I'm using NSData to operate on the data and such, but I don't want to slow down my application with excessive file reads and writes because in some cases I'm having to read a 200 kilobyte file just to extract the first 2 bytes of data from the file. Is there any way to only read or write a part of the file without reading or overwriting the whole thing in Xcode with the iOS SDK?
The file system that I'm using is just the default one that's accessible through the NSFileManager class (I don't know of any other iOS file system).
You may take advantage of the higher level NSFileHandle class. The NSFileHandle class is an object-oriented wrapper for a file descriptor. You use file handle objects to access data associated with files, sockets, pipes, and devices. For files, you can read, write, and seek within the file. For sockets, pipes, and devices, you can use a file handle object to monitor the device and process data asynchronously.
- (NSData *)readDataOfLength:(NSUInteger)length
You can get more info in official documentation NSFileHandle Class Reference
Use the standard C file API (either FILE* or int file descriptors). The caveat is that you have to properly convert the string path to a correct char* file path. Also, don't forget to close the file when done. Consider a category on NSData, something kinda like this...
+ (id)dataWithContentsOfFile:(NSString *)filePath numBytes:(NSUInteger)numBytes
{
void *bytes = malloc(numBytes);
NSData *result = [NSData dataWithBytesNoCopy:bytes length:numBytes];
char const *path = [[NSFileManager defaultManager] fileSystemRepresentationWithPath:filePath];
int fd;
if ((fd = open(path, O_RDONLY)) < 0 || read(fd, bytes, numBytes) != numBytes) {
result = nil;
}
close(fd);
return result;
}

Encryption of contents in compiled iOS app ( IPA )

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];

Resources