RNCryptor AES256 to match PHP MCRYPT_RIJNDAEL_256

删除回忆录丶 提交于 2019-12-04 16:02:26

Although most of the answers focus on the MD5 hash, what's most likely to cause issues is the fact that MCRYPT_RIJNDAEL_256 is not AES. It does not specify a key size of 256 but a block size of 256, while AES always has a block size of 128 bits. As for the other parameters, print out their values in hexadecimal right before the encryption routine in both sides to find out their values.

I realize I'm late to the party here and you've probably already moved on. But I want to point out that there's now a full PHP port of RNCryptor that is bytestream compatible with the Objective-C implementation. I myself contributed it last summer, and I am currently maintaining it. :-)

So it should be quite easy now to encrypt with RNCryptor PHP and decrypt with RNCryptor Objective-C, or vice-versa. Check out the main RNCryptor project for details and a list of sub-projects.

It is uncommon to return an md5 as a hex-ascii in other than scripting languages, even php provides a binary output option.

There are a few n on-standard things about the php mcrypt_encrypt:

  1. Padding the key with \0 if it is smaller than the required key size.
  2. The data will be padded with \0 characters to a multiple of block size, generally a padding such as pkcs7 is used.
  3. Not specified is how an iv that is not a block size is handled, one could guess that is is also padded with trailing \0 characters.

Of these the iv will be the correct length due to the hex-ascii out put of the md5 method. But the that leaves the data length and the padding which is non-standard.

The key will be 32 bytes so will be padded with 32 \0 characters in php. This begs the question of using AES256 with a 128 bit key.

From the underlying CommonCrypto "CommonCryptor.h":

keyLength: Length of key material. Must be appropriate for the selected operation and algorithm.

The key length is not correct.

Things to do:
1. Handle the data length/padding
2. Handle the key length

For further help please provide sample data you are using and the hex-ascii out put of mcrypt_encrypt prior to base64 encoding.

For reference see:
mcrypt-encrypt.php and md5.php

Zaph’s note, that

The data will be padded with \0 characters to a multiple of block size

set me on track and helped me figure out part of the problem.

Essentially, PHP’s mcrypt only uses \0 padding for the data, while Apple’s CommonCryptor lets you choose between PKCS7 padding (kCCOptionPKCS7Padding) or no padding whatsoever. This was one of the reasons I could never get the data to match: it was always padded differently before it was about to get encrypted.

The solution for this is to either make PHP perform PKCS7 padding of the data before running mcrypt (example solution) or to make Objective-C perform PHP-style \0 padding and make sure to remove kCCOptionPKCS7Padding (pass NULL to CCCrypt options):

NSMutableData *dataToEncrypt = [sourceData mutableCopy];
NSUInteger dataLength = [dataToEncrypt length];

// See how much padding is required
NSUInteger padding = kCCBlockSizeAES128 - (dataLength % kCCBlockSizeAES128);

// Add that many \0’s (there could be a more efficient way to do this)
for (int i=0; i<padding; i++)
    [dataToEncrypt appendData:[@"\0" dataUsingEncoding:NSASCIIStringEncoding]];

// Recalculate the data length
dataLength = dataToEncrypt.length;

I ended up ditching RNCryptor and working with the native CommonCryptor API directly instead, so the end result looked something like this (the encryptedBase64String method here is a category on NSString in my application, because I only ever need to encrypt strings this way; also note the kHSEncryptionKey constant representing the freeform key string):

- (NSString*)encryptedBase64String {

    // Prepare the data

    NSMutableData *sourceData = [[self dataUsingEncoding:NSUTF8StringEncoding] mutableCopy];

    // Process the key

    NSString *key = [[kHSEncryptionKey MD5String] substringWithRange:NSMakeRange(0, 16)];

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

    // Process the iv

    NSString *iv = [[[kHSEncryptionKey MD5String] MD5String] substringWithRange:NSMakeRange(0, 16)];

    char ivPtr[kCCKeySizeAES128 + 1];
    bzero(ivPtr, sizeof(ivPtr));
    [iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];

    // Pad the data, PHP style

    NSUInteger dataLength = [sourceData length];
    NSUInteger padding = kCCBlockSizeAES128 - (dataLength % kCCBlockSizeAES128);

    for (int i=0; i<padding; i++)
        [sourceData appendData:[@"\0" dataUsingEncoding:NSASCIIStringEncoding]];

    dataLength = sourceData.length;

    // Buffer for the resulting data

    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void* buffer = malloc(bufferSize);

    // Run the encryption

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, NULL,
                                          keyPtr, kCCKeySizeAES128,
                                          ivPtr,
                                          sourceData.bytes, dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);

    if (cryptStatus == kCCSuccess) {
        NSData *encyptedData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        return [encyptedData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    }

    free(buffer);
    return nil;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!