I have a XML file on a server encrypted with the RC4 algorithm (http://rc4crypt.devhome.org)
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;
}
Here is the objective-C code I use to decrypt :
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];
Logs output : SUCCESS but my result is not good (I tested many encoding but ASCII seems to be the good, cf. PHP function ord …)
Are my both RC4 implementation standard ?
Edit: removed IV in Objective-C code
Edit2: Objective-C KeyLength = password data length, removed option
If you don’t know what you’re doing in cryptography, then “rolling-your-own” is a sure fire receipe for disaster. You don’t have to believe me, read John Viega on The Cult of Schneier about general programmers who try to “roll their own” cryptography. Paraphrased: Don’t do it.
Since this is a file, and I’m guessing a reasonable small file, you can use more standard and higher level libraries using standards such as SSL (OpenSSL and others) or OpenPGP (GPG, etc.) to do the necessary encryption / decryption. I believe there is library or module support for SSL in both Objective-C (or the iPhone environment) and PHP.
In particular about RC4, it is a stream cipher that is deceptively simple to write, but incredibility easy to mess up in its implementation details. See The Misuse of RC4 in Microsoft Word and Excel, and Can you recommend RC4 128-bit encrypted software? for an well known historic example, and a recommendation of security / cryptography expert (former CTO and co-founder of PGP Corp.).
Added:
The keysize in the php script is based on the raw length of the password data. It also does not use any PKCS7 Padding, so I believe that field should be zero (0) (CCryptor doesn’t support padding of stream ciphers, and the php version certainly doesn’t use it). In your code CCCrypt used a keysize of 8 bytes (64* bits), whereas I believe you want it to be the length (in bytes) of the password (binary data).
There is no MAC or hash of the data so the functions won’t be able to determine valid from invalid decodings.
I think this will get you closer to compatibility with this insecure implementation of RC4 (RC4crypt in PHP).