Securely storing OAuth keys in iOS application

Post date: Jun 28, 2013 6:33:31 AM

Recently I was involved in iOS native application which is accessing Restful OAuth web service.  Client provided OAuth API key and Secrete Key to access their web service.

So we just put on "Plist" and we start using this for web service call. Once we done a application we start digging the security flaws in our application. We realise that "PLIST" values will be available to everyone once you extract the .IPA file.

So we decide to AES encryption to Encrypt the API and Secrete keys then stored it plist.

Encryption

Again we found below drawback:

At this point I don't have any idea about to hiding this key. So I decided to workaround.

Encrypt Plist:

I decide to encrypt my plist using AES algorithm. Here my AES key is "GreateIndiaClub@123"

Plist

The code I used for Encryption is:

-(NSString*)getEncryptedPlistInfo:(NSString*)resourceName{

//get the plist path

NSString * strPath= [[NSBundle mainBundle] pathForResource:resourceName ofType:@"plist"];

//convert it into dictionary

NSDictionary* dictionary= [[NSDictionary alloc]initWithContentsOfFile:strPath];

//conver into NSData

NSData *xmlData = [NSPropertyListSerialization dataFromPropertyList:dictionary

format:NSPropertyListXMLFormat_v1_0 errorDescription:nil];

//Apply AES encrytpion

NSData* encryptData = [ xmlData EncryptAES:@"GreateIndiaClub@123"];

//Encode with Base 64

NSString* strBase64= [QSStrings encodeBase64WithData:encryptData];

//Return cipher text

return strBase64;

}

Don't forget to Delete this function from your project once you done a encryption.

After encryption I got the cipher text mentioned below:

BxcLIWJ720ZztUO1uRwIOEATvjbRyeh8ny6G0Nq2sS/uaB6QD584ASjkpddHnlc+LsPDXeBJPau16fh1

GVAsB09J8Cl6KrnzakHssHyYWsVfV4lYPMSUhzGnd0szPu+JyNud3H91yr+x65fSTywc45eDhS7r

SG2wd8byPvYdbHh/mWW4k2Az+m6IZw7WDq9n46roDp53FPn2CkcV5XXbh3BJEtQVBzVm9/

CRYmdFdNS4i9UKX1ND0WWpeBRuHP3qtJQUBoCuX7c8dN0smhx51wLcHxgY4+cPE+sjWGb

6slNWi5HejF7PC1fjawJyJmfE9mlQoyF3hxATJGyxQJinNCZ6FfSZ0cDcjv3lQQZZZRN6e0UTQ

TSipS729a4trD2hVgmJk7NBNAup26FkFGlGKA==

Modify the cipher text:

Now we need append AES key with this cipher text, so that it will became as invalid cipher text. So no can able to use this. The new cipher text will be

GreateIndiaClub@123BxcLIWJ720ZztUO1uRwIOEATvjbRyeh8ny6G0Nq2sS/uaB6QD5

84ASjkpddHnlc+L

sPDXeBJPau16fh1GVAsB09J8Cl6KrnzakHssHyYWsVfV4lYPMSUhzGnd

0szPu+JyNud3H91yr+x65fSTywc45eDhS7rSG2wd8byPvYdbHh/mWW4k2Az

+m6IZw7WDq9n46roDp53FPn2CkcV5XXbh3BJEtQVBzVm9/CRYm

dFdNS4i9UKX1ND0WWpeBRuHP3qtJQUBoCuX7c8dN0smhx51wLcHxgY4+cPE+sj

WGb6slNWi5H ejF7PC1fjawJyJmfE9mlQoyF3hxATJGyxQJinNCZ6FfSZ0cDcjv3lQQZ

ZZRN6e0UTQTSipS729a4trD2hV

gmJk7NBNAup26FkFGlG KA==

Makes key more complex by applying your own algorithm:

To make your secrete key more complex append some text with your key with some logic

Original Key : GreateIndiaClub@123

Modified Key : GOr3ePa=tAe8IRnDd9i/aUCFlau3bi@h1k2l3

So here the logic is EVEN position contains the original key, just have to omit the ODD position of the characters

Now add this key in your plist cipher text:

GOr3ePa=tAe8IRnDd9i/aUCFlau3bi@h1k2l3BxcLIWJ720ZztUO1uRwIOEATv

jbRyeh8ny6G0Nq2sS/uaB6QD584ASjkpddHnlc+LsPDXeBJPau16fh

1GVAsB09J8Cl6KrnzakHss HyYWsVfV4lYPMSUhzGnd0szPu+JyNud3H91yr+x65fST

ywc45eDhS7rSG2wd8byPvYdbHh/mWW4k2Az+m6IZw7WDq9n46roDp53FP n2Ckc

V5XXbh3BJEtQVBzVm9/CRYmdFdNS4i9

UKX1ND0WWpeBRuHP3qtJQUBoCuX7c8dN0s

mhx51wLcHxgY4+cPE+sjWGb6slNWi5HejF7PC1fjawJyJmfE9mlQoyF3hx

ATJGyxQJinNCZ6FfSZ0cDcjv3lQQZZZRN6e0UTQTSipS729a

4trD2hVgmJk7NBNAup26FkFGlG KA==

Now add this key in your plist and delete the earlier plist:

New PLIST

All these should be done manually before the application deployment. You should Delete getEncryptedPlistInfo once encrypt the plist.

Now new plist has encrypted plist with modified AES Key.

Decrypt PLIST:

1. Get value from PLIST

2. Separate the Modified AES Key and Encrypted key. You should know the modified AES key length, In our case it was 37 character length

3. Parse the AES Key with your algorithm, here we had original key at EVEN postion

4. Apply AES decryption using parsed AES key, you will get the Decrypted Plist dictionary as output.

Function used to Decrypt the PLIST:

-(NSDictionary*)getConfigurationPlist{

//get the plist path

NSString * strPath= [[NSBundle mainBundle] pathForResource:@"Test" ofType:@"plist"];

//convert it into dictionary

NSDictionary* dictStoreScanner= [[NSDictionary alloc]initWithContentsOfFile:strPath];

//Read the new Plist, which has encrypted value with Modified AES key

NSString* strPlist =[dictStoreScanner valueForKey:@"Info"];

//Get Modified AES Key

if ([strPlist length]>37) {

NSString* strKey= [strPlist substringToIndex:37];

NSMutableString* strAES=[NSMutableString string];

//Parse the Modifed values and get the originial key, You should apply your own algorithm here

for (int i=0; i<strKey.length; i++) {

//Here I'm looking for EVEN position of the characters only

if (i%2==0) {

[strAES appendFormat:@"%c", [strKey characterAtIndex:i]];

}

}

//get the encrypted text for plist

NSString* strEncryptedPlist = [strPlist substringWithRange:NSMakeRange(37, 

[strPlist length]-37)];

//decrypt the text

NSData* plistData=[QSStrings decodeBase64WithString:strEncryptedPlist];

plistData = [ plistData DecryptAES:strAES andForData: nil];

NSPropertyListFormat plistFormat;

//parse the data and get the dictionary (NSData - NSDictionary)

NSDictionary* dictValue =[NSPropertyListSerialization 

propertyListWithData:plistData options:NSPropertyListImmutable 

format:&plistFormat error:nil];

return dictValue;

 }

return nil;

}

By calling above function you will get APIkey and Secretekey from the dictionary;

Printing description of dictValue:

{

    APIKey = "ApiKey@123";

    SecreteKey = "SecreteKey@123";

}

Advantages:

Hope you enjoy this concept. Please let me know if you have any queries.

New Plist