16
votes

I have been tearing my hair out all day trying to solve this...

I have an objective-c client running on the iPhone, connecting to a Java server. The iPhone is encrypting data using AES but I cannot decrypt it on the server. I am using a known passphrase and message (single string) and am generating the byte array on the iPhone, generating a comparison byte array on the Java server using the same key and message but the byte arrays are completely different (and hence can't be decoded on the Java side).

The client is using the CommonCrypto library with the following settings...

Data is an NSData holding the word "message" using dataUsingEncoding:NSASCIIStringEncoding Key is an NSData holding the phrase "1234567891123456" again using the encoding as above. Algorithm is kCCAlgorithmAES128 Options is kCCOptionsPKCS7Padding (which I believe equates to ECB on the server?!)

The server is using the following code...

byte[] key = "1234567891123456".getBytes();
Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");

SecretKeySpec k =  new SecretKeySpec(key, "AES");
c.init(Cipher.ENCRYPT_MODE, k);
byte[] encryptedData = c.doFinal("message".getBytes());

BUT the data in encryptedData does not match that which is being generated in the objective-c code, the byte arrays are completely different.

Can anyone see anything obvious I am doing wrong? I think the settings are all the same... :(

  • UPDATE - As requested....

Ok so here goes....

iPhone client is encrypting the following string "message" It uses the key "1234567891123456" It uses an initialisation vector of "1010101010101010" It is using AES128, with CBC mode (as far as I can tell) and options of kCCOptionsPKCS7Padding.

The result of the encryption (with base64 encoding) is UHIYllDFAXl81ZM7OZPAuA==

The server is encrypting the same string, with the same key and initialisation vector. It is using the following Cipher.getInstance("AES/CBC/PKCS5Padding");

The result of the encryption (with base64 encoding) is ALBnFIHysLbvAxjvtNo9vQ==

Thanks.

  • UPDATE 2 - As requested...

Here is the iPhone code....

NSData *toencrypt = [@"message" dataUsingEncoding:NSASCIIStringEncoding];

NSData *pass = [@"1234567891123456" dataUsingEncoding:NSASCIIStringEncoding];

NSData *iv = [@"1010101010101010" dataUsingEncoding:NSASCIIStringEncoding];    

CCCryptorStatus status = kCCSuccess;

NSData *encrypted = [toencrypt dataEncryptedUsingAlgorithm:kCCAlgorithmAES128 key:pass initializationVector:iv options:kCCOptionPKCS7Padding error:&status];

NSString *text = [NSString base64StringFromData:encrypted length:[encrypted length]];

The NSData category for encrypting comes from here...

http://github.com/AlanQuatermain/aqtoolkit/tree/master/CommonCrypto/

Incidentally, I have checked the byte arrays that are in toencrypt, pass and iv and they match those that are on the server.

5
I have changed the server to use ECB as suggested and still doesn't work. Incidentally I did notice the server using PKCS5 and client using PKCS7 but there is no 5 availabile on the client and no 7 available on the server, and apparently they are compatible anyway.Simon Lee
Yes, PKCS7 padding is the same as PKCS5Padding. If changing to ECB didn't work, it's likely that the iPhone is using CBC mode. You need to determine the initialization vector and make sure the server is using the same.erickson
Thanks for the replies. I created an IV same on the client and on the server but still not working. This is where a decent and reliable AES library for the iPhone is severely lacking! :(Simon Lee
Could you post a sample of a plain text and the resulting cipher text from each environment?laz
Have you tried using the other variants of the AES algorithm on the client? (ie. AES192, AES256)GameFreak

5 Answers

3
votes

This is not my area but it looks like on the client you have PKCS7 but on the server you have PKCS5.

3
votes

I just ran across the exact same problem. I am using CommonCrypto on the iOS client, using settings:

NSData * encrypted = [data dataEncryptedUsingAlgorithm:kCCAlgorithmAES128 key:pass initializationVector:iv options:kCCOptionPKCS7Padding error:&status];

The server uses Cipher.getInstance("AES/CBC/PKCS5Padding"); with the same key and initialization vector as the client.

After banging my head against the wall for the last few hours, I finally followed Jason's advice and checked the dataEncryptedUsingAlgorithm routine and printed out keyData right after FixKeyLengths. It turns out my 128bit key was extended to 192bit with 0s added to the end. After fixing this, everything works properly. :)

Update: My answer was posted almost 2 years ago, and this issue seems to be fixed in the latest NSData+CommonCrypto code. Specifically, this was the part that caused the issue:

static void FixKeyLengths( CCAlgorithm algorithm, NSMutableData * keyData, NSMutableData * ivData )
{
  NSUInteger keyLength = [keyData length];
  switch ( algorithm )
  {
    case kCCAlgorithmAES128:
    {
      if ( keyLength <= 16 )
      {
        [keyData setLength: 16];
      }
      else if ( keyLength <= 24 )
      {
        [keyData setLength: 24];
      }
      else
      {
        [keyData setLength: 32];
      }

      break;
    }

The first check keyLength <= 16 wasn't there before.

If you are still experiencing problems now, it's probably something else.

2
votes

What mode is the iPhone using with AES? You don't list anything, so perhaps that means it's using no chaining (ECB).

However, on the Java side, you are using CBC, but not specifying an initialization vector. That is definitely wrong. If you really are using CBC, you have to have the IV that was used during encryption. The IV is not secret; it can be sent along with the ciphertext.

If you are really using ECB, there is no IV, but your Java specifies the wrong mode.

0
votes

Based on your samples, the server is doing it right, and the client is not.

Looking at the data, I would guess that the key is wrong. Please show us the iPhone code, especially the code to go from "1234567891123456" to your key.

0
votes

I recently ran across this in another project. The problem was that the key was one byte too long to fit into the char buffer inside of the dataEncryptedUsingAlgorithm method.

The problem was that the getBytes method on the NSString was soft-failing. It would copy most of the string into the buffer, but then since the key was one byte too long, it would "mark" the operation as failed by setting the first char to NUL (char 0).

Step into that method in Xcode and see what your key char[16] buffer looks like. It may have this same problem, and have the contents { 0, '2', '3', '4', ... }.