对单字母替换密码执行字母频率攻击的程序
给定一个大小为N的字符串S代表一个单字母密码,任务是打印可以使用字母频率攻击从给定单字母密码解密的前五个可能的纯文本。
例子:
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
方法:可以根据以下观察解决问题:
- 频率分析是已知的密文攻击之一。它基于对密文中字母或字母组的频率的研究。在所有语言中,不同的字母以不同的频率使用。
- 频率阵列攻击是基于观察到,在英文文本中,并非所有字母都以相同的频率出现。
- 在给定的问题中,字符串T = “ETAOINSHRDLCUMWFGYPBVKJXQZ”用于解密。
- 因此,想法是找到给定字符串中第 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)