Playfair Cipher Decryption

C code to decrypt a string encoded using the Playfair cipher

Ruthu S Sanketh
Towards Data Science

--

If you haven’t read this article on Playfair Encryption, go take a look first! It has a brief on the Playfair cipher as well as the logic behind most of the code.

Contents

  1. The Playfair Cipher
  2. Rules for Decryption
  3. C Implementation
  4. Outputs for Some Ciphertexts
  5. Further Reading
Photo by iMattSmart on Unsplash
Photo by iMattSmart on Unsplash

The Playfair Cipher

Assuming the keyword is ‘Charles’, the decryption procedure would be as follows. A 5x5 matrix is drawn, and letters are filled in each cell, starting with the keyword, followed by the letters in the alphabet. I/J are filled in the same cell. All repeating letters are removed, giving us this matrix -

Image by author -Playfair matrix for keyword Charles
Image by author -Playfair matrix for the keyword ‘Charles

Given a ciphertext sentence, it is split into digrams. For the ciphertext ‘gddogdrqprsdhmembv’, the digrams would be -

gd do gd rq pr sd hm em bv

Rules for Decryption

  1. Two ciphertext letters in the same row of the matrix are each replaced by the letter to the left, with the last element of the row circularly following the first.

sd would be replaced by eb

gi would be replaced by ng

2. Two ciphertext letters that fall in the same column of the matrix are replaced by the letters above, with the bottom element of the column circularly following the top.

my would be replaced by dt

yr would be replaced by ty

3. Otherwise, each ciphertext letter in a pair is replaced by the letter that lies in its own row and the column occupied by the other ciphertext letter.

gd would be replaced by me

do would be replaced by et

Following these rules, the plaintext becomes ‘Meet me at the bridge’ (x is neglected at the end since its a filler letter).

C Implementation

First we import the required libraries and define a large enough size for allocation of the ciphertext to be decrypted.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100

Now we write a function to decrypt a ciphertext using the Playfair cipher. The string is converted to lower case and the 5x5 key square is generated. For this, first a 26 character hashmap is used to store the count of each alphabet in the key string. Using this, each cell in the matrix is populated with the key string alphabets first, and only once by reducing the count in the hashmap. Then the remaining alphabets are populated.

Each character in the ciphertext is then searched for in the digraph and its position is found. Based on the relative positions of characters in a pair, following the above detailed rules, decryption is performed, and the decrypted pair is returned. Once the digrams are joined, a sentence can be made by looking at the letters and neglecting filler letters like x, etc.

The main difference between the encryption and decryption implementation are the corner cases; when alphabets are in the first row or first column. In the encryption case, alphabets in the last row or last column had to be replaced by those in the first, and this code was taken care of by a modulus 5 operation. However, for decryption, separate if clauses have to be written for these corner cases.

// Function to decrypt using the Playfair Cipher
void PlayfairDeCrypt(char str[], char keystr[])
{
char ps, ks, keyT[5][5];

// Key
ks = strlen(keystr);
// ciphertext
ps = strlen(str);

// Convert all the characters of a string to lowercase
// Can also use the library function toLower here, but a function was written for better understanding of ascii values.
void toLowerCase(char plain[], int ps)
{
int i;
for (i = 0; i < ps; i++) {
if (plain[i] > 64 && plain[i] < 91)
plain[i] += 32;
}
}


// generates the 5x5 key square
void generateKeyTable(char keystr[], int ks,
char keyT[5][5])
{
int i, j, k, flag = 0, *dicty;

// a 26 character hashmap to store count of the alphabet
dicty = (int*)calloc(26, sizeof(int));

for (i = 0; i < ks; i++) {
if (keystr[i] != 'j')
dicty[keystr[i] - 97] = 2;
}
dicty['j' - 97] = 1;

i = 0;
j = 0;
for (k = 0; k < ks; k++) {
if (dicty[keystr[k] - 97] == 2) {
dicty[keystr[k] - 97] -= 1;
keyT[i][j] = keystr[k];
j++;
if (j == 5) {
i++;
j = 0;
}
}
}
for (k = 0; k < 26; k++) {
if (dicty[k] == 0) {
keyT[i][j] = (char)(k + 97);
j++;
if (j == 5) {
i++;
j = 0;
}
}
}
}

// Search for the characters of a digraph in the key square and return their position
void search(char keyT[5][5], char a, char b, int arr[])
{
int i, j;

if (a == 'j')
a = 'i';
else if (b == 'j')
b = 'i';

for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
if (keyT[i][j] == a) {
arr[0] = i;
arr[1] = j;
}
else if (keyT[i][j] == b) {
arr[2] = i;
arr[3] = j;
}
}
}
}

// Function to decrypt
void decrypt(char str[], char keyT[5][5], int ps)
{
int i, a[4];
for (i = 0; i < ps; i += 2) {
search(keyT, str[i], str[i + 1], a);
if (a[0] == a[2]) {
if(a[1]==0){
str[i] = keyT[a[0]][4];
str[i + 1] = keyT[a[0]][(a[3]-1)%5];
}
else if(a[3]==0){
str[i] = keyT[a[0]][(a[1] - 1)%5];
str[i + 1] = keyT[a[0]][4];
}
else{
str[i] = keyT[a[0]][(a[1] - 1)%5];
str[i + 1] = keyT[a[0]][(a[3]-1)%5];
}

}
else if (a[1] == a[3]) {
if(a[0]==0){
str[i] = keyT[4][a[1]];
str[i + 1] = keyT[(a[2]-1)%5[a[1]];
}
else if(a[2]==0){
str[i] = keyT[(a[0] - 1)%5][a[1]];
str[i + 1] = keyT[4][a[1]];
}
else{
str[i] = keyT[(a[0] - 1)%5][a[1]];
str[i + 1] = keyT[(a[2]-1)%5][a[1]];
}
}
else {
str[i] = keyT[a[0]][a[3]];
str[i + 1] = keyT[a[2]][a[1]];
}
}
}
ks = removeSpaces(keystr, ks);
toLowerCase(str, ps);
ps = removeSpaces(str, ps);
generateKeyTable(keystr, ks, keyT);
decrypt(str, keyT, ps);

//plain text printed in lower case letters
printf("Plain text: %s\n", str);
}

The driver code just takes the input key string and input ciphertext, and calls the PlayfairDeCrypt function which outputs the decrypted string.

// Driver code
int main()
{
char str[SIZE], keystr[SIZE];

//Key used - to be enered in lower case letters
printf("Enter the key: ");
scanf("%[^\n]s", &keystr);
printf("Key text: %s\n", keystr);


printf("Enter the ciphertext: ");
scanf("\n");
scanf("%[^\n]s", &str);
printf("Cipher text: %s\n", str);

//Calling the PlayfairDeCrypt function
PlayfairDeCrypt(str, keystr);

return 0;
}

Outputs for Some Ciphertexts

The above code is compiled, run and tested for some ciphertexts using a key string ‘diskjockey’.

  1. RBIABDIGTPSZ
  2. REBSLUMNGYXYNBLFCR
  3. QTBPCPSCDZLXYBQTDMYIKDTKUFGEQDSIYEITBQGYGDGAKW
Image by author -Outputs for some ciphertexts using the C code for Playfair Decryption

The entire code used and explained in this article can be found here.

Further Reading

  1. Project -Implementation of the Encoding and Decoding of the Playfair Cipher
  2. Erin Baldwin -An Essay on the Playfair Cipher
  3. Pal, Ramani, Iyengar, Sunitha. A Variation in the Working of the Playfair Cipher

--

--