7

Here are my method's to use RNCryptor to encrypt/decrypt a JSON string that I am sending to the web service. I am using a static IV variable which may be bad practice but please don't focus on that. Here is how I'm doing it:

Note: I'm using Matt Gallagher's NSData+Base64 category found here (at bottom of page)

-(NSString*)encryptString:(NSString*)plaintext withKey:(NSString*)key error:(NSError**)error{
    NSData *data = [plaintext dataUsingEncoding:NSUTF8StringEncoding];
    NSData *encryptionKey = [NSData dataFromBase64String:key];
    NSData *IV = [NSData dataFromBase64String:ENCRYPTION_IV];

    RNCryptorEngine *engine = [[RNCryptorEngine alloc] initWithOperation:kCCEncrypt settings:kRNCryptorAES256Settings key:encryptionKey IV:IV error:error];
    [engine addData:data error:error];
    NSData *encryptedData = [engine finishWithError:error];

    NSString *based64Encrypted = [encryptedData base64EncodedString];
    NSLog(@"Encrytped: %@", based64Encrypted);
    return based64Encrypted;
}
-(NSString*) decryptString:(NSString*)cipherText withKey:(NSString*)key error:(NSError**)error;{
    NSData *data = [NSData dataFromBase64String:cipherText];
    NSData *encryptionKey = [NSData dataFromBase64String:key];
    NSData *IV = [NSData dataFromBase64String:ENCRYPTION_IV];

    RNCryptorEngine *engine = [[RNCryptorEngine alloc] initWithOperation:kCCDecrypt settings:kRNCryptorAES256Settings key:encryptionKey IV:IV error:error];
    [engine addData:data error:error];
    NSData *decryptedData = [engine finishWithError:error];
    NSString *decryptedString = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];
    NSLog(@"Decrypted: %@", decryptedString);
    return decryptedString;
}

When I use a string like hello world it works fine. When I use a string like {"username":"developer","password":"abcdefG*12"} I imagine it hase something to do with the encoding but I really know what to use.

when I encrypt that string I get a base64 string and when I try to decrypt that I get an empty string.

UPDATE

It looks like it's failing because of the : in the json string. What's weirder is it only fails with the string is in json format, I thought it was the : cause I tried that first but upon further investigation if I broke any of the JSON requirements ,'s {'s }'s it stopped working. It works with the RNEncryptor however so I'm not sure what I'm doing wrong. Either way, I think we may redesign the current flow

UPDATE 2

Here is where I am calling these methods:

NSDictionary *credentials = @{@"username":@"developer",@"password":@"abcdefG*12"};
NSString *jsonString = [ credentials JSONStringWithOptions:JKSerializeOptionNone error:&error];
NSLog(@"json string: %@", jsonString); //OUTPUTS: {"username":"developer","password":"abcdefG*12"}
CCGEncryption *encryptionObject = [[CCGEncryption alloc] init]; //THIS IS THE OBJECT WHERE THE encrypt/decrypt methods are

NSString *encrypted = [encryptionObject encryptString:jsonString withKey:ENCRYPTION_KEY error:&error];
if(error){
    NSLog(@"Error:%@", error); //NO ERROR
}
NSString *decrypted = [encryptionObject decryptString:encrypted withKey:ENCRYPTION_KEY error:&error];
if(error){
    NSLog(@"Error:%@", error);  //NO ERROR
}
NSLog(@"decrypted: %@", decrypted); //OUTPUT: decrypted: 
jbtule
  • 31,383
  • 12
  • 95
  • 128
mkral
  • 4,065
  • 4
  • 28
  • 53
  • When you say " I encode that string I get a base64 string and when I try to decode that I get a null value." are you meaning encrypt and decrypt? from your posted code, i see your plaintext uses UTF8 encoding and your ciphertext uses Base64 neither of those should have issues with colons. If your decryption function is returning `null`, then there is probably an `error` value being returned. What is it's value? – jbtule Jan 10 '13 at 17:13
  • @jbtule I've added the code where I use those methods. I am using JSONKit to serialize the NSDictionary to NSString – mkral Jan 10 '13 at 17:24
  • @jbtule and yes, I meant encrypt/decrypt I've edited the post – mkral Jan 10 '13 at 17:33
  • @jbtule also to clarify, I meant to say decrypt returns an empty string, not a null value. I've check all methods that can return errors and no errors received. – mkral Jan 10 '13 at 17:43
  • As far as I can tell, it looks like you are using the engine correctly, however it doesn't look the the API is intending for you to use the engine directly, so maybe it's a bug, maybe missing something, the api is clearly geared toward using `RNEncryptor` & `RNDecryptor` instead of the engine. – jbtule Jan 10 '13 at 17:49
  • Yea, unfortunately you can't set the IV for the RNEncryptor explicitly, it's using a random IV. Which makes the .NET webservice have to enable breaking apart the data as described by the Data Format for RNEncryptor. – mkral Jan 10 '13 at 18:10

1 Answers1

3

You're not collecting the data returned by addData:. The engine encrypts/decrypts as you go so that you don't have to hold the entire plaintext and ciphertext in memory. It doesn't accumulate the data unless it has to (for padding reasons). I suspect that the tests that are working are of different lengths than the ones that aren't.

You are correct that using a fixed IV is bad practice. If you use the same IV and key in multiple messages, then it is possible for attackers to recover parts of your messages by comparing the ciphertexts. If you are using AES-CBC without a random IV and an HMAC, then your AES is insecure in several ways. That is the problem RNCryptor was built to address and why the data format looks the way it does.

@jbtule is correct that I didn't particularly mean for people to use the engine directly and haven't heavily documented it, but there's no problem using it, and I can document it better to support that. That said, the engine itself is insanely simple; I just created it as a way to share code between the encryptor and decryptor. There's not much reason to use RNCryptor if you're going to bypass most of the security it provides. For the above code, it'd be a lot simpler to just call the one-shot CCCrypt().

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Thanks Rob for explaining it very clearly. I will talk to our backend developer about implementing with random IV. One question I had is the Data-Format you use some sort of standard? Eventually we'll move to android and want to do it right now. – mkral Jan 11 '13 at 15:42
  • There's no simple standard format that I know of that can include an IV, salts, and an HMAC, so I had to roll a new one. The aescrypt format is close, but you can't provide random salts (and they don't use a standard PBKDF). The only standard format that I've found that can actually encode AES correctly is CMS, but it's *much* more complicated and designed mostly for certificate-signed messages, not symmetric encryption. I'm actively looking for a format to support, but it has to be secure. The best-known "standard" is OpenSSL, but its AES format is broken in several ways. – Rob Napier Jan 11 '13 at 17:12