Prerequisites:
PHP 7.x
This piece of code is a simple way of encrypting and decrypting text using a bit wise XOR operation (⊕). First a simple reminder about how XOR operators work.
XOR stands for Exclusive OR. This means that the output of A XOR B will only return 1 if either A or B is 1, see the truth table below.
A | B | O |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
So in practice, lets say we have the binary numbers 01110110 and 11011010. If we want to XOR these two numbers we can do it easy by writing them like this:
01110110
⊕ 11011010
10101100
As you can see, anytime we have a 1 and a 0 in the same position the result is a 1, and in all other cases it’s a 0. You might be thinking, “Well that’s great, but what is this useful for”? I’ll show you. Let’s take that output we got and XOR that number with our second binary number from earlier.
10101100
⊕ 11011010
01110110
The result of this is the same as our first binary number. This means that we can use our second binary number as an encryption key. Now I’ll be the first to tell you that an 8 bit encryption key, as in the example above, is totally useless. So the encryption method will not fool any government agencies. But you can use it to keep some secrets from your friends (or enemies).
The code below will not use a single 8 bit binary as a key, but a string (unless you use a single character key, which you shouldn’t). This means that it will loop over each character in the key when encrypting. Let’s say you have a message of 10 characters and a key of 4 characters, the first, fifth, and ninth characters in the message will be encrypted using the first character of the key, and so on. The longer the key, the harder the message will be to decrypt. This means that there’s no need for a key that’s longer than the message.
The encrypt function below takes two strings, a plaintext message and a key. For each character in the message, XOR that character with the corresponding character in the key ($keyPos). This result is then converted into a 8 bit binary value, and then converted to a two digit hexadecimal value and appended to a string, which is what we will return.
function encrypt(string $plainText, string $key) : string { $output = ""; $keyPos = 0; for ($p = 0; $p < strlen($plainText); $p++) { if ($keyPos > strlen($key) - 1) { $keyPos = 0; } $char = $plainText[$p] ^ $key[$keyPos]; $bin = str_pad(decbin(ord($char)), 8, "0", STR_PAD_LEFT); $hex = dechex(bindec($bin)); $hex = str_pad($hex, 2, "0", STR_PAD_LEFT); $output .= strtoupper($hex); $keyPos++; } return $output; }
The decrypt function also takes two strings, the encrypted message (in form of a string of hexadecimal values), and the key. First of we split the encrypted message into an array of two digit hexadecimal values. We then loop over this array. For each position in the array we convert the hexadecimal value to a character and XOR it with the corresponding character in the key. The character is then appended to a string, which is what we will return afterwards.
function decrypt(string $encryptedText, string $key) : string { $hex_arr = explode(" ", trim(chunk_split($encryptedText, 2, " "))); $output = ""; $keyPos = 0; for ($p = 0; $p < sizeof($hex_arr); $p++) { if ($keyPos > strlen($key) - 1) { $keyPos = 0; } $char = chr(hexdec($hex_arr[$p])) ^ $key[$keyPos]; $output .= $char; $keyPos++; } return $output; }
To increase the complexity of this code you can iterate over the encryption and decryption functions a few times. As long as you make sure to use the same key and the same number of iterations when encrypting and decrypting you will get the correct result. I also prefer to return a base64 encoded string when encrypting in case the encrypted string has some characters that doesn’t convert well. If you use the base64 method, don’t forget to decode it before decrypting the message.
You can download the demo code from github.
Featured image by Pete Linforth from Pixabay
Jimmie is a full stack developer with over 13 years working experience in building web based solutions and over 25 years of programming experience over all.
Jimmie has worked with a slew programming languages over the years, but his main focus is usually on web frameworks such as Symfony, Angular, and Spring Boot.