RNCryptor AES256匹配PHP MCRYPT_RIJNDAEL_256 [英] RNCryptor AES256 to match PHP MCRYPT_RIJNDAEL_256

查看:315
本文介绍了RNCryptor AES256匹配PHP MCRYPT_RIJNDAEL_256的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在iOS应用程序中调用的PHP API要求有效载荷以特定的定制方式进行加密。我正在使用RNCryptor在Objective-C中复制该方法。



以下是用于加密字符串的PHP代码:

 函数encrypt($ string){
$ key ='some-random-key';
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256,md5($ key)),$ string,MCRYPT_MODE_CBC,md5(md5($ key))));
}

这个我如何尝试在Objective- C:

  +(NSData *)encryptData:(NSData *)sourceData {

NSString * keyString = @some-random-key;
NSData * key = [[keyString MD5String] dataUsingEncoding:NSUTF8StringEncoding];
NSData * iv = [[[keyString MD5String] MD5String] dataUsingEncoding:NSUTF8StringEncoding];

NSMutableData * encryptedData = [NSMutableData data];

RNCryptorEngine * cryptor = [[RNCryptorEngine alloc] initWithOperation:kCCEncrypt设置:kRNCryptorAES256设置密钥:key IV:iv error:nil];

[encryptedData appendData:[cryptor addData:sourceData error:nil]];
[encryptedData appendData:[cryptor finishWithError:nil]];

return encryptedData;

}

但两个功能的结果从不匹配。例如,对于相同的单字字符串,PHP代码返回 J39gRcuBEaqMIPP1VlizdA8tRjmyAB6za4zG5wcOB / 8 = ,而在Objective-C(运行 base64EncodedStringWithOptions: code>在得到的NSData)我得到 1FGpZpVm2p4z3BBY6KW2fw ==



有什么我需要进一步调整RNCryptor设置以使其正常工作?



更新



我已经直接玩了本地iOS CommonCrypto框架,而不用完全使用第三方的RNCryptor lib。我一直得到与RNCryptor相同的结果。我甚至尝试在我的Objective-C和PHP片段中实现AES128,但即使从未使两个环境的结果匹配...



更新2



我使用的 MD5String 方法是NSString中的一个类别,定义如下: p>

   - (NSString *)MD5String {
const char * cstr = [self UTF8String];
unsigned char result [16];
CC_MD5(cstr,strlen(cstr),result);

返回[[NSString stringWithFormat:
@%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X %02X,
结果[0],结果[1],结果[2],结果[3],
结果[4],结果[5],结果[6],结果[7 ],
结果[8],结果[9],结果[10],结果[11],
结果[12],结果[13],结果[14],结果[15]
] lowercaseString];
}


解决方案

Zaph的笔记, p>


数据将以\0个字符填充到块大小的倍数


让我正轨,帮我弄清楚部分问题。



本质上,PHP的 mcrypt 仅使用 \0 填充数据,而Apple的CommonCryptor可让您选择PKCS7填充( kCCOptionPKCS7Padding )或没有填充。这是我无法获得数据匹配的原因之一:在加密之前,它总是被填充不同。



解决方案是要么在运行 mcrypt 示例解决方案)或使Objective-C执行PHP风格的 \0 填充,并确保删除 kCCOptionPKCS7Padding (将NULL传递给CCCrypt选项):

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

//查看需要多少填充
NSUInteger padding = kCCBlockSizeAES128 - (dataLength%kCCBlockSizeAES128);

//添加多个\0(可能会有一个更有效的方式来做到这一点)
for(int i = 0; i< padding; i ++)
[ dataToEncrypt appendData:[@\0dataUsingEncoding:NSASCIIStringEncoding]];

//重新计算数据长度
dataLength = dataToEncrypt.length;

我最终放弃了RNCryptor,直接使用了NativeCryptor API,所以最终的结果看起来是像这样( encryptedBase64String 方法这里是我的应用程序中 NSString 的一个类别,因为我只需要加密字符串这样做;还要注意 kHSEncryptionKey 表示自由格式键字符串的常量:

   - (NSString *)encryptedBase64String {

//准备数据

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

//处理密钥

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

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

//处理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];

//填写数据,PHP样式

NSUInteger dataLength = [sourceData length];
NSUInteger padding = kCCBlockSizeAES128 - (dataLength%kCCBlockSizeAES128);对于(int i = 0; i< padding; i ++)
[sourceData appendData:[@\0dataUsingEncoding:NSASCIIStringEncoding]];



dataLength = sourceData.length;

//生成数据的缓冲区

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

//运行加密

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;
}


The PHP API I’m calling from within my iOS app requires the payload to be encrypted in a certain customised way. I’m having troubles replicating that approach in Objective-C, with RNCryptor.

Here is the PHP code used to encrypt a string:

function encrypt($string) {
    $key = 'some-random-key';
    return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, md5(md5($key))));
}

And this how I’m trying to achieve the same encryption result in Objective-C:

+ (NSData*)encryptData:(NSData*)sourceData {

    NSString *keyString = @"some-random-key";
    NSData *key = [[keyString MD5String] dataUsingEncoding:NSUTF8StringEncoding];
    NSData *iv = [[[keyString MD5String] MD5String] dataUsingEncoding:NSUTF8StringEncoding];

    NSMutableData *encryptedData = [NSMutableData data];

    RNCryptorEngine *cryptor = [[RNCryptorEngine alloc] initWithOperation:kCCEncrypt settings:kRNCryptorAES256Settings key:key IV:iv error:nil];

    [encryptedData appendData:[cryptor addData:sourceData error:nil]];
    [encryptedData appendData:[cryptor finishWithError:nil]];

    return encryptedData;

}

But the results from the two functions never match. E.g., for the same one-word string, the PHP code returns J39gRcuBEaqMIPP1VlizdA8tRjmyAB6za4zG5wcOB/8=, while in Objective-C (after running base64EncodedStringWithOptions: on the resulting NSData) I’m getting 1FGpZpVm2p4z3BBY6KW2fw==.

Is there something I need to further tweak in the RNCryptor settings to make it work?

UPDATE

I’ve played around the the native iOS CommonCrypto framework directly, without using the third party RNCryptor lib altogether. I’m consisently getting the same result as with RNCryptor though. I even tried implementing AES128 in both my Objective-C and PHP snippets, but even that never made the results from the two environments match…

UPDATE 2

The MD5String method I‘m using is a category on NSString and is defined as follows:

- (NSString *)MD5String {
    const char *cstr = [self UTF8String];
    unsigned char result[16];
    CC_MD5(cstr, strlen(cstr), result);

    return [[NSString stringWithFormat:
            @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
            result[0], result[1], result[2], result[3],
            result[4], result[5], result[6], result[7],
            result[8], result[9], result[10], result[11],
            result[12], result[13], result[14], result[15]
            ] lowercaseString];
}

解决方案

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;
}

这篇关于RNCryptor AES256匹配PHP MCRYPT_RIJNDAEL_256的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆