Program to perform a letter frequency attack on a monoalphabetic substitution cipher
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 OGUUCIGInput: 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.
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 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 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 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 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 # 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 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 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 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 |
Javascript
function printString(S) { // Stores final 5 possible deciphered plaintext var plaintext = new Array(5); // Store the frequency of each letter in cipher text var freq = new Array(26).fill(0); // Stores the frequency of each letter in cipher text in descending order var freqSorted = new Array(26); // Store which alphabet is used already var used = new Array(26).fill(0); // Traverse the string S for ( var i = 0; i < S.length; i++) { if (S[i] !== ' ' ) { freq[S.charCodeAt(i) - 65] += 1; } } // Copy the frequency array for ( var 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 var T = "ETAOINSHRDLCUMWFGYPBVKJXQZ" ; // Sort the array in descending order freqSorted.sort( function (a, b) { return b - a }); // Iterate over the range [0, 5] for ( var i = 0; i < 5; i++) { var ch = -1; // Iterate over the range [0, 26] for ( var 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 var x = T.charCodeAt(i) - 65; // Calculate the probable shift used in monoalphabetic cipher x = x - ch; // Temporary string to generate one plaintext at a time var curr = "" ; // Generate the probable ith plaintext string using the shift calculated above for ( var k = 0; k < S.length; k++) { // Insert whitespaces as it is if (S[k] === ' ' ) { curr += " " ; continue ; } // Shift the kth letter of the cipher by x var y = S.charCodeAt(k) - 65; y += x; if (y < 0) { y += 26; } if (y > 25) { y -= 26; } // Add the kth calculated/shifted letter to temporary string curr += String.fromCharCode(y + 65); } plaintext[i] = curr; } console.log(plaintext); } // This Code is Contributed By Shivam Tiwari |
A SIMPLE MESSAGE B TJNQMF NFTTBHF A SIMPLE MESSAGE C UKORNG OGUUCIG C UKORNG OGUUCIG
Time Complexity: O(N)
Auxiliary Space: O(N)
Please Login to comment...