📜  对单字母替换密码执行字母频率攻击的程序

📅  最后修改于: 2022-05-13 01:57:06.899000             🧑  作者: Mango

对单字母替换密码执行字母频率攻击的程序

给定一个大小为N的字符串S代表一个单字母密码,任务是打印可以使用字母频率攻击从给定单字母密码解密的前五个可能的纯文本。

例子:

方法:可以根据以下观察解决问题:

  1. 频率分析是已知的密文攻击之一。它基于对密文中字母或字母组的频率的研究。在所有语言中,不同的字母以不同的频率使用。
  2. 频率阵列攻击是基于观察到,在英文文本中,并非所有字母都以相同的频率出现。
  3. 在给定的问题中,字符串T = “ETAOINSHRDLCUMWFGYPBVKJXQZ”用于解密。
  4. 因此,想法是找到给定字符串中第 i最大出现字母与字符串T之间的差异,然后将给定字符串的所有字母与该差异一起移动。获得的字符串将是可能的解密字符串之一。

请按照以下步骤解决问题:

  • 将字符串T初始化为“ETAOINSHRDLCUMWFGYPBVKJXQZ”。
  • 找出字符串S中每个字符的频率,并将其存储在一个变量中,比如freq[]。
  • 使用变量i迭代范围[0, 5]并执行以下步骤:
    • 在字符串S中找到第i出现次数最多的元素并将其存储在变量中,例如ch
    • 找出字符串T的第ch第 i字符之间的差异,并将其存储在一个变量中,比如x
    • 遍历字符串S 的字符,字符所有字符移动x ,然后将得到的字符串压入数组plaintext[]。
  • 最后,经过以上步骤,将数组plaintext[]中得到的字符串打印出来。

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
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());
 
    // 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


输出
A SIMPLE MESSAGE
B TJNQMF NFTTBHF
A SIMPLE MESSAGE
C UKORNG OGUUCIG
C UKORNG OGUUCIG

时间复杂度: O(N)
辅助空间: O(N)