RC4加密 - CommonCrypto(Objective-C)与PHP

时间:2010-02-10 09:34:42

标签: php iphone objective-c algorithm encryption

我在使用RC4算法(http://rc4crypt.devhome.org

加密的服务器上有一个XML文件
function encrypt ($pwd, $data, $ispwdHex = 0)
    {
        if ($ispwdHex)
            $pwd = @pack('H*', $pwd); // valid input, please!

        $key[] = '';
        $box[] = '';
        $cipher = '';

        $pwd_length = strlen($pwd);
        $data_length = strlen($data);

        for ($i = 0; $i < 256; $i++)
        {
            $key[$i] = ord($pwd[$i % $pwd_length]);
            $box[$i] = $i;
        }
        for ($j = $i = 0; $i < 256; $i++)
        {
            $j = ($j + $box[$i] + $key[$i]) % 256;
            $tmp = $box[$i];
            $box[$i] = $box[$j];
            $box[$j] = $tmp;
        }
        for ($a = $j = $i = 0; $i < $data_length; $i++)
        {
            $a = ($a + 1) % 256;
            $j = ($j + $box[$a]) % 256;
            $tmp = $box[$a];
            $box[$a] = $box[$j];
            $box[$j] = $tmp;
            $k = $box[(($box[$a] + $box[$j]) % 256)];
            $cipher .= chr(ord($data[$i]) ^ $k);
        }
        return $cipher;
    }

这是我用来解密的Objective-C代码:

      NSData *dataToDecrypt = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.url.com/fileCrypted.xml"]] returningResponse:nil error:nil];
        const void *vplainText;
        size_t plainTextBufferSize;


            plainTextBufferSize = [dataToDecrypt length];
            vplainText = [dataToDecrypt bytes];


        CCCryptorStatus ccStatus;
        uint8_t *bufferPtr = NULL;
        size_t bufferPtrSize = 0;
        size_t movedBytes = 0;

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

        NSString *key = @"mykey";
        //NSString *initVec = @"init Vec";
        const void *vkey = (const void *) [key UTF8String];
        const void *vinitVec = (const void *) [initVec UTF8String];

size_t keyLength = [[key dataUsingEncoding:NSUTF8StringEncoding] length]; 
        ccStatus = CCCrypt(kCCDecrypt,
                           kCCAlgorithmRC4,
                           0,
                           vkey,
                           kCCKeySizeDES,
                           nil,
                           vplainText,
                           plainTextBufferSize,
                           (void *)bufferPtr,
                           bufferPtrSize,
                           &movedBytes);
        if (ccStatus == kCCSuccess) NSLog(@"SUCCESS");
        /*else*/ if (ccStatus == kCCParamError) return @"PARAM ERROR";
        else if (ccStatus == kCCBufferTooSmall) return @"BUFFER TOO SMALL";
        else if (ccStatus == kCCMemoryFailure) return @"MEMORY FAILURE";
        else if (ccStatus == kCCAlignmentError) return @"ALIGNMENT";
        else if (ccStatus == kCCDecodeError) return @"DECODE ERROR";
        else if (ccStatus == kCCUnimplemented) return @"UNIMPLEMENTED";

        NSString *result = [[ NSString alloc ] initWithData: [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes] encoding:NSASCIIEncoding];

日志输出:SUCCESS但我的结果不好(我测试了很多编码,但ASCII似乎是好的,参见PHP函数ord ...)

我的两个RC4实施标准是什么?

编辑:在Objective-C代码中删除了IV Edit2:Objective-C KeyLength =密码数据长度,删除选项

2 个答案:

答案 0 :(得分:3)

如果您不知道自己在加密方面所做的工作,那么“滚动自己”就是灾难的必要条件。你不必相信我,在The Cult of Schneier上阅读John Viega,了解那些试图“推出自己的”密码学的普通程序员。转述:不要这样做。

由于这是一个文件,我猜一个合理的小文件,你可以使用更多标准和更高级别的库,使用SSL(OpenSSL等)或OpenPGP(GPG等)等标准来做必要的加密/解密。我相信在Objective-C(或iPhone环境)和PHP中都有SSL的库或模块支持。

特别是关于RC4,它是一个流密码,编写起来很简单,但令人难以置信的是它的实现细节容易搞乱。有关众所周知的历史案例,请参阅The Misuse of RC4 in Microsoft Word and ExcelCan you recommend RC4 128-bit encrypted software?,以及安全/加密专家(前CTO和PGP公司联合创始人)的推荐。


<强>加了:

php脚本中的密钥大小基于密码数据的原始长度。它也没有使用任何PKCS7 Padding,所以我认为该字段应该为零(0)(CCryptor不支持流密码的填充,并且php版本肯定不使用它)。在你的代码中,CCCrypt使用了8字节(64 *位)的密钥,但我相信你希望它是密码的长度(以字节为单位)(二进制数据)。

数据没有MAC或散列,因此函数无法从无效解码中确定有效。

我认为这将使您更接近与RC4的这种不安全的实现(PHP中的RC4crypt)的兼容性。

答案 1 :(得分:1)

在@mctylr的基础上,尽可能避免自己滚动。如果您需要RC4,请使用预先构建/测试的库:OpenSSL RC4。您可以用大约3行替换整个代码。