简体   繁体   中英

Encrypt with Objective-C and decrypt in PHP using MCRYPT_RIJNDAEL_256 MCRYPT_MODE_ECB

First I want to say that I have really tried to solve this by myself and read a lot of stuff (like this Objective-C version of PHP mcrypt_encrypt and this How to Decrypt a PHP Script in Objective-C / ios )

I'm really stuck for hours. I have to implement a server API in iOS (as does my colleague next to me on Android). The server people told us we have to send an encrypted password, which they will decrypt with mcrypt_decrypt . They sent us the code they use to test the encryption/ decryption, here is their encryption part:

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=

Now we are both trying to implement the encryption, but I will concentrate on the iOS part. Here is where I'm now:

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;

Whatever I do, the result is never the same. I came across an answer where someone said, that different results in encoding may be ok, but in this case, the server gives me an error, saying that the password is not right. Which means that the decryption also leads to different results.

Does someone see any error in these lines of frustration?

EDIT: If I set everything to 128, in PHP MCRYPT_RIJNDAEL_256 to MCRYPT_RIJNDAEL_128 and in Objective C kCCKeySizeAES256 to kCCKeySizeAES128, I can encrypt with Objective C and decrypt successfully with my own PHP script. In that case the encryptet strings still don't look the same, but they have the same length. I assume that the padding on the Objective C side, will append bytes to key and password, until they are 16 byte long. But using kCCKeySizeAES256, both values still seem to be appended to 16 bytes, not 32 (speculation!!!). Maybe this is the cause. I still would be glad for some help!

MCRYPT_RIJNDAEL_256 is not AES . This algorithm of mcrypt indicates Rijndael with a block size of 256 bits. The key size is determined by the amount of bytes within the key (it's rounded up to the nearest key size in PHP using right padding with 00 valued bytes, and is cut if it exceeds 256 bits). Note that PHP uses zero padding. You should however use PKCS#7 padding, there should be few implementations of that out there (eg in the comments of mcrypt_encrypt ).

To use AES-256, use MCRYPT_RIJNDAEL_128 with a key of 32 bytes. You won't find many implementations of Rijndael with 256 bit block size. It does not add much security and it is not standardized (by NIST, anyway).

The usual caveats apply with crypto. If the IV, the key, the plaintext (character) encoding or ciphertext encoding differs by one bit, you may get a rather different output. Test each input/output vector explicitly by printing out the hexadecimal notation of the bytes.

In addition, you getCString:maxLength:encoding needs a buffer size one bigger than the string you intend to store, as it will add the NUL byte for you. Just put a +1 in the keyPtr and ivPtr declarations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM