Reputation: 1779
I have the following code that does a XOR encode/decode procedure:
<?php
/*
* Simple XOR encoder/decoder, Inkubus
*
*/
$key = pack("H*","3cb37efae7f4f376ebbd76cd");
//$encoded = ")5/Y+F8'0P$/;"; // <- OK, Working
//$decoded = 'hM5cf$350';
$encoded = "-?^<]TLV.GQV)B4[YQ "; // <- BAD, Not working
$decoded = "CTC(*zlkb4848";
//$encoded = ')3\8?E(21@$;='; // <- OK, Working
//$decoded = 'suances06';
function decode($encoded,$key) {
$cipher = convert_uudecode($encoded);
$plain = $cipher ^ $key;
$result = substr($plain, 0, strlen($cipher));
return $result;
}
function encode($decoded,$key) {
$plain = $decoded ^ $key;
$result = convert_uuencode(substr($plain, 0, strlen($decoded)));
$result = preg_replace("/\n/m","",$result);
$result = preg_replace("/`$/m","",$result);
return $result;
}
echo "Encoded: " . $encoded . "\n";
echo "Decoded: " . decode($encoded,$key) . "\n";
echo "Encoded: " . encode($decoded,$key) . "\n";
echo "Decoded: " . decode(encode($decoded,$key),$key) . "\n";
?>
commented right after the header are two examples that work, the uncommented is the one with problem. How can I GENERICALLY comment the UUENCODED string to be decoded so it is kept unchanged and decoded right? Commenting any problematic character in the string is not an option, but the entire string as a whole.
Working run example:
bash-$ php xor.php
Encoded: )3\8?E(21@$;=
Decoded: suances06
Encoded: )3\8?E(21@$;=
Decoded: suances06
Not working example:
bash-$ php xor.php
Encoded: -?^<]TLV.GQV)B4[YQ
Decoded: CTC(*zlkb484
Encoded: ,?^<]TLV.GQV)B4[Y
Decoded: CTC(*zlkb484
Some character is lost or whatever. Any ideas?
Thanks!
UPDATE: Another not working example:
$encoded = "-!8H<RY67FP';C1+]R@ "; // <- BAD, Not working
$decoded = "99b1rchw00d06";
Ran:
bash-$ php xor.php
Encoded: -!8H<RY67FP';C1+]R@
Decoded: 99b1rchw00d0
Encoded: ,!8H<RY67FP';C1+]
Decoded: 99b1rchw00d0
Upvotes: 1
Views: 177
Reputation: 7157
It's a unclear bit what you're actually asking here. Your functions contain a lot of cruft code and can/should be reduced to:
function decode($encoded,$key) {
return convert_uudecode($encoded) ^ $key;
}
function encode($decoded,$key) {
return convert_uuencode($decoded ^ $key);
}
The reason this does not work as you expect is because PHP's XOR doess not work the way you're hoping:
$a = "-?^<]TLV.GQV)B4[YQ ";
$b = pack("H*","3cb37efae7f4f376ebbd76cd");
$c = ($a ^ $b) ^ $b;
echo $a == $c ? 'OK' : 'NOT OK';
This will output NOT OK
. If you want a simple string XOR operator, use this:
function str_xor($a, $b){
$out = '';
for ($i=0; $i<strlen($a); $i++){
$ac = ord($a{$i});
$bc = ord($b{$i});
$out .= chr($ac ^ $bc);
}
return $out;
}
The preceding example code will then round-trip:
$c = str_xor(str_xor($a, $b), $b);
echo $a == $c ? 'OK' : 'NOT OK';
# outputs 'OK'
PHP's XOR function does not work on strings where the 2nd operand is shorter that the first - it will truncate the returned string to the length of the 2nd operand (it's fine if the 2nd operand is longer than the first - it truncates the output to the length of the shortest operand).
Another possible solution is to just expand your key like this:
while (strlen($key) < strlen($text)) $key .= $key;
This will make sure that your key is longer than the thing you're XOR'ing
Upvotes: 1