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

19 Dec, 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:
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.The frequency array attack is based on the observation that in an English text, not all letters occur with the same frequency.In the given problem, the string, T = “ETAOINSHRDLCUMWFGYPBVKJXQZ” is used for deciphering.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. 
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.
The frequency array attack is based on the observation that in an English text, not all letters occur with the same frequency.
In the given problem, the string, T = “ETAOINSHRDLCUMWFGYPBVKJXQZ” is used for deciphering.
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[].
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++
Java
Python3
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 attackvoid 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 concatenating    // 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>());     // Iterate 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 Codeint main(){    // Given string    string S = "B TJNQMF NFTTBHF";    int N = S.length();     // Function Call    printString(S, N);     return 0;}
// Java program for the above approachimport java.util.*; class GFG{ // Function to decrypt a monoalphabetic// substitution cipher using the letter// frequency attackstatic 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 concatenating    // 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);    // Iterate 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 Codepublic 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 program for the above approach # Function to decrypt a monoalphabetic# substitution cipher using the letter# frequency attackdef 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    # concatenating the english letters    # in the decreasing frequency in the    # english language        T = "ETAOINSHRDLCUMWFGYPBVKJXQZ"         # Sort the array in descending order    freqSorted.sort(reverse = True)         # Iterate 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 stringS = "B TJNQMF NFTTBHF"N = len(S) # Function CallprintString(S, N) # This code is contributed by Parth Manchanda
// C# program for the above approachusing System; public class GFG{ // Function to decrypt a monoalphabetic// substitution cipher using the letter// frequency attackstatic 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 concatenating    // 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);    // Iterate 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 Codepublic 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
A SIMPLE MESSAGE
B TJNQMF NFTTBHF
A SIMPLE MESSAGE
C UKORNG OGUUCIG
C UKORNG OGUUCIG
Time Complexity: O(N)Auxiliary Space: O(N)
parthmanchanda81
princi singh
shikhasingrajput
gulshankumarar231
akshaysingh98088
Arrays
cpp-string
encoding-decoding
frequency-counting
Strings
Arrays
Strings
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.