Last part of my series about Vigenere cipher. (3 post in a row? I am proud of myself :-P)

In my previous posts I already showed how to use Vigenere square to encrypt/decrypt text, so this time I'll follow the algebraic method described in the Wikipedia:

I'll use the same input, same key, and same alphabets as in previous exercises:

mykey: "WHITE" input_text: "en un lugar dela mancha de cuyo nombre no quiero acordarme" Position: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Ref alphabet(M): A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Key alphabet(K): B C D E F G H I J K L M N O P Q R S T U V W X Y Z A

(In the reference alphabet,we have shifted the letters one position, as the author did in the book, so K alphabet starts in "B" not in "A"

## Encryption:

Now we are going to use numbers instead of the square approach.

If you remember the first post, the foundation of this cipher is the tuple (letter,key):

INPUT: EN UN LUGAR DE LA MANCHA KEY: WH IT EWHIT EW HI TEWHIT TUPLE: ('E', 'W'),('N', 'H'),('U', 'I'),('N', 'T'), ('L', 'E'),('U', 'W'),[...]

Let's get the positions of each element in the tuple in M[] and K[]:

*1st tuple:* 'E' is in position 4 in our reference alphabet(M). 'W' is in position 21 in the Key alphabet(K)

*2nd tuple:* 'N' is in position 13 in M[], 'H' is in position 6 in K[]

*3rd tuple:* 'U' is in position 20 in M[], 'I' is in position 7 in K[]

```
('4','21'),('13','6'),('20','7'),('13','18'),[...]
```

So putting this in the mathematical notation:

*C[i] = (M[i]+K[i]) mod len(M)*

C[0] = (4 + 21) % 26 = 25 C[1] = (13 + 6) % 26 = 19 C[2] = (20 + 7) % 26 = 1 [...]

So the letter "E" in position 4 in M[] will be replaced by the letter in position 25 in K[], which is "A". The same way, the letter "N" in position 13 in M[] will be replaced by the letter in position 19 in K[], which is "U", and so on...

E -> K[25] ->A N -> K[19] ->U U -> K[1] ->C N -> K[5] ->G L -> K[14] ->P U -> K[15] ->Q G -> K[12] ->N [...]

## Decryption:

Decryption works pretty much the same way... The message is calculated this way:

*M[i] = (C[i]-K[i]) mod len(M)*

Let's check step by step.. This is our input data:

INPUT: AU CG PQNIK HA SI FEJJPT KEY: WH IT EWHIT EW HI TEWHIT TUPLE: ('A', 'W'),('U', 'H'),('C', 'I'),('G', 'T'), ('P', 'E'),('Q', 'W'),('N', 'H'),('I', 'I'),('K', 'T'),('H', 'E'),[...]

We have to look for the positon of the each letter (of each tuple) in alphabet K[]:

*1st tuple:* Position of letter "A" and "W" in K[], 25 and 21.

*2nd tuple:* Position of letter "U" and "H" in K[], 19 and 6.

*3rd tuple:* C,I -> 1, 7

Now, coming back to the formula:

M[0] = (C[0]-K[0]) mod len(M) = (25 - 21) % 26 = 4 M[1] = (C[1]-K[1]) mod len(M) = (19 - 6) % 26 = 13 M[2] = (C[2]-K[2]) mod len(M) = (1 - 7) % 26 = 20 M[3] = (C[3]-K[3]) mod len(M) = (5 - 18) % 26 = 13

And looking for those positions in our reference alphabet M[]:

A -> M[4] -> E U -> M[13] -> N C -> M[20] -> U G -> M[13] -> N P -> M[11] -> L Q -> M[20] -> U N -> M[6] -> G I -> M[0] -> A K -> M[17] -> R [...]

Let put this into python code:

#!/usr/bin/env python import string mykey="WHITE" input_text="en un lugar de la mancha de cuyo nombre no quiero acordarme" code_text="AU CG PQNIK HA SI FEJJPT HA JCRS JVUUVA UW JYELZH EYVZWENTM" # Alphabet used as reference (M) # ABCDEFGHIJKLMNOPQRSTUVWXYZ source = string.ascii_uppercase # Key alphabet (K) shifted 1 position to the left # BCDEFGHIJKLMNOPQRSTUVWXYZA shift = 1 matrix = [ source[(i + shift) % 26] for i in range(len(source)) ] def coder(thistext): ciphertext = [] control = 0 for x,i in enumerate(input_text.upper()): if i not in source: #If the symbol is not in our reference alphabet, we simply print it ciphertext.append(i) continue else: #Wrap around the mykey string control = 0 if control % len(mykey) == 0 else control #Calculate the position C[i] = (M[i]+K[i]) mod len(M) result = (source.find(i) + matrix.index(mykey[control])) % 26 #Add the symbol in position "result" to be printed later ciphertext.append(matrix[result]) control += 1 return ciphertext def decoder(thistext): control = 0 plaintext = [] for x,i in enumerate(code_text.upper()): if i not in source: #If the symbol is not in our reference alphabet, we simply print it plaintext.append(i) continue else: #Wrap around the mykey string control = 0 if control % len(mykey) == 0 else control #Calculate the position M[i] = (C[i]-K[i]) mod len(M) result = (matrix.index(i) - matrix.index(mykey[control])) % 26 #Add the symbol in position "result" to be printed later plaintext.append(source[result]) control += 1 return plaintext # Print results print("Key: {0}".format(mykey)) print("\nDecode text:") print("-> Input text: {0}".format(input_text)) print("-> Coded text: {0}".format(''.join(coder(input_text)))) # Print results print("\nDecode text:") print("-> Input text: {0}".format(code_text)) print("-> Decoded text: {0}".format(''.join(decoder(code_text)).lower()))

Code stored in GitHub

The script is pretty basic and simple to understand. There are two functions, and the key part is the calculation of *result* using the math formula shown above.

And see the result:

$ python Vigenere_cipher_mod.py Key: WHITE Decode text: -> Input text: en un lugar de la mancha de cuyo nombre no quiero acordarme -> Coded text: AU CG PQNIK HA SI FEJJPT HA JCRS JVUUVA UW JYELZH EYVZWENTM Decode text: -> Input text: AU CG PQNIK HA SI FEJJPT HA JCRS JVUUVA UW JYELZH EYVZWENTM -> Decoded text: en un lugar de la mancha de cuyo nombre no quiero acordarme

There are tons of references about how to break this code on the internet. I found these two very interesting:

Later

PS: I hate markdown. Just a little bit...