使用Objective-C加密并使用MCRYPT_RIJNDAEL_256在PHP中解密MCRYPT_MODE_ECB

时间:2014-07-10 12:52:42

标签: php ios cryptography aes

首先,我想说我自己真的试图解决这个问题并阅读了很多内容(例如Objective-C version of PHP mcrypt_encryptHow to Decrypt a PHP Script in Objective-C / ios}

我真的被困了好几个小时。我必须在iOS中实现一个服务器API(就像我在Android上的同事一样)。服务器人告诉我们,我们必须发送加密密码,他们将使用mcrypt_decrypt解密。他们向我们发送了用于测试加密/解密的代码,这是他们的加密部分:

function fnEncrypt($sValue, $sSecretKey)
{

    $ivsize =  mcrypt_get_iv_size(
                        MCRYPT_RIJNDAEL_256, 
                        MCRYPT_MODE_ECB
                    );

    $iv = mcrypt_create_iv($ivsize, MCRYPT_RAND);

    $encrypted = mcrypt_encrypt(
                MCRYPT_RIJNDAEL_256,
                $sSecretKey, $sValue, 
                MCRYPT_MODE_ECB,
                $iv);

    $encoded = base64_encode($encrypted);

    $trimmed = rtrim($encoded, "\0");

    return $trimmed;
}

$prepared = fnEncrypt("somePassword","someKey");

echo $prepared; // => 42bbd9ZPMVFmm7Z9RfLb3zOrCpxnmwhl4gYRSb9WxY8=

现在我们都在尝试实施加密,但我将专注于iOS部分。我现在就在这里:

NSString* key = @"someKey";
    NSString* pw = @"somePassword";

    NSData *data = [pw dataUsingEncoding:NSUTF8StringEncoding];

    char keyPtr[kCCKeySizeAES256];
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSString *iv = @"12345678123456781234567812345678"; // Static
    char ivPtr[kCCKeySizeAES256];
    [iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [data length];

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

    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          kCCAlgorithmAES,
                                          kCCOptionECBMode|kCCOptionPKCS7Padding,
                                          keyPtr,
                                          kCCKeySizeAES256,
                                          ivPtr /* initialization vector (optional) */,
                                          [data bytes],
                                          dataLength, /* input */
                                          buffer,
                                          bufferSize, /* output */
                                          &numBytesEncrypted);

    if (cryptStatus == kCCSuccess)
    {

        NSData* resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        NSString* resultString = [resultData base64EncodedStringWithOptions:0];

        NSLog(@"resultString %@", resultString); // => 2rj7sDEoGtwDGPgae1BC1A==

        free(buffer);
        return resultString;
    }

    free(buffer);
    return nil;

无论我做什么,结果都是不一样的。我遇到了一个答案,有人说,编码的不同结果可能没问题,但在这种情况下,服务器给我一个错误,说密码不对。这意味着解密也会导致不同的结果。

有人在这些挫败感中看到任何错误吗?

编辑: 如果我将所有内容设置为128,在PHP MCRYPT_RIJNDAEL_256到MCRYPT_RIJNDAEL_128,在Objective C kCCKeySizeAES256到kCCKeySizeAES128,我可以使用Objective C加密并使用我自己的PHP脚本成功解密。在这种情况下,加密字符串仍然看起来不一样,但它们具有相同的长度。我假设Objective C端的填充将字节附加到密钥和密码,直到它们长16个字节。但是使用kCCKeySizeAES256,两个值似乎仍然附加到16个字节,而不是32个(推测!!!)。也许这就是原因。我仍然很乐意帮助你!

2 个答案:

答案 0 :(得分:2)

MCRYPT_RIJNDAEL_256 不是AES 。该mcrypt算法表示Rijndael的块大小为256位。密钥大小由密钥中的字节数决定(它使用带有00值字节的右边距填充向上舍入到PHP中最接近的密钥大小,如果超过256位则被削减)。请注意,PHP使用零填充。但是,你应该使用PKCS#7填充,那里的实现应该很少(例如在mcrypt_encrypt的注释中)。

要使用AES-256,请使用带有32字节密钥的MCRYPT_RIJNDAEL_128。您不会发现许多具有256位块大小的Rijndael实现。它没有增加太多安全性,也没有标准化(无论如何都是NIST)。

通常的警告适用于加密。如果IV,密钥,明文(字符)编码或密文编码相差一位,则可能会得到相当不同的输出。通过打印出字节的十六进制表示法来明确地测试每个输入/输出向量。

答案 1 :(得分:1)

另外,你得到了CString:maxLength:encoding需要比你想要存储的字符串大一个的缓冲区大小,因为它会为你添加NUL字节。只需在keyPtr和ivPtr声明中输入+1。