Skip to content
Related Articles

Related Articles

Improve Article

Program to perform a letter frequency attack on a monoalphabetic substitution cipher

  • Last Updated : 10 Aug, 2021

Given a string S of size N representing a monoalphabetic cipher, the task is to print the top five possible plain texts that can be decrypted from the given monoalphabetic cipher using a letter frequency attack.

Examples:

Input: S = “ETAOINSHRDLCUMWFGYPBVKJXQZ”
Output: A SIMPLE MESSAGE
              B TJNQMF NFTTBHF
             A SIMPLE MESSAGE
             C UKORNG OGUUCIG
             C UKORNG OGUUCIG

Input: S = “ABCDEFGH”
Output: W OEILHA IAOOWCA
              J BRVYUN VNBBJPN
             C UKORNG OGUUCIG
             R JZDGCV DVJJRXV
             Y QGKNJC KCQQYEC

Approach: The problem can be solved based on the following observations:



  1. Frequency analysis is one of the known ciphertext attacks. It is based on the study of the frequency of letters or groups of letters in a ciphertext. In all languages, different letters are used with different frequencies.
  2. The frequency array attack is based on the observation that in an English text, not all letters occur with the same frequency.
  3. In the given problem, the string, T = “ETAOINSHRDLCUMWFGYPBVKJXQZ” is used for deciphering.
  4. Therefore, the idea is to find the difference between ith maximum occurring letter in the given string and the string T and then shift all the letters of the given string with that difference. The string obtained will be one of the possible decrypted strings.
     

Follow the steps below to solve the problem:

  • Initialize a string say T as “ETAOINSHRDLCUMWFGYPBVKJXQZ”.
  • Find the frequency of each character of the string S, and store it in a variable, say freq[].
  • Iterate over the range [0, 5] using the variable i and perform the following steps:
    • Find the ith most occurring element in the string S and store it in a variable, say ch.
    • Find the difference between the ch and ith character of the string T and store it in a variable, say x.
    • Iterate over the characters of string S, and shift all characters by x and then push the obtained string into an array plaintext[].
  • Finally, after the above steps, print the strings obtained in the array plaintext[].

Below is the implementation of the above approach:

C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to decrypt a monoalphabetic
// substitution cipher using the letter
// frequency attack
void printString(string S, int N)
{
 
    // Stores final 5 possible deciphered
    // plaintext
    string plaintext[5];
 
    // Store the frequency of each letter in
    // cipher text
    int freq[26] = { 0 };
 
    // Stores the frequency of each letter
    // in cipher text in descending order
    int freqSorted[26];
 
    // Store which alphabet is used already
    int Used[26] = { 0 };
 
    // Traverse the string S
    for (int i = 0; i < N; i++) {
        if (S[i] != ' ') {
            freq[S[i] - 'A']++;
        }
    }
 
    // Copy the frequency array
    for (int i = 0; i < 26; i++) {
        freqSorted[i] = freq[i];
    }
 
    // Stores the string formed from concatanating
    // the english letters in the decreasing frequency
    // in the english language
    string T = "ETAOINSHRDLCUMWFGYPBVKJXQZ";
 
    // Sort the array in descending order
    sort(freqSorted, freqSorted + 26, greater<int>());
 
    // Itearate over the range [0, 5]
    for (int i = 0; i < 5; i++) {
 
        int ch = -1;
 
        // Iterate over the range [0, 26]
        for (int j = 0; j < 26; j++) {
 
            if (freqSorted[i] == freq[j] && Used[j] == 0) {
                Used[j] = 1;
                ch = j;
                break;
            }
        }
        if (ch == -1)
            break;
 
        // Store the numerical equivalent of letter at
        // ith index of array letter_frequency
        int x = T[i] - 'A';
 
        // Calculate the probable shift used
        // in monoalphabetic cipher
        x = x - ch;
 
        // Temporary string to generate one
        // plaintext at a time
        string curr = "";
 
        // Generate the probable ith plaintext
        // string using the shift calculated above
        for (int k = 0; k < N; k++) {
 
            // Insert whitespaces as it is
            if (S[k] == ' ') {
                curr += ' ';
                continue;
            }
 
            // Shift the kth letter of the
            // cipher by x
            int y = S[k] - 'A';
            y += x;
 
            if (y < 0)
                y += 26;
            if (y > 25)
                y -= 26;
 
            // Add the kth calculated/shifted
            // letter to temporary string
            curr += 'A' + y;
        }
 
        plaintext[i] = curr;
    }
 
    // Print the generated 5 possible plaintexts
    for (int i = 0; i < 5; i++) {
        cout << plaintext[i] << endl;
    }
}
 
// Driver Code
int main()
{
    // Given string
    string S = "B TJNQMF NFTTBHF";
    int N = S.length();
 
    // Function Call
    printString(S, N);
 
    return 0;
}

Java




// Java program for the above approach
import java.util.*;
 
class GFG{
 
// Function to decrypt a monoalphabetic
// substitution cipher using the letter
// frequency attack
static void printString(String S, int N)
{
 
    // Stores final 5 possible deciphered
    // plaintext
    String []plaintext = new String[5];
 
    // Store the frequency of each letter in
    // cipher text
    int freq[] = new int[26];
 
    // Stores the frequency of each letter
    // in cipher text in descending order
    int freqSorted[] = new int[26];
 
    // Store which alphabet is used already
    int Used[] = new int[26];
 
    // Traverse the String S
    for (int i = 0; i < N; i++) {
        if (S.charAt(i) != ' ') {
            freq[S.charAt(i) - 'A']++;
        }
    }
 
    // Copy the frequency array
    for (int i = 0; i < 26; i++) {
        freqSorted[i] = freq[i];
    }
 
    // Stores the String formed from concatanating
    // the english letters in the decreasing frequency
    // in the english language
    String T = "ETAOINSHRDLCUMWFGYPBVKJXQZ";
 
    // Sort the array in descending order
    Arrays.sort(freqSorted);
    freqSorted= reverse(freqSorted);
    // Itearate over the range [0, 5]
    for (int i = 0; i < 5; i++) {
 
        int ch = -1;
 
        // Iterate over the range [0, 26]
        for (int j = 0; j < 26; j++) {
 
            if (freqSorted[i] == freq[j] && Used[j] == 0) {
                Used[j] = 1;
                ch = j;
                break;
            }
        }
        if (ch == -1)
            break;
 
        // Store the numerical equivalent of letter at
        // ith index of array letter_frequency
        int x = T.charAt(i) - 'A';
         
        // Calculate the probable shift used
        // in monoalphabetic cipher
        x = x - ch;
 
        // Temporary String to generate one
        // plaintext at a time
        String curr = "";
 
        // Generate the probable ith plaintext
        // String using the shift calculated above
        for (int k = 0; k < N; k++) {
 
            // Insert whitespaces as it is
            if (S.charAt(k) == ' ') {
                curr += (char)' ';
                continue;
            }
 
            // Shift the kth letter of the
            // cipher by x
            int y = S.charAt(k) - 'A';
            y += x;
 
            if (y < 0)
                y += 26;
            if (y > 25)
                y -= 26;
 
            // Add the kth calculated/shifted
            // letter to temporary String
            curr += (char)('A' + y);
        }
 
        plaintext[i] = curr;
    }
 
    // Print the generated 5 possible plaintexts
    for (int i = 0; i < 5; i++) {
        System.out.print(plaintext[i] +"\n");
    }
}
static int[] reverse(int a[]) {
    int i, n = a.length, t;
    for (i = 0; i < n / 2; i++) {
        t = a[i];
        a[i] = a[n - i - 1];
        a[n - i - 1] = t;
    }
    return a;
}
// Driver Code
public static void main(String[] args)
{
    // Given String
    String S = "B TJNQMF NFTTBHF";
    int N = S.length();
 
    // Function Call
    printString(S, N);
 
}
}
 
// This code contributed by Princi Singh

Python3




# Python3 program for the above approach
 
# Function to decrypt a monoalphabetic
# substitution cipher using the letter
# frequency attack
def printString(S, N):
     
    # Stores final 5 possible deciphered
    # plaintext
    plaintext = [None] * 5
     
    # Store the frequency of each letter in
    # cipher text
    freq = [0] * 26
     
    # Stores the frequency of each letter
    # in cipher text in descending order
    freqSorted = [None] * 26
     
    # Store which alphabet is used already
    used = [0] * 26
     
    # Traverse the string S
    for i in range(N):
        if S[i] != ' ':
            freq[ord(S[i]) - 65] += 1
             
    # Copy the frequency array        
    for i in range(26):
        freqSorted[i] = freq[i]
         
    # Stores the string formed from
    # concatanating the english letters
    # in the decreasing frequency in the
    # english language    
    T = "ETAOINSHRDLCUMWFGYPBVKJXQZ"
     
    # Sort the array in descending order
    freqSorted.sort(reverse = True)
     
    # Itearate over the range [0, 5]
    for i in range(5):
        ch = -1
         
        # Iterate over the range [0, 26]
        for j in range(26):
            if freqSorted[i] == freq[j] and used[j] == 0:
                used[j] = 1
                ch = j
                break
             
        if ch == -1:
            break
         
        # Store the numerical equivalent of letter
        # at ith index of array letter_frequency
        x = ord(T[i]) - 65
         
        # Calculate the probable shift used
        # in monoalphabetic cipher
        x = x - ch
         
        # Temporary string to generate one
        # plaintext at a time
        curr = ""
         
        # Generate the probable ith plaintext
        # string using the shift calculated above
        for k in range(N):
             
            # Insert whitespaces as it is
            if S[k] == ' ':
                curr += " "
                continue
             
            # Shift the kth letter of the
            # cipher by x
            y = ord(S[k]) - 65
            y += x
             
            if y < 0:
                y += 26
            if y > 25:
                y -= 26
             
            # Add the kth calculated/shifted
            # letter to temporary string    
            curr += chr(y + 65)
             
        plaintext[i] = curr
     
    # Print the generated 5 possible plaintexts    
    for i in range(5):
        print(plaintext[i])
 
# Driver code
 
# Given string
S = "B TJNQMF NFTTBHF"
N = len(S)
 
# Function Call
printString(S, N)
 
# This code is contributed by Parth Manchanda

C#




// C# program for the above approach
using System;
 
public class GFG{
 
// Function to decrypt a monoalphabetic
// substitution cipher using the letter
// frequency attack
static void printString(String S, int N)
{
 
    // Stores readonly 5 possible deciphered
    // plaintext
    String []plaintext = new String[5];
 
    // Store the frequency of each letter in
    // cipher text
    int []freq = new int[26];
 
    // Stores the frequency of each letter
    // in cipher text in descending order
    int []freqSorted = new int[26];
 
    // Store which alphabet is used already
    int []Used = new int[26];
 
    // Traverse the String S
    for (int i = 0; i < N; i++) {
        if (S[i] != ' ') {
            freq[S[i] - 'A']++;
        }
    }
 
    // Copy the frequency array
    for (int i = 0; i < 26; i++) {
        freqSorted[i] = freq[i];
    }
 
    // Stores the String formed from concatanating
    // the english letters in the decreasing frequency
    // in the english language
    String T = "ETAOINSHRDLCUMWFGYPBVKJXQZ";
 
    // Sort the array in descending order
    Array.Sort(freqSorted);
    freqSorted= reverse(freqSorted);
    // Itearate over the range [0, 5]
    for (int i = 0; i < 5; i++) {
 
        int ch = -1;
 
        // Iterate over the range [0, 26]
        for (int j = 0; j < 26; j++) {
 
            if (freqSorted[i] == freq[j] && Used[j] == 0) {
                Used[j] = 1;
                ch = j;
                break;
            }
        }
        if (ch == -1)
            break;
 
        // Store the numerical equivalent of letter at
        // ith index of array letter_frequency
        int x = T[i] - 'A';
         
        // Calculate the probable shift used
        // in monoalphabetic cipher
        x = x - ch;
 
        // Temporary String to generate one
        // plaintext at a time
        String curr = "";
 
        // Generate the probable ith plaintext
        // String using the shift calculated above
        for (int k = 0; k < N; k++) {
 
            // Insert whitespaces as it is
            if (S[k] == ' ') {
                curr += (char)' ';
                continue;
            }
 
            // Shift the kth letter of the
            // cipher by x
            int y = S[k] - 'A';
            y += x;
 
            if (y < 0)
                y += 26;
            if (y > 25)
                y -= 26;
 
            // Add the kth calculated/shifted
            // letter to temporary String
            curr += (char)('A' + y);
        }
 
        plaintext[i] = curr;
    }
 
    // Print the generated 5 possible plaintexts
    for (int i = 0; i < 5; i++) {
        Console.Write(plaintext[i] +"\n");
    }
}
static int[] reverse(int []a) {
    int i, n = a.Length, t;
    for (i = 0; i < n / 2; i++) {
        t = a[i];
        a[i] = a[n - i - 1];
        a[n - i - 1] = t;
    }
    return a;
}
   
// Driver Code
public static void Main(String[] args)
{
    // Given String
    String S = "B TJNQMF NFTTBHF";
    int N = S.Length;
 
    // Function Call
    printString(S, N);
 
}
}
 
// This code is contributed by shikhasingrajput
Output
A SIMPLE MESSAGE
B TJNQMF NFTTBHF
A SIMPLE MESSAGE
C UKORNG OGUUCIG
C UKORNG OGUUCIG

Time Complexity: O(N)
Auxiliary Space: O(N)

 

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :