Lab1题解
一、关于Lab1.py提供的加密过程分析
- 可以注意到明文(message,也就是flag)被隐藏,初始化的密文需要我们逆推得出
message = '*****{********************}'
cipher = ''
- Lab1采用的加密方式是移位密码
- 关于移位密码:
其加密变换为:
E
k
(
m
)
=
(
m
+
k
)
m
o
d
q
=
c
0
≤
m
,
c
<
q
E_k(m) = (m+k)~mod~q = c\\ 0 \leq m,~c<q\\
Ek(m)=(m+k) mod q=c0≤m, c<q
密钥空间为
K
=
{
k
∣
0
≤
k
<
q
}
K=\{k|0\leq k<q\}
K={k∣0≤k<q} ,元素个数为q,当
k
=
0
k=0
k=0 时,为恒等变换
其解密变换为:
D
k
(
c
)
=
(
c
−
k
)
m
o
d
q
=
m
D_k(c)=(c-k)~mod~q=m
Dk(c)=(c−k) mod q=m
key, _, _ = xgcd(24249125136394343, 16156191447296617)
key = key % 16156191447296617
-
key实为24249125136394343的逆元,可以采用扩展欧式算法得出
-
关于逆元:
设n为正整数,a为整数满足 0 < a < n 0<a<n 0<a<n
若存在一个正整数b, 0 < b < n 0<b<n 0<b<n 满足:
a b ( m o d n ) = 1 ab(mod~n)=1 ab(mod n)=1
称b为 a ( m o d n ) a(mod~n) a(mod n) 的逆元,并记b为 a − 1 ( m o d n ) a^{-1}(mod~n) a−1(mod n) -
关于逆元使用扩欧算法计算:
若想求得满足 a x ( m o d n ) = 1 的逆元 x ,等价于 ax(mod~n)=1的逆元x,等价于 ax(mod n)=1的逆元x,等价于 a x = k n + 1 , k ax=kn+1,k ax=kn+1,k 为整数
移项得 a x − k n = 1 ax-kn=1 ax−kn=1 即
a x + l n = 1 ax+ln=1 ax+ln=1
可以发现求解逆元转化为扩欧算法计算x,但x可能为负,所以再次取模保证了 k e y > 0 key>0 key>0 (这是因为python的模运算会保证非负)更多内容详见:https://zhuanlan.zhihu.com/p/449221995
-
-
关于扩欧算法:
-
关于AITMCLAB.libnum中所带扩欧算法函数,可直接import使用,其实现可自行查看
def xgcd(a, b): """ Extented Euclid GCD algorithm. Return (x, y, g) : a * x + b * y = gcd(a, b) = g. """ pass
-
关于自己编写的Egcd()函数
def Egcd(a, b): x = [a, 1, 0] y = [b, 0, 1] while y[0] != 0: q = x[0]//y[0] for i in range(0, 3): x[i] = x[i] - q*y[i] tmp = x[:] x = y[:] y = tmp[:] return x
个人关于扩欧算法的理解:使用单位阵 I I I 将辗转相除法每一步所等价的初等矩阵 P i P_i Pi(左乘)的结果 P = P 1 P 2 . . . P t P=P_1P_2...P_t P=P1P2...Pt记录下来
[ a 1 0 b 0 1 ] − > [ r u v 0 m n ] 其中 P = [ u v m n ] \left[\begin{matrix} a&1&0\\ b&0&1 \end{matrix}\right] -> \left[\begin{matrix} r&u&v\\ 0&m&n \end{matrix}\right] \\其中~P= \left[\begin{matrix} u&v\\ m&n \end{matrix}\right] [ab1001]−>[r0umvn]其中 P=[umvn] -
移位加密程序实现:
for char in message: if 'a' <= char <= 'z': now_cipher = (ord(char) - ord('a') + key) % 26 cipher += chr(now_cipher + ord('a')) else: cipher += char
-
-
最后再一次使用逆元进行计算(同key)得到了output
numOfCipher = s2n(cipher) bigPrime = 356591097085378373041406631775396675403608993465904761745667548546613469964055945893375233 output, _, _ = xgcd(numOfCipher, bigPrime) output = output % bigPrime # output = 233238587670647787805028809001128036933176275182381815462045390514627843647184629262585311
二、关于Lab1的解密过程
其核心任务在于:
- 如何实现移位密码的解密变换
- 如何求解numOfCipher
- 一些库函数导入和已知的数据
from AITMCLAB.libnum import n2s, s2n, xgcd
bigPrime = 356591097085378373041406631775396675403608993465904761745667548546613469964055945893375233
output = 268287563061576100897937311713001449077245433065661668430027784938038192146644112389472865
key, _, _ = xgcd(24249125136394343, 16156191447296617)
key = key % 16156191447296617 # 取正的余数
# key为24249125136394343的逆元
# (ppx, ppy, gcd) = (-5984828584066420, 8982739386836133, 1)
# key = 10171362863230197
- 关于实现移位密码的解密变换
def decode(cpr):
msg = ""
for c in cpr:
if 'a' <= c <= 'z':
now_msg = c - ord('a')
msg += chr(((now_msg - key) % 26) + ord('a'))
else:
msg += chr(c)
return msg
- 关于numOfCipher的求解
- 回忆扩欧算法
a x + b y = 1 ax+by=1 ax+by=1
加密时使用numOfCipher(a)和bigPrime(b)得到output(x):
n
u
m
O
f
C
i
p
h
e
r
∗
o
u
t
p
u
t
+
b
i
g
P
r
i
m
e
∗
y
=
1
numOfCipher~*~output~+~bigPrime~*~y=1
numOfCipher ∗ output + bigPrime ∗ y=1
反之,解密时使用output(a)和bigPrime(b)得到numOfCipher:
o
u
t
p
u
t
∗
n
u
m
O
f
C
i
p
h
e
r
+
b
i
g
P
r
i
m
e
∗
y
=
1
output~*~numOfCipher~+~bigPrime~*~y=1
output ∗ numOfCipher + bigPrime ∗ y=1
noc, _, _ = xgcd(output, bigPrime)
noc = noc % bigPrime
- 最后使用n2s将cipher复原,并解码
- 注意n2s返回的字符串为字节数据类型,形如: b ′ h e l l o _ w o r l d ′ b'hello\_world' b′hello_world′,所以需要转换为utf-8的编码,再使用decode进行解密变换
cipher = n2s(noc)
cipher = cipher.decode("utf-8")
message = decode(cipher)