Playfair密码
在密码学的万神殿里,如果说凯撒密码是入门级的“Hello World”,那么Playfair密码无疑是第一座真正需要动脑筋翻越的小山。它首次告别了简单的单字母替换,开创了“双字母组” 加密的先河,将密码的强度提升了一个维度。
这个由查尔斯·惠斯通发明,并由他的朋友Playfair勋爵推广的算法,以其优雅的规则和手工时代难以破解的特性而闻名。它不仅是维多利亚时代密码学的杰作,更是理解现代分组密码思想的绝佳起点。准备好你的5x5矩阵,我们即将开始一场逻辑与智慧的构建之旅
这个密码我自己感觉不行,信息损坏太多了,对于这个在我们讲完就可以给各位揭秘了,不过这个也是密码学的一座丰碑了
算法原理
密钥处理
我们首先来讲一个Playfair开创性的东西,密钥表这个不再像维吉尼亚密码一样只在一维进行偏移计算了,他使用密钥来生成一个比表格,接下来我来讲表格是怎么生成的
首先对密钥本身进行处理
- 将密钥中所有非英文字符去除
- 将密钥所有英文字符转大写
- 讲字母
J替换为字母I - 移除密钥中重复字符,只保存第一次出现的字符
然后就是表的生成了
- 将处理过后的密钥依次填入
- 将剩余未使用的字母按顺序填入,表格剩余位置
我们来看一个示例 密钥为:PLAYFAIR EXAMPLE
我们首先处理掉空格,然后转成大写,将J替换为I,这里没有就暂时不处理了,然后去除掉重复出现的字符,然后得到的真实密钥就是PLAYFIREXM
然后进行填入
P L A Y F
I R E X M
B C D G H
K N O Q S
T U V W Z前两行是我们已使用过的字符,后面填充没有使用过的字符,这时候我们就搞定密钥表了,下面来看明文处理
明文处理
对于明文处理Playfair算法也是和维吉尼亚密码有相当大的区别,维吉尼亚密码以及之前的密码都是单字符进行加密,Playfair密码是两个字符进行分组并加密
我们来加密一句话吧Hello World,加密也是非常常见的话了
- 首先全部转化为大写,得到
HELLO WORLD - 移除非字母字符,得到
HELLOWORLD - 讲字符
J替换为I,这里没有J就不进行替换了 - 然后就是处理重复字符
- Playfair处理是两个字符两个字符进行处理
- 每两个相同字符之间来进行插入
X,我们的HELLO的LL是重复的那么我们就在这之间插入X占位符,还有就是插入结束后求现在明文的长度,如果是奇数那么就在最后插入X占位,我们最后的处理结果就是HE LX LO WO RL DX
- 然后下一步就是进行真正的加密了
加密处理
HE LX LO WO RL DX
P L A Y F
I R E X M
B C D G H
K N O Q S
T U V W Z这个计算有三条计算规则
- 同一行
取右边的字母(循环)
- 同一列
取下边的字母(循环)
- 不同行不同列
形成矩形 → 用同一行、对角列的字母替换
然后我们来进行计算
手推密码
| 明文 digraph | 字母 1 (row,col) | 字母 2 (row,col) | 规则 | 密文 digraph |
|---|---|---|---|---|
| HE | H (2,4) | E (1,2) | 矩形 | DM |
| LX | L (0,1) | X (1,3) | 矩形 | YR |
| LO | L (0,1) | O (3,2) | 矩形 | AN |
| WO | W (4,3) | O (3,2) | 矩形 | VQ |
| RL | R (1,1) | L (0,1) | 同列 | CR |
| DX | D (2,2) | X (1,3) | 矩形 | GE |
最后得到的结果就是DM YR AN VQ CR GE |
代码
这个东西的代码还需要打磨,实现起来确实复杂,等我自己想象
就这个东西很抽象,它标准算法并不包含处理字符串,但是你自己需要处理字符串的,这个字符串如果是偶数,最后一个你X你还需要去做内容含义判断
然后还有里面插入的x和空格也是需要解密人员去自己根据含义来进行还原,消息损耗太大了,我感觉不好用,现在已经是下午了,上午把文章写完,下午自己又想了想算法
func playfair_buildMatrix(key string) (Matrix [5][5]rune, key_table map[rune][2]int) {
data := strings.ToUpper(strings.ReplaceAll(key, "J", "I"))
used := map[rune]bool{}
var chars []rune
for _, c := range data {
if c >= 'A' && c <= 'Z' && !used[c] {
used[c] = true
chars = append(chars, c)
}
}
for c := 'A'; c <= 'Z'; c++ {
if c == 'J' {
continue
}
if !used[c] {
chars = append(chars, c)
used[c] = true
}
}
var matrix [5][5]rune
pos := map[rune][2]int{}
for i, c := range chars {
r, col := i/5, i%5
matrix[r][col] = c
pos[c] = [2]int{r, col}
}
return matrix, pos
}
func playfair_Preprocess(text string) string {
text = strings.ToUpper(strings.ReplaceAll(text, "J", "I"))
var result []rune
for i := 0; i < len(text); i++ {
c1 := rune(text[i])
var c2 rune
if i+1 < len(text) {
c2 = rune(text[i+1])
if c1 == c2 {
c2 = 'X'
} else {
i++
}
}
result = append(result, c1, c2)
}
if len(result)%2 == 0 {
result = append(result, 'X')
}
return strings.ReplaceAll(string(result), " ", "")
}
func playfair_encrypt(data string, key string) (res string) {
var result []rune
data = playfair_Preprocess(data)
matrix, pos := playfair_buildMatrix(key)
fmt.Println(pos)
for i := 0; i < len(data); i += 2 {
a, b := rune(data[i]), rune(data[i+1])
r1, c1 := pos[a][0], pos[a][1]
r2, c2 := pos[b][0], pos[b][1]
var x, y rune
switch {
case r1 == r2:
x = matrix[r1][(c1+1)%5]
y = matrix[r2][(c2+1)%5]
case c1 == c2:
x = matrix[(r1+1)%5][c1]
y = matrix[(r2+1)%5][c2]
default:
x = matrix[r1][c2]
y = matrix[r2][c1]
}
result = append(result, x, y)
}
return string(result)
}
func main() {
fmt.Println(playfair_encrypt("HELLO WORLD", "PLAYFAIR EXAMPLE"))
}下一篇我们就要步入现代密码学了,下一篇学习S-DES