來源於我的博客
1.編制密碼錶
構造一個5*5的密碼錶,表格填充關鍵字(字母不重複),之後按字典序填充密碼錶中沒有的字母,需要注意的是5*5表格只能放25個字母,剩下一個字母需要選擇已經放入表的一個作爲替代,這裏習慣性將J省略,I/J共用。
以關鍵字爲PLAYFAIR EXAMPLE爲例
P | L | A | Y | F |
I/J | R | E | X | M |
B | C | D | G | H |
K | N | O | Q | S |
T | U | V | W | Z |
得到如上密碼錶
2.整理明文
由於PalyFair成對字母加密的特性,要對明文進行分組處理:
兩個不同的字母一組,如果字母相同需要添加冗餘(指定一個字母)保持其不同;
最後如果有單個字母同樣需要添加冗餘使其成對。
以明文“Things are not always what they see”爲例(指定W爲替代字母)
整理後變成:“TH IN GS AR EN OT AL WA YS WH AT TH EY SE EW”
3.加密
根據成對字母在字母表中的相對位置進行替代
主要分兩類:
-
在一條線上(行相同或列相同)
x相同,就取x+1位置的字母(mod 5,即最右邊+1=最左邊的):
y相同,就取y+1位置的字母(mod 5,即最下邊+1=最上邊的):
AL=YA
P | L | A | Y | F |
I/J | R | E | X | M |
B | C | D | G | H |
K | N | O | Q | S |
T | U | V | W | Z |
-
不在一條線上
取兩點爲頂點的矩形,矩形的另外兩點即爲密文
注意的是順序:橫座標保持不變,縱座標改爲pair的縱座標
T-Z H-B I-R K-N 他們的橫座標均相同
TH=ZB
P | L | A | Y | F |
I/J | R | E | X | M |
B | C | D | G | H |
K | N | O | Q | S |
T | U | V | W | Z |
IN=RK
P | L | A | Y | F |
I/J | R | E | X | M |
B | C | D | G | H |
K | N | O | Q | S |
T | U | V | W | Z |
C++實現:
#include#include#includeusing namespace std;
//string keyWord = { "MoonCake" };
string keyWord = { "PLAYFAIR EXAMPLE" };
string alphabet = { "ABCDEFGHIKLMNOPQRSTUVWXYZ" };
char a[5][5] = { " " };
pair getPosi(char c) {
for (int i = 0;i < 5;i++) {
for (int j = 0;j < 5;j++) {
if (c == a[i][j]) return make_pair(i,j);
}
}
return make_pair(6, 6);//(5*5缺少一個字母)失敗
}
string SplitWord_(string f) {
string g;
int count_g = 0;
int char_c = 0;
//作簡單分割
for (int i = 0;i < f.size();) {
for (int j = 0;j < 2;j++) {
if ((int)(f[i])>64 && (int)(f[i]) < 91) {
//g[count_g++] = f[i];
string t_f;
t_f.resize(1);
t_f[0] = f[i];
g.append(t_f);
char_c++;
}
if (((int)(f[i]) > 96) && ((int)(f[i]) < 123)) {
//g[count_g++] = (char)((int)f[i] - 32);
string t_f;
t_f.resize(1);
t_f[0]= (char)((int)f[i] - 32);
g.append(t_f);
char_c++;
}
if (char_c == 2&&i!=f.size()&& i != f.size()-1) {
//g[count_g++] = ' ';
g.append(" ");
char_c = 0;
}
i++;
}
}
//cout << g << "e"<<endl;
return g;
}
bool is_dup(string g,int &posi) {
for (int i = 0;i < g.size()-1;i++) {
if (((int)(g[i]) > 64) && ((int)(g[i]) < 91)&& ((int)(g[i+1]) > 64) && ((int)(g[i+1]) < 91)) {
if (g[i] == g[i + 1]) {
posi = i;
posi++;
return true;
}
}
}
return false;
}
string SplitWord(string f, char replace) {
string g = SplitWord_(f);
//插值(replace)去除重複
int posi = 0;
string re;
re.resize(1);
re[0] = replace;
while (is_dup(g,posi)) {
g.insert(posi,re);
g = SplitWord_(g);
}
//判斷結尾是否成對
if ((g[g.size() - 2]) < 64 || (g[g.size() - 2]) > 91) {
g.insert(g.size(), re);
}
//明文整理完成
return g;
}
void CreateMatrix() {
int row = 0;
int colom = 0;
for (int i = 0;i < keyWord.size();i++) {
if (keyWord[i] == ' ') continue;
if ((int)keyWord[i]>96 && (int)keyWord[i] < 123) {
keyWord[i] = (char)((int)keyWord[i] - 32);
}
bool noMatch = true;
for (int x = 0;x < 5;x++) {
for (int y = 0;y < 5;y++) {
if (a[x][y] == keyWord[i]) {
noMatch = false;
}
}
}
if (noMatch) {
a[row][colom] = keyWord[i];
if (++colom > 4) {
colom = colom % 5;
row++;
}
}
}
// 填充剩餘字母
for (int i = 0;i < alphabet.size();i++) {
bool noMatch = true;
for (int x = 0;x < 5;x++) {
for (int y = 0;y < 5;y++) {
if (a[x][y] == alphabet[i]) {
noMatch = false;
}
}
}
if (noMatch) {
a[row][colom] = alphabet[i];
if (++colom > 4) {
colom = colom % 5;
row++;
}
}
if (row == 5) break;
}
//填充完成
}
void PrintMatrix() {
for (int i = 0;i < 5;i++) {
for (int j = 0;j < 5;j++) {
cout << a[i][j] << " ";
}
cout << endl;
}
}
void encrypt(){
//create 5*5 Matrix
CreateMatrix();
string f = { "Things are not always what they see" };
f = { "MY Name IS ATUL" };
//整理明文
string g=SplitWord(f, 'W');
PrintMatrix();
cout << g << endl;
//加密
for (int i = 0;i < g.size()-1;) {
if (getPosi(g[i]).first != getPosi(g[i + 1]).first&&getPosi(g[i]).second != getPosi(g[i + 1]).second) {//對角
char gi = g[i];
char giPlus = g[i + 1];
g[i] = a[getPosi(gi).first][getPosi(giPlus).second];
g[i + 1] = a[getPosi(giPlus).first][getPosi(gi).second];
}
if (getPosi(g[i]).first == getPosi(g[i + 1]).first&&getPosi(g[i]).second != getPosi(g[i + 1]).second) {//同x軸 換成對應位於y+1的字母,越界則爲最上面
char gi = g[i];
char giPlus = g[i + 1];
int giy = getPosi(gi).second;
giy = (giy+1) % 5;
int giPlusy = getPosi(giPlus).second;
giPlusy = (giPlusy+1) % 5;
g[i] = a[getPosi(gi).first][giy];
g[i + 1] = a[getPosi(giPlus).first][giPlusy];
}
if (getPosi(g[i]).first != getPosi(g[i + 1]).first&&getPosi(g[i]).second == getPosi(g[i + 1]).second) {//同y軸 換成對應位於x+1的字母,越界則爲最上面
char gi = g[i];
char giPlus = g[i + 1];
int gix = getPosi(gi).first;
gix = (gix+1) % 5;
int giPlusx = getPosi(giPlus).first;
giPlusx = (giPlusx+1) % 5;
g[i] = a[gix][getPosi(gi).second];
g[i + 1] = a[giPlusx][getPosi(giPlus).second];
}
i+=3;
}
cout << g << endl;
}
void decrypt() {
CreateMatrix();
string g = { "XF OL IX MK PV LR" };
cout << g << endl;
//解密
for (int i = 0;i < g.size() - 1;) {
if (getPosi(g[i]).first != getPosi(g[i + 1]).first&&getPosi(g[i]).second != getPosi(g[i + 1]).second) {//對角
char gi = g[i];
char giPlus = g[i + 1];
g[i] = a[getPosi(gi).first][getPosi(giPlus).second];
g[i + 1] = a[getPosi(giPlus).first][getPosi(gi).second];
}
if (getPosi(g[i]).first == getPosi(g[i + 1]).first&&getPosi(g[i]).second != getPosi(g[i + 1]).second) {//同x軸 換成對應位於y-1的字母,越界則爲最上面
char gi = g[i];
char giPlus = g[i + 1];
int giy = getPosi(gi).second;
giy = (giy - 1)>=0?(giy - 1):4;
int giPlusy = getPosi(giPlus).second;
giPlusy = (giPlusy - 1)>=0? (giPlusy - 1):4;
g[i] = a[getPosi(gi).first][giy];
g[i + 1] = a[getPosi(giPlus).first][giPlusy];
}
if (getPosi(g[i]).first != getPosi(g[i + 1]).first&&getPosi(g[i]).second == getPosi(g[i + 1]).second) {//同y軸 換成對應位於x-1的字母,越界則爲最上面
char gi = g[i];
char giPlus = g[i + 1];
int gix = getPosi(gi).first;
gix = (gix - 1)>=0 ? (gix - 1):4;
int giPlusx = getPosi(giPlus).first;
giPlusx = (giPlusx - 1)>=0? (giPlusx - 1):4;
g[i] = a[gix][getPosi(gi).second];
g[i + 1] = a[giPlusx][getPosi(giPlus).second];
}
i += 3;
}
cout << g << endl;
}
int main() {
encrypt();
cout << "加密完成,立即解密" << endl;
decrypt();
cout << "解密完成" << endl;
return 0;
}