Question

I need to asynchronously decrypt a large file with RNCryptor on iOS (so as to show a progress bar). I have found no example anywhere, and thus have tried what I guessed was right, but... what I've come up with doesn't work : the decryptor’s handler is never called, and the thread crashed with EXC_BAD_ADDRESS after sending all data at the end of the function.

NSOutputStream *decryptedStream = [NSOutputStream outputStreamToFileAtPath:decryptedPath append:NO];
[decryptedStream open];

NSUInteger totalBytesToRead = [[[NSFileManager defaultManager] attributesOfItemAtPath:tempPath error:nil] fileSize];
__block NSUInteger totalBytesRead = 0;

LOG("I've got %d bytes to decrypt.", totalBytesToRead);

RNDecryptor *decryptor = [[RNDecryptor alloc] initWithPassword:SNCatalogPassword handler:^(RNCryptor *cryptor, NSData *data) {
    totalBytesRead += data.length;
    [decryptedStream write:data.bytes maxLength:data.length];

    LOG("Decrypted %d bytes : %d / %d bytes treated", data.length, totalBytesRead, totalBytesToRead);

    if (cryptor.isFinished)
    {
        //proceed
        LOG("Done with decrypting.");

        [decryptedStream close];

    }
}];

// Feed data to the decryptor
NSInputStream *cryptedStream = [NSInputStream inputStreamWithFileAtPath:tempPath];
[cryptedStream open];
while (cryptedStream.hasBytesAvailable)
{
    uint8_t buf[4096];
    NSUInteger bytesRead = [cryptedStream read:buf maxLength:4096];
    NSData *data = [NSData dataWithBytes:buf length:bytesRead];
    LOG("Sending %d bytes to decryptor...", bytesRead);

    dispatch_async(dispatch_get_main_queue(), ^{
        [decryptor addData:data];
    });
}

LOG("Sent everything.");
[decryptor finish];
[cryptedStream close];

(Obvsiouly, tempPath is the path to the crypted file ; decryptedPath is the path where decrypted data should be written).

Also I'm new to ARC so this may be a memory- or dispatch-related problem.

Thanks for any help.

Was it helpful?

Solution

I ran into the same issue today, and it seems to be happening due to the recent deprecation of dispatch_get_current_queue() in iOS6.

By changing [RNCryptor initWithHandler:] to create a new queue the decryption works correctly.

NSString *responseQueueName = [@"net.robnapier.response." stringByAppendingString:NSStringFromClass([self class])];
_responseQueue = dispatch_queue_create([responseQueueName UTF8String], NULL);

You can find the fix and an associated unit test (based on your code) on the async_decrypt branch of my fork on github.

Commit on csteynberg/RNCryptor

OTHER TIPS

your behaviour is due to asynchronous execution: you call [decryptor finish] before doing the calls to addData: To fix this you should replace

while (cryptedStream.hasBytesAvailable)
{
  //...

by

while (YES) {
  if (!cryptedStream.hasBytesAvailable) {
    dispatch_async(dispatch_get_main_queue(), ^{
      [decryptor finish];
    });
    break;
  }
  //...

(and of course remove the existing call to [decryptor finish]) this way finish is always called after all the data was sent.

Regards

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top