8

I'm new to Xor encryption, and I'm having some trouble with the following code:

function xor_this($string) {

// Let's define our key here
 $key = ('magic_key');

 // Our plaintext/ciphertext
 $text =$string;

 // Our output text
 $outText = '';

 // Iterate through each character
 for($i=0;$i<strlen($text);)
 {
     for($j=0;$j<strlen($key);$j++,$i++)
     {
         $outText .= $text{$i} ^ $key{$j};
         //echo 'i='.$i.', '.'j='.$j.', '.$outText{$i}.'<br />'; //for debugging
     }
 }  
 return $outText;
}

When I run this it works for normal strings, like 'dog' but it only partially works for strings containing numbers, like '12345'.

To demonstrate...

xor_this('dog') = 'UYV'

xor_this('123') = ''

It's also interesting to note that xor_this( xor_this('123') ) = '123', as I expect it to. I'm pretty sure the problem resides somewhere in my shaky understanding of bitwise operators, OR possibly the way PHP handles strings that contain numbers. I'm betting there's someone clever out there that knows exactly what's wrong here. Thanks.

EDIT #1: It's not truly 'encryption'. I guess obfuscation is the correct term, which is what I'm doing. I need to pass a code containing unimportant data from a user without them being able to easily tamper with it. They're completing a timed activity off-line and submitting their time to an online scoreboard via this code. The off-line activity will obfuscate their time (in milliseconds). I need to write a script to receive this code and turn it back into the string containing their time.

e-sushi
  • 13,786
  • 10
  • 38
  • 57
emersonthis
  • 32,822
  • 59
  • 210
  • 375
  • 2
    I hope you don't intend to use this for anything more than homework :P – lsl Sep 25 '11 at 21:16
  • 1
    Try casting `$string` to a string like: `$string = (string)$string`. Also, do note that "encryption" is a rather strong word for XORing things, so don't use it in a production environment. – Bojangles Sep 25 '11 at 21:16
  • 2
    You are working too hard. PHP will happily xor each character of a string, and give the result as another string. You don't need a loop to do it yourself, just do `$str1 ^ $str2`. But WATCH OUT! The result string will be as long as the shortest string! (Including the empty string!) So pad the strings first, or do them in chunks. – Ariel Jul 10 '12 at 09:02
  • Your probably safer AND have much less work if you just use some of the built in encoding/decoding functions that php already has. For example the mcrypt functions. The phpdoc page has samples. – ToBe Mar 13 '14 at 14:53

9 Answers9

4

How i did it, might help someone ...

$msg = 'say hi!';
$key = 'whatever_123';

// print, and make unprintable chars available for a link or alike.
// using $_GET, php will urldecode it, if it was passed urlencoded
print "obfuscated, ready for url: " . urlencode(obfuscate($msg, $key)) . "\n";
print "deObfuscated: " . obfuscate(obfuscate($msg, $key), $key);


function obfuscate($msg, $key) {
    if (empty($key)) return $msg;
    return $msg ^ str_pad('', strlen($msg), $key);
}
BananaAcid
  • 3,221
  • 35
  • 38
3

I think you might have a few problems here, I've tried to outline how I think you can fix it:

  • You need to use ord(..) to get the ASCII value of a character so that you can represent it in binary. For example, try the following:

    printf("%08b ", ord('A')); // outputs "01000001"
    
  • I'm not sure how you do an XOR cipher with a multi-byte key, as the wikipedia page on XOR cipher doesn't specify. But I assume for a given key like "123", your key starts "left-aligned" and extends to the length of the text, like this:

    function xor_this($text) {
        $key = '123';
        $i = 0;
        $encrypted = '';
        foreach (str_split($text) as $char) {
            $encrypted .= chr(ord($char) ^ ord($key{$i++ % strlen($key)}));
        }
        return $encrypted;
    }
    print xor_this('hello'); // outputs "YW_]]"
    

    Which encrypts 'hello' width the key '12312'.

Rusty Fausak
  • 7,355
  • 1
  • 27
  • 38
1

Use this code, it works perfect

function scramble($inv) {
  $key=342244;  // scramble key
  $invarr=str_split($inv);
  for($index=0;$index<=strlen($inv)-1;$index++) {
    srand($key);
    $var=rand(0,255);
    $res=$res.(chr(ord($var)) ^ chr(ord($invarr[$index])));
    $key++;
  }
  return($res);
}
1

There's no guarantee that the result of the XOR operation will produce a printable character. If you give us a better idea of the reason you're doing this, we can probably point you to something sensible to do instead.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • I hope my edit clarifies what I'm trying to do. I actually don't need to encrypt anything. My task is simply to decrypt whatever I'm given, and I want to make sure my function can properly handle integers since that's exactly what I'll be receiving. – emersonthis Sep 25 '11 at 21:30
1

I believe you are faced with console output and encoding problem rather than XOR-related. Try to output results of xor function in a text file and see a set of generated characters. I believe HEX editor would be the best choice to observe and compare a generated characters set.

Basically to revert text back (even numbers are in) you can use the same function:

var $textToObfuscate = "Some Text 12345";
var $obfuscatedText = $xor_this($textToObfuscate);
var $restoredText = $xor_this($obfuscatedText);
sll
  • 61,540
  • 22
  • 104
  • 156
1

Based on the fact that you're getting xor_this( xor_this('123') ) = '123', I am willing to guess that this is merely an output issue. You're sending data to the browser, the browser is recognizing it as something which should be rendered in HTML (say, the first half dozen ASCII characters). Try looking at the page source to see what is really there. Better yet, iterate through the output and echo the ord of the value at each position.

cwallenpoole
  • 79,954
  • 26
  • 128
  • 166
0

Try this:

$outText .= (string)$text{$i} ^ (string)$key{$j};

If one of the two operands is an integer, PHP casts the other to an integer and XORs them for a numeric result.

Alternatively, you could use this:

$outText .= chr(ord($text{$i}) ^ ord($key{$j}));
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
0
// Iterate through each character
for($i=0; $i<strlen($text); $i++)
{
    $outText .= chr(ord($text{$i}) ^ ord($key{$i % strlen($key)))};
}

note: it probably will create some weird characters...

Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
-3

Despite all the wise suggestions, I solved this problem in a much simpler way:

I changed the key! It turns out that by changing the key to something more like this:

$key = 'ISINUS0478331006';

...it will generate an obfuscated output of printable characters.

emersonthis
  • 32,822
  • 59
  • 210
  • 375
  • 6
    And you know **why** it works now? If not, how do you know when the problem arises the next time? – martinstoeckli Jan 24 '13 at 11:50
  • 2
    Might be a solution for you but it is no solution for anyone else having this problem since it only works around your dangerous characters. – ToBe Mar 13 '14 at 14:54