The Vigenère cipher dates from the sixteenth century, and resisted deciphering for three centuries. In Part One we look at this ancient cipher, build a data model to represent Vigenère square and use it to display a version in the browser.
A brief history
The Vigenère cipher was first described in 1563 by Giovan Battista Bellaso. It is easy to understand and implement, but resisted attempts to break it until 1863 when Friedrich Kasiski published the first general method for decipering it. In the 19th century the cipher was mistakenly attributed to Blaise de Vigenère, from which it gets ts current name (source:Wikipedia)
How it works
A Caesar cipher consistes of a an alphabet shifted a certain number of places to left or right. Each letter in a message is replaced by its counterpart in the shifted. alphabet. This simple cipher is vulnerable to a frequency analysis, where the number of occurrences of each letter is counted and compared with the known frequency of letters on the source language. This quickly gives a structure to the cipher, from which the meaning can be derived.
The Vigenère cipher uses a table of alphabets, each rotated by one letter, and successive letters are chosen from differetnt rows (and thus rotated by different amounts). The rows used, and the order they are selected depends on a keyword that must be known to both parties. This change in rotation between letters effectively defeats a simple frequency analysis.
A Vigenère square
Here we see an example of a Vigenère square. To save space, this example works with just six letters. We can see that the rows in the body of the table are rotated left by one character with respect to the row above.
The code
The Vigenère square is essentiall a two dimensional array, with the keyword letters down the side, and the cipher letters across each row. If we use an associative array in each direction it will make using the table very straightforward. The structure will look like this:
$table = ['A':['A':'A', 'B':'B','C':'C'...],
'B':['A':'B', 'B':'C','C':'D'...],
...];
We could just code an array, but that limits the use to the characters we define. It would be more flexible to allow someone using our code to define their own alphabet, so we're going to need some code to create the array from that. We'll also need some code to enchiper and decipher messages, and it would be useful to add a couple of functions to produce some printed versions of the square.
Wrapping this in a class will allow us to encapsulate all the code in a way that doesn't interfere with other scripts. The outline of our class is thus
class Vigenere {
constructor($alphabet, $keyword) {
// construct the 2D array here.
}
getTextSquare(){
// return a text representation of the square
}
getHTMLSquare(){
// return a square in HTML that can be formatted with CSS
}
encipher(message){
// Return an enciphered message
}
decipher(message) {
// Decipher and return a message
}
}
See Part 2 for methods for setting the keyword, and enciphering and deciphering messages.
The constructor
The constructor builds the 2D array we'll use later. Since we're working with arrays we need to split the alphabet string into an array, and create a copy that we can rotate to form the rows.
// Break alphabet string into an array
this.alphabet = Array.from(alphabet);
// Create a copy that we can rotate
let cipherAlphabet = Array.from(alphabet);
// Create an empty array to store our square
this.cipher = [];
// Loop through the alphabet array creating a row for each letter
this.alphabet.forEach(el=>{
// combine the original alphabet as keys with the rotating copy as values
//this.cipher[el] = this.array_combine(this.alphabet, cipherAlphabet);
// Rotate the cipher alhpabet
cipherAlphabet.push(cipherAlphabet.shift());
});
// this.cipher now contains aour Vigenere square
A helper method
Note the use of a helper method to create the rows, keyed by the original array, and values from the rotated one. This is similar to the PHP array_combine()
function, hence the name.
// Return a new array where the keys are taken from
// the first array, and the values from the second
array_combine(a,b) {
let result = [];
a.forEach((el,ix)=>{
result[el] = b[ix];
});
return result;
}
Getting a text square
To create the square we need a heading that we can get from this.alphabet
, followed by a series of roes that we get by iterating over this.cipher
. We can use Array.join()
to combine the arrays into strings and add some whitespace.
getTextSquare(){
// Form the top row by joining the original alphabet with some whitespace
let square = " | "+this.alphabet.join(' ')+"\n";
// Create a horizontal line by repeating '---'
square += "--|"+'---'.repeat(this.alphabet.length)+"\n";
// Create the body of the square by iterating over the keys and joining the
// array returned by each key with whitespace
Object.keys(this.cipher).forEach(el=>{
square += el + " | "+Object.values(this.cipher[el]).join(' ')+"\n";
});
return square;
}
Getting an HTML square
Returning an HTML square is essntially he same opration as returning a text square, but with a little more text to include the HTML element tags.
getHTMLsquare(){
let square = "<table><thead>";
square += "<tr><td> </td><td>"+this.alphabet.join('</td><td>')+"</td></tr>\n";
square += "</thead><tbody>";
Object.keys(this.cipher).forEach(el=>{
square += `<tr><th>${el}</th><td>` +
Object.values(this.cipher[el]).join('</td><td>')+"</td></tr>\n";
});
square += "</tbody></table>";
return square;
}
The class so far
Put these elements together, and add some code to handle a bad argument passed to the constructor and we get
class Vigenere {
// Helper method: return a new array where the keys are taken from
// the first array, and the values from the second
array_combine(a,b) {
let result = [];
a.forEach((el,ix)=>{
result[el] = b[ix];
});
return result;
}
/**
* The constructor
*/
constructor(alphabet) {
// Check that we have been provided with a string
if ((typeof alphabet !== 'string') || alphabet.length === 0) {
throw "Invalid alphabet - must be a string";
}
// Break alphabet string into an array
this.alphabet = Array.from(alphabet);
// Create a copy that we can rotate
let cipherAlphabet = Array.from(alphabet);
// Create an empty array to store our square
this.cipher = [];
// Loop through the alphabet array creating a row for each letter
this.alphabet.forEach(el=>{
// combine the original alphabet as keys with the rotating copy as values
this.cipher[el] = this.array_combine(this.alphabet, cipherAlphabet);
// Rotate the cipher alphabet
cipherAlphabet.push(cipherAlphabet.shift());
});
// The variable this.cipher now contains our Vigenere square
}
/**
* read the cipher square and return a text representation
*/
getTextSquare(){
// Form the top row by joining the original alphabet with some whitespace
let square = " | "+this.alphabet.join(' ')+"\n";
// Create a horizontal line by repeating '---'
square += "--|"+'---'.repeat(this.alphabet.length)+"\n";
// Create the body of the square by iterating over the keys and joining the
// array returned by each key with whitespace
Object.keys(this.cipher).forEach(el=>{
square += el + " | "+Object.values(this.cipher[el]).join(' ')+"\n";
});
return square;
}
/**
* Read the cipher square and return an HTML version
*/
getHTMLsquare(){
let square = "<table><thead>";
square += "<tr><td> </td><td>"+this.alphabet.join('</td><td>')+"</td></tr>\n";
square += "</thead><tbody>";
Object.keys(this.cipher).forEach(el=>{
square += `<tr><th>${el}</th><td>` +
Object.values(this.cipher[el]).join('</td><td>')+"</td></tr>\n";
});
square += "</tbody></table>";
return square;
}
}
Using the class
Using the class is simply a matter if instantiating it and calling the required methods:
<div id="squareDiv"></div>
<script src="/vigenere.js"></script>
<script>
let cipher = new Vigenere("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
let square = cipher.getHTMLSquare();
document.getElementById('squareDiv').innerHTML = square;
</script>
That completes part one of this look at the Vigenère cipher. Check out Part Two for enciphering and deciphering messages, and the completion of our JavaScript class.