4

I have been looking and looking at this for hours. I am desperately trying to get iOS to encrypt a short piece of text using AES-256 encryption that can then be decrypted by openssl.

Straight forward? Nope.

The code I've found for iOS is not compatible with the keys and IVs for openssl, so I've had to adapt it, but it's plainly not working.

So here is the code to encrypt I am using... passing in a string to encrypt (dataString) a string key (key) and a string initialisation vector (iv)...

- (NSData *)AES256Encrypt:(NSString *)dataString WithKey:(NSString *)key iv:(NSString *)iv {

    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    //char keyPtr[kCCKeySizeAES256+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];

    //NSLog(@"keyPtr: '%s'", keyPtr);

    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"keyPtr: '%s'", keyData.bytes);
    NSData *dataToEncrypt = [dataString dataUsingEncoding:NSUTF8StringEncoding];
    NSData *ivData = [iv dataUsingEncoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [dataToEncrypt length];

    //See the doc: For block ciphers, the output size will always be less than or 
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyData.bytes, kCCKeySizeAES256,
                                          ivData.bytes, // initialisation vector
                                          dataToEncrypt.bytes, 
                                          dataToEncrypt.length, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}

For the same string to encode, this does not produce the same value as when using openssl with the same key and iv... e.g. this command line:

openssl enc -aes-256-cbc -e -in secrets.txt -a -iv 0000 -K 0000 -p

secrets.txt is just a text file containing the string to be encrypted

This outputs something like this:

salt=3C66000000000000
key=0000000000000000000000000000000000000000000000000000000000000000
iv =00000000000000000000000000000000
qTMfgtAxbF8Yyh27ZDrcIQ==

And to decrypt, do the opposite operation (assuming the encrypted last line of data above is in test.secrets.out)

openssl enc -aes-256-cbc -d -in test.secrets.out -a -iv 0000 -K 0000 -p 
salt=3C66000000000000
key=0000000000000000000000000000000000000000000000000000000000000000
iv =00000000000000000000000000000000
< text of the secrets.txt file >

Now, if I use the key and iv of 4 chars, this doesn't encode correctly in iOS. If I use the full length key and iv, this doesn't encode correctly either.

Basically, this is a check to see that if I send a piece of encrypted data it is the right piece of data.

What am I missing?

Some code I've looked through to try to find an answer...

http://robnapier.net/blog/aes-commoncrypto-564

https://github.com/rnapier/RNCryptor

http://pastie.org/426530

Have searched extensively on here too and cannot find an answer.

Any help appreciated.

padajo
  • 65
  • 2
  • 8
  • See if you can get IOS to decrypt what it encrypted. – Hot Licks Jun 05 '12 at 16:19
  • Agree with Hot Licks, however if he is trying to encrypt locally using iOS accelerated routines to connect via SSL to something else, then..... I noticed the SSL is using the CBC mode of AES. Are you sure that you have setup the iOS in CBC mode. AES processes blocks in 128 bit chunks, perhaps its worth the research to find out whether iOS is interpreting the input data in little endian or big. This goes for the key and IV as well. – trumpetlicks Jun 05 '12 at 17:51
  • Just another note, you may also need to look at how the data is padded for the last 128 bit block (if the data is NOT aligned on a 128 bit bound). – trumpetlicks Jun 05 '12 at 17:52
  • Hot Licks: Yes - have checked it decrypts what I encrypt. That appears to not be the issue... although decrypting the data is not needed here. – padajo Jun 06 '12 at 10:08
  • trumpetlicks: have looked at padding and little/big endian... although I'm not sure I know enough as to how to look *in detail* at this bit. The code is purely to provide an encrypted packet along with an HTTP POST operation with a shared private key. This way the other end can check the data has been tampered with or not. So no need for decryption or anything like that. – padajo Jun 06 '12 at 10:11
  • Have had the API remove the AES encryption as it's just not clear what key it's using to encrypt, so we cannot guarantee decryption or encryption anywhere else will be the same. *sigh* – padajo Jun 14 '12 at 10:40

1 Answers1

2

OpenSSL has a unique (read "not close to any standard, and also not particularly secure") method for converting passwords into IV and key. If you look at RNOpenSSLCryptor, you'll see the algorithm used:

// For aes-128:
//
// key = MD5(password + salt)
// IV = MD5(Key + password + salt)

//
// For aes-256:
//
// Hash0 = ''
// Hash1 = MD5(Hash0 + Password + Salt)
// Hash2 = MD5(Hash1 + Password + Salt)
// Hash3 = MD5(Hash2 + Password + Salt)
// Hash4 = MD5(Hash3 + Password + Salt)
//
// Key = Hash1 + Hash2
// IV = Hash3 + Hash4
//

// File Format:
//
// |Salted___|<salt>|<ciphertext>|
//

Using RNOpenSSLCryptor allows RNCryptor support for the OpenSSL format. I am currently in the midst of reworking this code on the async branch to support async operations, and that branch doesn't yet support OpenSSL, but I do plan to rework that shortly (by mid-July 2012).

If you want code that implements this for your own use, look at keyForPassword:salt: and IVForKey:password:salt:.

Note that the the OpenSSL file format has several security problems and I don't recommend it if you can avoid it. It does not use a very good KDF to generate its key, does not have as random an IV as it should, and provides no HMAC for authentication. These security problems are why I designed a different file format, much as I hated creating "yet another incompatible container."

Rob Napier
  • 286,113
  • 34
  • 456
  • 610