IOS DES加密和PHP解密无法可靠地工作

IOS DES加密和PHP解密无法可靠地工作

问题描述:

I'm encrypting a string in iOS using the method below


-(NSString *) encrypt:(NSString *) data 
{

    const void *vplainText;
    size_t plainTextBufferSize = [data length];
    vplainText = (const void *) [data UTF8String];
    CCCryptorStatus ccStatus;
    uint8_t *bufferPtr = NULL;
    size_t bufferPtrSize = 0;
    size_t movedBytes = 0;

    bufferPtrSize = (plainTextBufferSize + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
    bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
    memset((void *)bufferPtr, 0x0, bufferPtrSize);

    Byte iv [] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef};

    NSString *key = @"complexkey";
    const void *vkey = (const void *) [key UTF8String];

    ccStatus = CCCrypt(kCCEncrypt,
                       kCCAlgorithmDES,
                       kCCOptionPKCS7Padding | kCCOptionECBMode,
                       vkey,
                       kCCKeySizeDES,
                       iv,
                       vplainText,
                       plainTextBufferSize,
                       (void *)bufferPtr,
                       bufferPtrSize,
                       &movedBytes);

    NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
    NSString *result = [myData base64Encoding];

    // url encode the result
    return (__bridge NSString *) CFURLCreateStringByAddingPercentEscapes(NULL,
                                        (__bridge CFStringRef) result,
                                        NULL,
                                        (__bridge CFStringRef) @"!*'();:@&=+$,/?%#[]",
                                        kCFStringEncodingUTF8);
}

And on php, I'm decrypting the string as follows -


$decrypted = mcrypt_decrypt(MCRYPT_DES, 'complexkey', base64_decode(urldecode($encrypted)), MCRYPT_MODE_ECB);

This seems to work correctly 75% of the time and I'm not sure why it fails at other times. Any clues? Thanks for the help!

It turns out that there was nothing wrong in the encryption/decryption I was doing. Rather the issue was that urldecode() in PHP wasn't decoding '%2B' to '+' (but instead to ' '). I switched from urldecode() to rawurldecode() in PHP and everything is working fine now!

It's probably the padding, it is the only thing that is not synchronized between the two methods. Unfortunately, you may have to create your own unpadding form mcrypt, as that library does not perform PKCS#5 padding (same as PKCS#7 padding really). Fortunately that is rather simple: decrypt, then use the value of the last byte to strip of the last bytes.

Other security related notes:

  • DES is not safe, use 3DES (or officially TDEA) as a minimum;
  • ECB mode is not safe, use CBC (which does use an IV);
  • ECB mode does not use an IV;
  • for client/server authentication you need to be aware of padding oracle attacks.