Basic cryptography – the Caesar cipher

One of the first cryptographic systems I ever learned was the Caesar cipher. It’s one you’ve probably used as well. Unlike more sophisticated ciphers, Caesar uses a fixed shift of characters in the alphabet.

Your key is effectively the number of letters to shift to the left. A key of 1 means to shift every character one position to the left. A becomes Z. B becomes A. C becomes B. Rinse and repeat.

One of the most famous Caesar shifts is the much mocked rot13() function where every character is replaced by one exactly 13 characters away. This particular shift is mocked because the function is an inversion of itself – apply things twice and you end up with the original input.

With a traditional Caesar cipher, you encrypt with an integer key and decrypt with that key subtracted from 26. It’s a quick operation and sufficiently obscures the original message.

Implementing the Caesar cipher in PHP

If you are using a shift of 13, the easiest implementation in PHP is the native str_rot13() function that ships with core. Unfortunately, that’s not very extensible and, if you use a shift of 13, everyone will start there to crack your message.

Instead, we want to build a more generic rotation algorithm that can adequately replace each character in a given string with its complement post shift. The following function (derived heavily from an example in the PHP documentation) does exactly that by:

  • Creating a static array of candidate letters
  • Leveraging PHP’s strtr() string translation function to replace characters in-place
function rotate(string $str, int $shift, string $direction = 'right'): string
{
    $letters = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz';
    $shift = abs($shift % 26);

    if ($direction === 'right') $shift = abs($shift - 26);

    if ($shift === 0) {
      return $str;
    } else if ($shift === 13) {
      return str_rot13($str);
    }

    $transform = substr($letters, $shift * 2) . substr($letters, 0, $shift * 2);
    return strtr($str, $letters, $transform);
}

Now, armed with a translation function, we can implement encryption and decryption interfaces for the Caesar cipher:

function caesar_encrypt(string $message, int $key): string
{
  return rotate($message, $key, 'left');
}

function caesar_decrypt(string $message, int $key): string
{
  return rotate($message, $key, 'right');
}

Don’t do this at home

Implementing ciphers is a fun hobby but please do not use this for anything critical! The Caesar cipher is incredibly easy to crack as there are only 26 possible keys. Decrypting a message through brute force is child’s play.

For now, rest assured that knowing how to implement a Caesar cipher is a critical stepping stone to more advanced cryptography. It’s also a fun exercise for coders trying to brush the rust off their algorithm skills.