views:

94

answers:

3

I try to decrypt data that was originally encrypted with Objective-C in Java.

There are other questions mentioning this but they are really cluttered and many of them aren't solved yet therefore I will post my own.

This is the code that encrypts the data:

  - (int) encryptWithKey: (NSString *) key
    {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char * keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
    bzero( keyPtr, sizeof(keyPtr) ); // fill with zeroes (for padding)

    // fetch key data
    [key getCString: keyPtr maxLength: sizeof(keyPtr) encoding: NSUTF8StringEncoding];

    // encrypts in-place, since this is a mutable data object
    size_t numBytesEncrypted = 0;
    CCCryptorStatus result = CCCrypt( kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 
                                     keyPtr, kCCKeySizeAES128,
                                     NULL /* initialization vector (optional) */, 
                                     [self mutableBytes], [self length], /* input */
                                     [self mutableBytes], [self length]+32, /* output */
                                     &numBytesEncrypted );
    return numBytesEncrypted;
}

I execute this function and write the resulting data to the disc with this code:

NSString* strTest = @"Hallo Welt!";
NSLog(@"strTest = %@", strTest);

NSMutableData *protectedData = [NSMutableData dataWithData:[strTest dataUsingEncoding:NSUTF8StringEncoding]];

int laenge = [protectedData encryptWithKey:@"keykeykeykeykeykeykeykey"];

NSData* dataOutput = [[NSData alloc] initWithBytes:[protectedData bytes] length:laenge];


[dataOutput writeToFile:@"/encryptedFileObjC" atomically:YES];

In Java I use this code to try to achieve the same behavior:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
String keyString = "keykeykeykeykeykeykeykey";
byte[] keyBytes = keyString.getBytes("UTF-8");

cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES"),
        new IvParameterSpec(new byte[16]));
byte[] resultBytes = cipher.doFinal("Hallo Welt!".getBytes("UTF8"));

FileOutputStream out =
        new FileOutputStream(new File("encryptedFileJava"));
out.write(resultBytes);
out.close();

If I now try decrypting the file that was encrypted via Objective-C I get a bad padding Exception. If I open the two files with the encrypted content they are different:

Hallo Welt! encrypted with Java: 96 C5 CB 51 39 B5 27 FB B3 93 BF 92 18 BB 16 9B
Hallo Welt! encrypted with ObjC: A3 61 32 8E A5 E6 66 E0 41 64 89 25 62 D3 21 16

Shouldn't the file content be the same? I think I don't got all the parameters for the algorithm the same in the two languages.

I need to alter the Java Code to get the same result as the Objective-C Code to be able to decrypt some data that was encrypted with Objective-C.

+1  A: 

You potentially have a bunch of issues.

When doing any encryption/decryption you need to ensure:

  • string encoding is identical (you're using UTF8 in both, thats good)
  • padding scheme is identical (you have pkcs5 on one and pkcs7 on the other)
  • initialisation vector is identical (you have null on one and empty bytes on the other)

..and of course the encryption scheme is identical. Confusingly your encryption seems to be using AES128, although the comments discuss using AES256. Not sure what the Java version is using

PaulG
My problem with the padding is that it seems there is no pkcs5padding available in java. Some other pages suggested using pkcs5 because it is nearly identical.
Janusz
"PKCS#5-padding" and "PKCS#7-padding" are synonyms.
Rasmus Faber
+1  A: 
  1. I would not assume that CCCrypt supported using the same array for input and output. Try using two different arrays.
  2. You have to resize the output array yourself (numBytesEncrypted should be equal to 16 after the call).
  3. As far as I can see, a null IV signals using ECB-encryption instead of CBC. As long as your input is smaller than 15 bytes, it should not make any difference, but it is still something you should fix.

EDIT: Another issue:

  1. You are using a 24-byte key. AES-128 needs a 128-bit = 16-byte key, AES-192 needs a 192-bit = 24-byte key and AES-256 needs a 256-bit = 32-byte key. You are explicitly indicating AES-128 to CCCrypt, which means it ignores the last 8 bytes of the key. You are just indicating AES to Java, which means it looks at the key-size to decide which AES variant to use. Since you are providing a 24-byte key, it uses AES-192. Fix it so both ends uses the same algorithm and you should be good.
Rasmus Faber
You are right I edited my question regarding the management of the NSDATA. Now I get the correct length but still a totally different encryption
Janusz
Also using ECB without an IV and PKCS5padding in Java gives the same result in the encryption, nothing near the ObjC result.
Janusz
Thank you works like a charm if I use only the first 16 bytes of the key.
Janusz
+1  A: 

This is probably not contributing to your problem, but it's wrong anyway:

   char * keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)

That defines an array of kCCKeySizeAES128 + 1 pointers, not kCCKeySizeAES128 + 1 bytes. As it happens, it is OK because the buffer you get is four or eight times larger than you need depending on whether you are compiling for 32 or 64 bit.

JeremyP
I can't do anything with the objc code the data is already encrypted
Janusz