代替密碼構造
使用加法方式構造一種代替密碼。
五元組(M,C,K,E,D)中各項如下所示:
明文
\[case\]
加密算法:
\[e(x)=x+a (mod 26) \quad a ∈ Z / (26)\]
密鑰:
\[a = 5\]
密文:
\[HFYJ\]
解密算法:
\[x=e(x)-a (mod 26) \quad a ∈ Z / (26)\]
仿射密碼分析
設計思想
仿射密碼由加法密碼和乘法密碼結合構成,由於加法和乘法相互獨立,可以實現更多種類的代替密碼。對於仿射密碼的加密過程\[e(x)=ax+b (mod 26) \quad a, b ∈ Z / (26)\]當且僅當\(gcd(a,26) = 1\)時具有唯一解(即可逆)。其中a的取值為(1,3,5,7,9,11,15,17,19,21,23,25)共12個。
(a取值為1時退化為加法密碼);b取值為0到25,共26種(當b取值為0時退化為乘法密碼)。在\(a = 1, b = 0\)時,相當於未加密。
- 通過C++實現仿射密碼所有的\(26\times12 = 312\)種不同情況的加密過程。
- 通過Matlab對字符頻率進行統計分析。
測試結果
添加一篇英文文檔:Apple appkit 官方文檔
在不同的仿射密碼進行單表代替加密后,不同字母的出現頻率等數據特征出現了明顯的規律性的變化。
結果分析
原文中的各個字母的統計結果:
字母頻數柱狀圖

通過仿射密碼加密后各個字母頻數變化統計
由於字母數量較多,只給出\(A,B,Y,Z\)四個字母的統計結果。
A

B

Y

Z

通過對統計結果的分析,觀察到單表代替密碼(通過模擬,包含了仿射密碼、加法密碼的所有情況)的實現方式是將明文字母表中的每個字母用密文字母表中的相應字母來代替,明密文表字母存在特定且唯一的一一對應關系。
通過統計分析發現,單表代替密碼(仿射密碼)的密文存在明顯的統計規律,同一字母在經過加密算法計算得到新的字母的詞頻特性存在明顯規律。容易受到頻率統計分析攻擊。
附:代碼
加密過程及字母頻率統計
#include <iostream>
#include <cstdio>
#include <string>
#include <fstream>
#include <cerrno>
typedef long long ll;
using namespace std;
string get_file_contents(const char *filename){
std::ifstream in(filename, std::ios::in | std::ios::binary);
if (in){
std::string contents;
in.seekg(0, std::ios::end);
contents.resize(in.tellg());
in.seekg(0, std::ios::beg);
in.read(&contents[0], contents.size());
in.close();
return(contents);
}
throw(errno);
}
int main(int argc, const char * argv[]) {
freopen("cData.txt", "w+", stdout);
string dataRead = get_file_contents(*argv);
string dataM;
ll cCountOfDataM[26] = {0};
ll dataReadLen = dataRead.size();
for(ll i = 0; i < dataReadLen; i++){
if(dataRead[i] >= 'A' && dataRead[i] <= 'Z'){
dataM += (dataRead[i] + 32);
cCountOfDataM[dataRead[i] - 65]++;
}
if(dataRead[i] >= 'a' && dataRead[i] <= 'z'){
dataM += dataRead[i];
cCountOfDataM[dataRead[i] - 97]++;
}
}
for(int i = 0; i < 26; i++){
cout<<cCountOfDataM[i]<<" ";
}
cout<<endl;
//cout<<dataM<<endl;
int keyA[] = {1,3,5,7,9,11,15,17,19,21,23,25};
for(int a = 0; a < 12; a++){
for(int b = 0; b < 26; b++){
string dataC;
ll cCountOfDataC[26] = {0};
for(ll i = 0; i < dataM.size(); i++){
char temp = (char)(((dataM[i] - 97) * keyA[a] + b)%26 + 97);
cCountOfDataC[temp - 'a']++;
dataC += temp;
}
//cout<<dataC<<endl;
for(int i = 0; i < 26; i++){
cout<<cCountOfDataC[i]<<" ";
}
cout<<endl;
}
}
return 0;
}
統計圖繪制
load cData.txt;
bar(cData(1,1:26));
name = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
set(gca, 'XTickLabel', name);
xti=[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26];
set(gca,'xtick',xti,'xtickLabel',name);
title('原文件中各個字母出現情況統計');
for i = 1:26
hold on;
figure;
bar(cData(1:313,i));
axis([1 313 0 3500]);
end