简单介绍Hill
加密算法.
Problem Description
一种矩阵密码问题:
密码学在经济和军事方面起着极其重要的作用.
1929年, Hill(希尔)
通过线性变换对传输信息进行加密处理, 提出了Hill
加密算法.
请结合Hill
加密算法的基本思想, 建立数学模型回答下面问题:
- 任意设计一段明文, 求出这段明文的
Hill(m)
密文(明文字符至少包含数字, 大写英文, 小写英文及标点符号等); - 给出对应的模
r
倒数表; - 假设你已经获取了通信双方的密文及密钥信息, 请编程实现解密过程;
Problem Analysis
Modeling
Naive Solution
先审察古典密码的基本理论.
对于正整数r
, 记集合 $ Z_r = \{ 0, 1, 2, \cdots, r - 1 \} $.
Definition 4.1
: 对于一个元素属于集合 $ Z_r $ 的m
阶方阵A
, 如若存在一个元素属于集合 $ Z_r $ 的方阵B
, 使得
称A
为模r
可逆, B
为A
的模r
逆矩阵, 记为 $ B = A^{-1} (\bmod{r}) $;
$ E (\bmod{r}) $ 的意义为, 每一个元素加减r
的整数倍后, 可以化成单位矩阵.
例如
Definition 4.2
: 对于 $ Z_r $ 的一个整数a
, 如若存在 $ Z_r $ 的一个整数b
, 使得 $ a b = 1 (\bmod{r}) $, 称b
为a
的模r
倒数或乘法逆, 记作 $ b = a^{-1} (\bmod{r}) $;
Theorem 4.1
: 元素属于 $ Z_r $ 的方阵A
模r
可逆的等价条件为, r
与|A|
互素;
Hill
Cipher
一般的加密过程为明文=>编码器=>密文=>普通信道=>解码器=>明文
, 但在其中=>普通信道=>解码器=>
这个环节容易为他人截获并加以分析.
在Hill
加密算法中, 运用的数学手段是矩阵运算, 编码过程如下:
- 根据明文字母表值, 把明文信息用数字表示, 设明文信息只需要
26
个字母, 通信双方给出26
个字母表值为{ "A": 0, "B": 1, "C": 2, ..., "X": 23, "Y": 24, "Z": 25 }
; - 选择一个三阶可逆整数方阵
A
, 称为 $ {Hill}_3 $ (也写作Hill(3)
) 编码的密钥矩阵, 这是整个加密算法的Key
(这也是加密算法的关键, 仅有通信的双方掌握); - 把明文字母逐对分组:
Hill(3)
密码的编码矩阵为三阶矩阵, 则明文字母每3
个为一组(扩展至Hill(m)
密码时每m
个明文字母为一组).
如若最后一组不足3
个字母, 则补充无实义的哑字母, 使每一组皆由3
个明文字母组成.
查出每个明文字母的表值, 构成一个三维列矢量 $ \alpha $; - $ \forall \alpha $, 得到新的三维列矢量 $ \beta = A \alpha $, 查表得到密文字母;
以上为Hill(3)
密码的编码过程, 解码即为上述的逆过程.
但需要注意的是! 由于某些原因, 我们这里不把词组存储为列矢量而存储为行矢量, 因此将采用矩阵右乘而非左乘.
Solving
现在, 我们将对原文Telling and Sharing the World, which Entrusts and Expresses Love and Feelings of VOCALOID
进行有损加密, 并采用可逆矩阵
作为密钥矩阵
首先, 我们使用正则表达式
(也称规则表达式
)以及Python
中的正则表达式模块re
以及其他字符串操作去除明文中的非字母部分, 并全部转化为大写字母, 这一步操作会使得到的明文相比待编码的原文产生少量损失, 可视为一步有损压缩.
需要用到的正则表达式为[^A-Za-z]
, 我们会把这一部分所匹配不到的部分全部删除, 即转化为长度为零的空字符串.
我们先用变量rawtext
存储待编码的文字然后进行如下操作
1 | import re |
现在我们查看得到的明文
1 | plaintext |
被有损压缩为了TELLINGANDSHARINGTHEWORLDWHICHENTRUSTSANDEXPRESSESLOVEANDFEELINGSOFVOCALOID
, 它有75
个字母.
由于我们使用Hill(3)
的原则进行加密, 所以我们现在要把字母数量用字母K
补齐至3
的整倍数(虽然在本例中目前的字母数量75
就是3
的整倍数), 需要注意的是这一步也会造成少量损失
1 | strlen_r = len(plaintext) % 3 # 计算字符串模3的余项的长度 |
此刻的明文
1 | plaintext |
现在切割明文字符串, 在此之前我们先写出把字母转为对应数字的函数alp2num
与数字转义回字母的函数num2alp
1 | alp2num = lambda x : (ord(x) - ord("A")) % 26 |
然后每3
个一组, 每组编成一个3
维矢量, 存入列表然后转化为以行矢量为元素的矩阵mat_origin
1 | import numpy as np |
(其实想要压行的话上面那一段二重循环可以借助语法糖写如下)
1 | mat_origin = np.array([ [ (lambda x : (ord(x) - ord("A")) % 26)(plaintext[k * 3 + l]) for l in range(3) ] for k in range(len(plaintext) // 3) ]) |
然后声明我们的密钥矩阵
1 | keymat = np.array([ |
于是加密后的矩阵便为
1 | mat_new = (mat_origin @ keymat) % 26 |
查看其值
1 | mat_new |
现在使用刚才定义的转义函数, 便可得到密文并存入变量cryptograph
1 | cryptograph = "".join(num2alp(eachnum) for eachnum in mat_new.flatten()) |
查看变量cryptograph
可知密文为TYRLURGMJDILAZFNSVHAKOBQDUVIWLEVMRQWTOCNJFXNYEKEEKXONTANQFWCLURGOQFVJCEBOAF
.
Validation
由于选取的字母集的长度r = 26
, 故方阵A
可逆的等价条件为|A| (mod r)
不为2
或13
所整除.
如若A
满足上述定理4.1
的条件, 不难验证 $ A^{-1} = \frac{1}{|A|} A^\ast $, 其中 $ \frac{1}{|A|} $ 为 $ |A| (\bmod{26}) $ 的倒数.
显然, $ |A| (\bmod{26}) $ 是 $ Z_{26} $ 中的数, $ Z_{26} $ 中有模26
倒数的整数及其倒数可见下表
a |
1 | 3 | 5 | 7 | 9 | 11 |
$ a^{-1} $ | 1 | 9 | 21 | 15 | 3 | 19 |
a |
15 | 17 | 19 | 21 | 23 | 25 |
$ a^{-1} $ | 7 | 23 | 11 | 5 | 17 | 25 |
从上表中我们可以得知 $ 3^{-1} = 9 (\bmod{26}) $, 因此可以反演求得
这便是解码时所需要用到的密钥矩阵的逆.
解码的过程也非常简单, 使用求得密钥矩阵的逆左乘(我们这里是右乘)密文所对应的矢量组, 然后取模, 转义回字母, 便可以得到解出的信息.
1 | keydet = np.linalg.det(keymat).astype(int) # 计算密钥矩阵的行列式值, |
现在我们查看密钥矩阵的模逆和解密后的矩阵
1 | key_inv |
最后我们把矩阵转义回字母
1 | "".join(num2alp(eachnum) for eachnum in mat_recover.flatten()) textrecover = |
查看变量textrecover
得到解出的信息为TELLINGANDSHARINGTHEWORLDWHICHENTRUSTSANDEXPRESSESLOVEANDFEELINGSOFVOCALOID
.
1 | textrecover == plaintext |
验证无误.
Extra
感兴趣的朋友可以看看兽音译者什么的.
References
1. 百度百科词条 Hill密码, 在网络上可以找到相关工具例如bugku
提供的Hill Cipher Tool
, 并参考其他文章 2 3 4 5 ↩
2. zhangliu
的博客园文章 Hill密码 ↩
3. qq_25968195
的CSDN博客 Hill 加密算法 ↩
4. 信管网文章 信息安全技术知识:Hill 密码、Hillm 密码加密过程 ↩
5. 0zcl
的博客园文章 信息安全-2:python之hill密码算法 ↩