The elves have taken cybersecurity seriously. Like any fashion, it has also reached children. One of the little elves’ favorite games is writing encrypted messages during school hours. Some of them found the page on the Caesar cipher on Wikipedia and now they don’t stop it anymore.
The Puzzle: Secret Messages ✉️
Today’s problem, issue 22 of the Dev Advent Calendar 🎅 is once again about the passwords, the codes and the methods to decipher them. And we go to the classic: Caesar’s cipher:
In cryptography, a Caesar cipher, also known as Caesar's cipher, the shift cipher, Caesar's code or Caesar shift, is one of the simplest and most widely known encryption techniques. It is a type of substitution cipher in which each letter in the plaintext is replaced by a letter some fixed number of positions down the alphabet.
Put simply, we replace each letter with the one that follows it in
x positions. For example, with
shift = 1 the letter
shift = 2 the letter
shift = 3 the letter
D. And so on.
There are several solutions on the internet but almost all of them involve explicit writing of the alphabet plus some
if conditions combined with
for loops. My solution to the problem is different and starts from the formula
f(x) = x + k(mod. m)
m = number of letters of the alphabet and
k = shift.
The problem is figuring out how to pass the letters. The most common method involves converting the character into the corresponding numeric code. Then we add the shift and convert it back to characters.
First I create two arrays, one for uppercase letters, the other for lowercase ones:
Then I need a function to calculate the modulus of a number:
Finally something that creates a match between the key and the solution.
This function accepts an array containing the alphabet as input and returns an object with the encryption code.
For each item in the array, for each letter of the alphabet, it calculates the corresponding encrypted letter. The length of the alphabet is given by the number of elements in the array.
To simplify the resolution I create a helper function to handle the dictionary of both uppercase and lowercase letters.
This way I get an object like this:
After getting the cipher I can translate each letter:
We can also ignore all non-alphabetic characters in a very simple way: if the matching key does not exist in the cipher then the character is not converted:
After creating all the various support functions the solution is short and simple:
There is an interesting aspect to this solution: the same function used to decrypt can also be used to decrypt. Just use a negative shift: in this way the letters are not scrolled forward but backwards allowing you to recover the original message.
This is the complete code:
Prashant Yadav’s solution
As I said at the beginning, there are many solutions to this problem online. Prashant Yadav proposes some of the most common.
What are the problems with this approach?
- this code only encrypts with a predefined shift (in this case of 13)
- only works for lowercase letters
- only works with strings that do not contain spaces or other characters not contained in the
- does not decrypt the message
His second idea is more interesting:
This function converts all letters to uppercase and then replaces them. There remains the problem of handling lowercase letters. To do this, you need to change the function:
The management of non-alphabetic characters, including spaces, remains problematic.
Marian Veteanu’s solution
Marian Veteanu’s blog has many interesting posts. There is a solution to how to create a Caesar cipher
This solution works, but I don’t like having so many hard-coded values. But it has the advantage of not using arrays or other objects. Like the next solution.
Evan Hahn’s solution
Evan Hahn proposes a working solution:
However, this solution presents some problems. Or, rather, some things I don’t like. The first is the presence of several
if conditions and a
for loop. I am increasingly convinced that they make it difficult to read the code and difficult to maintain.
Secondly, the alphabet to work on is fixed in the code by hard-coded values. Where possible it is always best to avoid entering hard-coded values. Finally if I wanted to convert this function to use another character set I would run into trouble.
But the code works.