1

I'm stuck trying to decrypt some AES encrypted data sent by a server to my app.

In order to distill the problem down I've written a small java program that emulates what the server is doing. It encrypts some test data using AES then encodes it as Base64:

AesCipherService cipherService  = new AesCipherService();
cipherService.setKeySize(128);

String stringKey = "2EE1F10212ADD4BE";
byte[] keyAsBytes =  stringKey.getBytes();

String text = "text to encrypt";
byte[] encryptedBytes    = cipherService.encrypt(text.getBytes(), keyAsBytes).getBytes();
String base64String      = Base64.encodeToString(encryptedBytes);
System.out.println(base64String);

// Reverse the process to check can retrieve "text to encrypt":
byte[] bytesToDecode = Base64.decode(base64String);
byte[] decryptedBytes = cipherService.decrypt(bytesToDecode, keyAsBytes).getBytes();         
String decryptedString = new String(decryptedBytes);   
System.out.println(decryptedString);

When run this is the output:

R5UBpP30YjX9Ae2HoPb2Rrfi5rQJY2d0ac1+zaIX5A4=

text to encrypt

So I can successfully encrypt the data, print it out. Then if I unencrypt it the original text is displayed, so everything here is working fine.

Now here is my Obj-C code where I attempt to decrypt the data encrypted from the Java code. I've copied/pasted the encrypted data from the NetBeans IDE output window as the source data of the obj-c content to decrypt:

- (void) decryptData
{
    NSData* dataToDecrypt       = [[NSData alloc] initWithBase64EncodedString: @"R5UBpP30YjX9Ae2HoPb2Rrfi5rQJY2d0ac1+zaIX5A4="  options: 0];
    NSString* key               = @"2EE1F10212ADD4BE";

    char keyPtr[kCCKeySizeAES128];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [dataToDecrypt length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          kCCAlgorithmAES,
                                          kCCOptionPKCS7Padding,
                                          keyPtr,
                                          kCCBlockSizeAES128,
                                          keyPtr,
                                          [dataToDecrypt bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesDecrypted);
    if (cryptStatus == kCCSuccess) {
        NSLog(@"Success");
        NSData* unencryptedData = [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
        Byte *unencryptedAsBytes = (Byte*)malloc(unencryptedData.length);
        memcpy(unencryptedAsBytes, [unencryptedData  bytes], unencryptedData.length);
        NSString *decryptedString = [NSString stringWithUTF8String:[unencryptedData bytes]];
        NSLog(@"%@", decryptedString);
    }
}

When this is run the status is kCCSuccess and numBytesDecrypted is 32 (the same as dataLength) but the decrypted string is not "text to encrypt", decryptedString is nil and if I po unencryptedAsBytes in Xcode's console it displays this:

"\aY|\376\347cD*\320NC\x14\x91C\x88\301\341z\xaca\x11\371

Any idea what is the problem here?

2
  • 4. Where is AesCipherService documented? Are you using the key as the IV, that is not secure. 5. Perhaps theIV is the first 16-bytes in the encrypted data, that is not uncommon. Commented Jul 14, 2017 at 19:48
  • @zaph AesCipherService is part of the Apache crypto library shiro.apache.org/static/1.2.3/apidocs/org/apache/shiro/crypto/…. The java part of the code is written not by me but by a server developer, I am trying to write the Objective-C part to decrypt what they have encrypted. The code I've posted above is my go at re-creating what they have done in condensed format to try to re-create the problem in a more manageable way. They are using AesCipherService as above i.e they are not setting the IV etc. explicitly and thus the AesCipherService defaults are being used. Commented Jul 14, 2017 at 19:58

1 Answer 1

2

The Java encryption code generates a random IV and prefixes the encrypted with it. In order to decrypt the IV is split from the encrypted.

In hex:

key:       32454531463130323132414444344245  
iv:        479501A4FDF46235FD01ED87A0F6F646 (first 16 binary bytes of the full encryption)  
encrypted: B7E2E6B40963677469CD7ECDA217E40E (rest of binary bytes of the full encryption)  
decrypted: 7465787420746F20656E6372797074

Code:

NSData* fullEncrypted       = [[NSData alloc] initWithBase64EncodedString: @"R5UBpP30YjX9Ae2HoPb2Rrfi5rQJY2d0ac1+zaIX5A4="  options: 0];
NSData *ivData = [fullEncrypted subdataWithRange:NSMakeRange(0, kCCBlockSizeAES128)];
NSData *encryptedData = [fullEncrypted subdataWithRange:NSMakeRange(kCCBlockSizeAES128, fullEncrypted.length-kCCBlockSizeAES128)];
NSLog(@"ivData:          %@", ivData);
NSLog(@"encryptedData:   %@", encryptedData);

NSData *keyData = [@"2EE1F10212ADD4BE" dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"keyData:         %@", keyData);

NSMutableData *unencryptedData = [NSMutableData dataWithLength:encryptedData.length];
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                      kCCAlgorithmAES,
                                      kCCOptionPKCS7Padding,
                                      keyData.bytes, keyData.length,
                                      ivData.bytes,
                                      encryptedData.bytes, encryptedData.length,
                                      unencryptedData.mutableBytes, unencryptedData.length,
                                      &numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
    NSLog(@"Success");

    unencryptedData.length = numBytesDecrypted;
    NSLog(@"unencryptedData: %@", unencryptedData);

    NSString *decryptedString = [[NSString alloc] initWithData:unencryptedData encoding:NSUTF8StringEncoding];
    NSLog(@"decryptedString: %@", decryptedString);
}

Output:

ivData:          479501a4 fdf46235 fd01ed87 a0f6f646  
encryptedData:   b7e2e6b4 09636774 69cd7ecd a217e40e  
keyData:         32454531 46313032 31324144 44344245  
Success  
unencryptedData: 74657874 20746f20 656e6372 79707400  
decryptedString: text to encrypt  
Sign up to request clarification or add additional context in comments.

6 Comments

Totally awesome! Can't thank you enough, I've been stuck on this for literally days. How did you determine that the random IV was being prepended to the encrypted data?
Because that is common and theencrypted data was one block longer than it should be. Also the ObjC code defaults to CBC mode and an IV was needed. Of course I first made a guess about encodings that was wrong. <g>
BTW, here is a neat AES converter, note the trailing 01 in the output data, that is the padding.
Thanks for your help, I really do appreciate it.
Hi why did you add + kCCBlockSizeAES128 to the length of the unencryptedData when its allocated?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.