3

I have an iPad application that transmits encrypted information to a PHP-based website, but I'm having difficulties in properly decrypting this information. I use the following code for the PHP-side decryption:

//Decryption function

function mc_decrypt($decrypt, $key, $iv)  
{  
    $decoded = base64_decode($decrypt);  
    $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');  
    mcrypt_generic_init($td, $key, $iv);  
    $decrypted = mdecrypt_generic($td, $decoded);  
    mcrypt_generic_deinit($td);  
    mcrypt_module_close($td);  
    return trim($decrypted);  
}  

and this Objective-C code in my iPad application:

#import <CommonCrypto/CommonCryptor.h>

@implementation NSData (AES256)

- (NSData *)AES256EncryptWithKey:(NSString *)key {
    // '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];

    NSUInteger dataLength = [self 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,
                                     keyPtr, kCCKeySizeAES256,
                                     NULL /* initialization vector (optional) */,
                                     [self bytes], dataLength, /* 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;
}

- (NSData *)AES256DecryptWithKey:(NSString *)key {
    // '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];

    NSUInteger dataLength = [self 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 numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                     keyPtr, kCCKeySizeAES256,
                                     NULL /* initialization vector (optional) */,
                                     [self bytes], dataLength, /* input */
                                     buffer, bufferSize, /* output */
                                     &numBytesDecrypted);

    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    }

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

@end

Why am I seeing data corruption when trying to decrypt data encoded on the iPad and decrypted on the PHP side?

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
cs1.6
  • 159
  • 1
  • 2
  • 13

2 Answers2

3

Check the key that you're using. In PHP the MCRYPT_RIJNDAEL_128 _256 etc constants do not represent the key strength, but rather the block size being used.

To get 128-bit encryption with PHP you want to use a key that is 16 bytes long. For 256 you need 32 bytes and so on and so forth.

Both you PHP and C code look correct to me. Make sure the key is being used correctly in both cases.

As another thought. It looks like you're using PKCS#7 padding in C. I don't believe PHP is designed to work with that padding by default. If memory serves me, I believe the Mcrypt functions use null padding.

Lastly check your initialization vector in PHP. I noticed you're not using one in your C code which means you should not be accepting an $iv variable in PHP. That should be passed as NULL into the mcrypt functions (but this is highly discouraged).

What you should do instead is randomize an IV in your C code (where the data is being encrypted) and then send the IV along with the encrypted data. You can detect the size of the IV for the algorithm being used and split it off the front of the encrypted data to then use to populate your PHP side of things. This further secures your encryption for you.

Brian
  • 3,013
  • 19
  • 27
  • but when i decrypte any password having "é" i will have this né – cs1.6 Aug 15 '11 at 21:29
  • That's a text encoding problem (e.g, UTF-8). It has nothing to do with encryption. –  Aug 15 '11 at 23:16
  • 2-way encryption can be used to encode ANY data. Not just strings. As a result the output of decrypting something is actually binary information. If that information happens to correctly map to a UTF string, you'll get the output you want. Did you check your issue of the $iv param in PHP? You're not using an IV in your C code so you should not use one to decrypt with. The reason you're getting gibberish is because the decryption is not being executed correctly. Decrypting doesn't "validate" it simply runs the algorithm and gives you the output. It's up to you to determine if it worked. – Brian Aug 16 '11 at 20:19
  • To clarify, I'm referring to the function mc_decrypt($decrypt, $key, $iv) declaration and usage of the $iv variable here: mcrypt_generic_init($td, $key, $iv); VS the C code here: NULL /* initialization vector (optional) */ Since you're not using an IV, and your $iv param is **not** optional in PHP, I presume you're slicing off something and using it as an IV which would cause your IV and cipher text to both be incorrect which would result in corrupt output. – Brian Aug 16 '11 at 20:22
0

please refere to this discussion for better usage AES encrypt/decrypt AES with CommonCrypto uses too much memory - Objective-C

Community
  • 1
  • 1
Waleed
  • 117
  • 1
  • 4