AFNetworking with JSONkit for iOS 4.x problem

When I try to build an app for iOS 5 to be compatible with iOS 4.x, I keep getting this error: “No JSON parsing functionality available”. After that I found out you need to add one of the following libraries to your project: JSONKit, SBJSON, or YAJL, according to https://github.com/AFNetworking/AFNetworking.

AFNetworking uses NSJSONSerialization if it is available. If your app targets a platform where this class is not available you can include one of the following JSON libraries to your project for AFNetworking to automatically detect and use.

I used JSONKit, but when I drag the library(JSONKit.h and JSONKit.m) in, it should auto detect the library. After I drag the library into the project, it doesn’t work at all, I still getting error: “No JSON parsing functionality available”.

Went to search on internet and troubleshoot for few hours, only to found out the project I build are with ARC support, and JSONKit is not. I have to disable ARC support for JSONKit to make the project compile with no problem.

After the changes, the project is able to run now. I am a happy man again :)

disabled ARC support for JSONKit.m, add -fno-objc-arc.


AFNetwork Library – ARC issue

AFNetwork is a very useful network library that I am using it now. But if you turn on Automatic reference Counting, you will get a lot of compilation error.

To solve this problem, you need to add “-fno-objc-arc” to all the AFNetwork library during compilation time.

How to do it?

First Click on Project > Build  Phases > Expand Compile Sources, double click on each AF(xxx).m file, and add in ”-fno-objc-arc” to compile flag. This will tell the xcode not to do arc on these library.


RSA1024 encryption in IOS

Recently, we have a project that need to do RSA 1024 encryption in IOS. We use this helpful library SSCrypto framework to do RSA encryption.

With this library and with private key, you can encrypt the key by doing this. The private will then generate the public key to use to RSA encryption.

NSData *privateKeyData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"rsaprivatekey" ofType:@"pem"]];

// generate a public key from the private key data
NSData *publicKeyData = [SSCrypto generateRSAPublicKeyFromPrivateKey:privateKeyData];
SSCrypto *rsa = [[SSCrypto alloc] initWithPublicKey:publicKeyData privateKey:privateKeyData];

// set input that you want to do RSA encryption
[rsa setClearTextWithString:input];
NSData *dataEncrypt = [rsa encrypt];

//return final encrypted RSA 1024 password
NSString *rsaPassword = [NSString stringWithFormat:@"%@", [dataEncrypt hexval]];
Problem with our project is that we doesn't have a private Key! Based on the security diagram, private key should stored in server side and only give out public key.

So we need to decrypt the public key from server. The server is writing in JAVA, and they NSDATA as bytes Array. What we are going to do is to translate the byte Array in JAVA to IOS.

1) First, I combined all the bytes into a array format in char value

char rsaKeys[[publicKeys count]];
for(int i=0; i<[publicKeys count];i++){
     rsaKeys[i] = [(NSString *)[publicKeys objectAtIndex:i] intValue];
}

2) By doing this, you are combining the byte Array into the format like this.

char rsaKeys[] = {48, -127, -97, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -127, ....}

3) Use this method to encode it into based 64, Please becareful you must use encodeBase64, if not the whole thing will not work.

[[NSData dataWithBytes:rsaKeys length:[publicKeys count]] encodeBase64]

4) This will help you to generate something like this:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmYQ+xuFlZSvt/9qiTClnEBro/
2i1WsAhozr99wreVxzWy1HPlIrjUsOS8oNeF4Nw3CQ/TpPkEFzxGEwqa7LypDB5U
cD8OghTaXp/xQqcyg2LqmhQXha6LMiMWhPL/7vR56p7yoGWm4zaNJm9mNyIFVeLk
cel/VNU24B+C4m9oYwIDAQAB

5) the pem file usually start with header and footer, you also need to add this two line.

Header:       -----BEGIN PUBLIC KEY-----
Footer:         -----END PUBLIC KEY-----
After append this two file, you should get a completed public key PEM file.

6) with the public key PEM file, you can do RSA1024 with just the public key.

NSData *key1 = [pemkey dataUsingEncoding:NSASCIIStringEncoding];
SSCrypto *rsa = [[SSCrypto alloc] initWithPublicKey:key1];

7) and you should able to use rsa1024 to encrypt:

[rsa setClearTextWithString:input];
NSData *dataEncrypt = [rsa encrypt];

The full code is as below:

    char rsaKeys[[publicKeys count]];
    for(int i=0; i<[publicKeys count];i++){
            rsaKeys[i] = [(NSString *)[publicKeys objectAtIndex:i] intValue];
     }

     NSString *pemkey = [NSString stringWithFormat:@"%@\n%@%@\n",@"-----BEGIN PUBLIC KEY-----", [[NSData dataWithBytes:rsaKeys length:[publicKeys count]] encodeBase64], @"-----END PUBLIC KEY-----"];

     //Convert to NSData
     NSData *key1 = [pemkey dataUsingEncoding:NSASCIIStringEncoding];

     SSCrypto *rsa = [[SSCrypto alloc] initWithPublicKey:key1];
     [rsa setClearTextWithString:input];
     NSData *dataEncrypt = [rsa encrypt];

    //return final encrypted RSA 1024 password
    NSString *rsaPassword = [NSString stringWithFormat:@"%@", [dataEncrypt hexval]];

By using the example above, you should able to do RSA1024 with just public key in IOS.

 


Simple RSS reader with AFNetworking

I was tasked to build a simple RSS reader to read some RSS feed from online.
Recently I start to use AFNetworking, an amazing framework for all networking/web library.

I found this third-party library: BlockRSSParser which was based on the AFNetworking, the coding of RSSParser take less than 10 lines.

//MAKE Request to server and retrieve RSS feed 
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:k_URL]];
[RSSParser parseRSSFeedForRequest:request success:^(NSArray *feedItems) {
         //Do Something
} failure:^(NSError *error) {
         //SHOW Error 
}];

and this will parse RSS feed and return as feedItems As an NSArray.

The only problem I encountered is when I try to parse feed with content-type of “application/rss+xml”, I got an error instead of success. Prompt as unsupported content type. To fix this issue, I added “application/rss+xml” into acceptableContentTypes in AFXMLRequestOperation.m. The output look like this:

+ (NSSet *)acceptableContentTypes {
    return [NSSet setWithObjects:@"application/xml", @"text/xml", @"application/rss+xml", nil];
}