Playfair密码
|字数总计:1.6k|阅读时长:7分钟|阅读量:|
Playfair密码
Playfair密码出现于1854年,它将明文中的双字母组合作为一个单元对待,并将这些单元转换为密文双字母组合。Playfair密码基于一个字母矩阵,该矩阵使用一个关键词(密钥)来构造。
字母矩阵
其构造方法是:从左至右、从上至下依次填入关键词的字母(去除重复的字母),然后再以字母表顺序依次填入其他字母。字母I和J被算为一个字母(即J被当做I处理)。
如密钥为monarchy,则构造字母矩阵如下:
当密钥串有重复字符出现时,需要去重,否则矩阵将无法覆盖26个字母。
我们可以方便地实现字母矩阵的数据结构的代码如下,
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| #include <iostream> #include <sstream> #include <unordered_map> #include <unordered_set> #include <vector>
using namespace std;
class AlphaMatrix { private: vector<char> data{}; unordered_map<char, int> index;
public: AlphaMatrix(string key) : data(vector<char>(25)) { unordered_set<char> m;
m.insert('j');
stringstream ss;
for (int i = 0; i < key.size(); i++) { if (m.count(key[i])) continue;
ss << key[i];
m.insert(key[i]); } string s = ss.str(); for (int i = 0; i < s.size(); i++) data[i] = s[i];
int p = s.size();
for (char c = 'a'; c <= 'z'; c++) { if (m.count(c)) continue; data[p++] = c; }
for (int i = 0; i < 25; i++) index[data[i]] = i;
index['j'] = index['i']; }
char get(int row, int col) { row = (row+5) % 5; col = (col+5) % 5; return data[row * 5 + col]; }
int row(char ch) { int idx = index[ch]; return idx / 5; }
int column(char ch) { int idx = index[ch]; return idx % 5; }
void display() { for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { cout << data[i * 5 + j] << ' '; } cout << endl; } } };
|
编写主函数测试当key="monarchy"时的字母矩阵的输出:
1 2 3 4 5
| int main() { AlphaMatrix am("monarchy"); am.display(); return 0; }
|
输出结果如下:
1 2 3 4 5
| m o n a r c h y b d e f g i k l p q s t u v w x z
|
测试结果符合预期的输出
加密算法
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| void encryptTwoChar(char p1, char p2, char& c1, char& c2, AlphaMatrix& key) { if (key.row(p1) == key.row(p2)) { int r = key.row(p1);
int c1c = key.column(p1) + 1; int c2c = key.column(p2) + 1;
c1 = key.get(r, c1c); c2 = key.get(r, c2c); } else if (key.column(p1) == key.column(p2)) { int c = key.column(p1);
int c1r = key.row(p1) + 1; int c2r = key.row(p2) + 1;
c1 = key.get(c1r, c); c2 = key.get(c2r, c); } else { int row1 = key.row(p1); int col1 = key.column(p1); int row2 = key.row(p2); int col2 = key.column(p2);
c1 = key.get(row1, col2); c2 = key.get(row2, col1); } }
string encrypt(string message, char Q, char X, AlphaMatrix& key) { stringstream ss;
int p = 0; while(p<message.size()) { char p1 = message[p++];
while(p1 == ' ') p1 = message[p++]; char p2; if(p<message.size()) { p2 = message[p++]; while(p2 == ' ') p2 = message[p++]; }else{ p2 = X; } if(p1 == p2) { p2 = Q; p--; } char c1,c2; encryptTwoChar(p1,p2,c1,c2,key); ss<<c1<<c2; } return ss.str(); }
|
编写main函数测试代码如下,
1 2 3 4 5 6 7 8 9 10
| int main() { AlphaMatrix am("monarchy"); am.display();
string src = "aamuhsea"; string result = encrypt(src, 'b', 'x', am); cout << result<<endl;
return 0; }
|
输出结果如下:
1 2 3 4 5 6
| m o n a r c h y b d e f g i k l p q s t u v w x z rmcmbpim
|
符合预期输出
实践
已知密钥key=“hello”,试用Playfair算法加密明文“enjoy your life”,注意:两个相同的字母之间可以插入字母“x”,如果明文为奇数个字符,末尾可以加字符“z”。
手动计算
写出字母矩阵
h |
e |
l |
o |
a |
b |
c |
d |
f |
g |
i/j |
k |
m |
n |
p |
q |
r |
s |
t |
u |
v |
w |
x |
y |
z |
加密过程
两两划分
-
en
- en不同行列,另一个对角线上的元素为ok(c1,c2的顺序同p1,p2的行号)
-
jo
- jo不同行列,另一条对角线上的元素为nh
-
yy会发现重复了,故插入字母x,得到yx
- yx同行,故同行向后各推一个得到zy
-
上一次因重复残留了一个y,故继续使用得到yo
- yo同列,故同列向下各推一个得到of
-
ur
- ur同行,qs
-
li
- li不同行列,hm
-
fe
- cf不同行列,co
得到最终密文为:oknhyxzy ofqs hmco
代码计算
1 2 3 4 5 6 7 8 9
| int main() { AlphaMatrix am("hello"); am.display();
string src = "enjoy your life"; string result = encrypt(src, 'x', 'z', am); cout << result<<endl; return 0; }
|
得出结果如下:
1 2 3 4 5 6
| h e l o a b c d f g i k m n p q r s t u v w x y z oknh zyofqs hmco
|