Search code examples
objective-cencryptionyiiafnetworking-2rncryptor

AFNetworking + RNCryptor - decrypt data before JSON parse


How are you?

I'm trying to use RNCryptor to encrypt my transactions between the iOS devices and the webserver. For that I'm using RNCryptor on iOS and PHP, and AFNetworking to communicate from iOS to WebServer.

How do I decrypt data received from AFNetworking before it's been parsed to JSON response object?


To synthesize, I have:

  • Yii Framework, server side, PHP
  • AFNetworling, client side, Objective-C
  • RNCryptor, both sides

From iOS to PHP: I can decrypt data before using it.

From PHP to iOS: AFNetworking do not decrypt data before using it.


My PHP code is something like that:

RNCryptorHelper::init();
$encryptor = new \RNCryptor\Encryptor;

$data['Model1'] = Model1::model()->findAll();
$data['Model2'] = Model2::model()->findAll();

// EDITED TO REMOVE THIS HEADER
// header('Content-type: application/json');
echo $encryptor->encrypt(CJSON::encode($data), Yii::app()->params['cryptPassword']);
Yii::app()->end();

That outputs something like that:

AwFQ9+OfsHyXcSPynCrtveF7MQupQ+urd/VYeNMmt6OMxd6MhsDz4nxapvS1kVEHHbBZ4xLHqN7hTUDZos1LTWhB/CyeYoWpZSDhyFeHu9wNlHcRie6KTaHv/h14krvfb2/GHMt3GhIFqnyo7UKy/d06


My Objective-C code is something like that:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];

[manager GET:[NSString stringWithFormat:@"%@/Sync", URL_ROOT]
  parameters:nil
     success:^(AFHTTPRequestOperation *operation, id responseObject) {

         NSLog(@"%@", [RNDecryptor decryptData:responseObject withPassword:CRYPT_PASSWORD error:nil]);

     }
     failure:^(AFHTTPRequestOperation *operation, NSError *error) {
         NSLog(@"Error: %@", error);
     }];

That outputs the following error:

Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0x15681970 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}


Thanks for your help!!


EDIT 1

I changed the code a little bit and now I can get the result:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];

[manager GET:[NSString stringWithFormat:@"%@/Sync", URL_ROOT]
  parameters:nil
     success:^(AFHTTPRequestOperation *operation, id responseObject) {

         NSData *decryptedData = [RNDecryptor decryptData:[[NSData alloc] initWithBase64EncodedData:responseObject options:NSDataBase64DecodingIgnoreUnknownCharacters]
                                             withPassword:CRYPT_PASSWORD
                                                    error:nil];

         id json = [NSJSONSerialization JSONObjectWithData:decryptedData
                                                   options:kNilOptions
                                                     error:nil];

     }
     failure:^(AFHTTPRequestOperation *operation, NSError *error) {
         NSLog(@"Error: %@", error);
     }];

Anyone has a hint on how to create a Response Serializer that automates that decrypt?


Solution

  • You say in the response header that the returned data will be JSON ('Content-type: application/json') but it isn't, it's just a bunch of encrypted bytes that were once JSON and can be again after decryption.

    Either change the header (best) or use a http request that does not see the header and automatically attempt to de serialize the JSON. Look at AAFNetworking and see if there is such an option or another method that just returns the rad data.

    You need to get the raw data, decrypt it and then deserialize it.