维吉尼亚密码的Python实现

0x00 序

代换密码体制的一般定义为M=C=K=Z26,其中M为明文空间、C为密文空间、K为密钥空间、Z26为26个整数(对应26个英文字母)组成的空间;要求26个字母与模26的剩余类集合{0,1,2,…,25}建立一一对应的关系。

0x01 移位密码
移位密码的加密实际上就是将26个英文字母向后循环移动k位,其加密解密可表示为:
c=Ek(m)=m+k(mod 26)

m=Dk(c)=c-k(mod 26)

其中,m、c、k是满足0≤m,c,k≤25的整数。

0x01 凯撒密码

恺撒密码的替换方法是通过排列明文和密文字母表,密文字母表示通过将明文字母表向左或向右移动一个固定数目的位置。例如,当偏移量是左移3的时候(解密时的密钥就是3):

明文:THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
密文:WKH TXLFN EURZQ IRA MXPSV RYHU WKH ODCB GRJ

恺撒密码的加密、解密方法还能够通过同余的数学方法进行计算。首先将字母用数字代替,A=0,B=1,…,Z=25。此时偏移量为n的加密方法即为:

E{n}(x)=(x+n)\mod 26}

解密就是:

D{n}(x)=(x-n)\mod 26}

0x02 维吉尼亚密码

Vigenenre密码是最著名的多表代换密码,是16世纪法国著名密码学家Vigenenre发明的。Vigenenre密码使用一个词组作为密钥,密钥中每一个字母用来确定一个代换表,每一个密钥字母被用来加密一个明文字母,第一个密钥字母加密第一个明文字母,第二个密钥字母加密第二个明文字母,等所有密钥字母使用完后,密钥再次循环使用,于是加解密前需先将明密文按照密钥长度进行分组。密码算法可表示如下:

设密钥K=(k1,k2,…,kd),明文M=(m1,m2,…,mn),密文C=(c1,c2,…,cn);

加密变换为:

ci=Eki(mi)=mi+ki(mod 26)

解密变换为:

mi=Dki(ci)=ci-ki(mod 26)

通常通过查询维吉尼亚表进行加解密。

0x04 以下为维吉尼亚密码的Python实现。

main.py
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
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# author:Hector
# datetime:20:13

#维吉尼亚
import VigenereDecrypto
import VigenereEncrypto

def main():

info = '''==========********=========='''

# 开始加密
print(info, "\n------维吉尼亚加密算法------")
print(info)

# 读取测试文本文档:傲慢与偏见第一卷第一节
message = open("test.txt","r+").read()
print("读取测试文本文档:test.txt......")
print("开始加密!")
# 输入key
key = input("请输入密钥:")
# 进入加密算法
CipherText = VigenereEncrypto.VigenereEncrypto(message, key)
# 写入密文文本文档
C = open("CipherText.txt", "w+")
C.write(CipherText)
C.close()
print("加密后得到的密文是: \n" + CipherText)

# 开始解密
print(info, "\n------维吉尼亚解密算法------")
print(info)

# 读取加密文本文档
print("读取密文文本文档:CipherText.txt......")
Ciphertext = open("CipherText.txt", "r+").read()
# 进入解密算法
print("开始解密!")
Plaintext = VigenereDecrypto.VigenereDecrypto(Ciphertext, key)
P = open("PlainText.txt", "w+")
# 写入解密文本文档
P.write(Plaintext)
P.close()
print("解密后得到的明文是 : \n" + Plaintext)


if __name__=="__main__":
main()
VigenereEncrypto.py
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
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# author:Hector
# datetime:20:14

def VigenereEncrypto(message, key):
msLen = len(message)
keyLen = len(key)
message = message.upper()
key = key.upper()

# 明文空间
raw = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

# 定义加密后的字符串
ciphertext = ""

# 开始加密
for i in range(0, msLen):
# 轮询key的字符
j = i % keyLen
# encode
# 判断字符是否为英文字符,不是则直接向后面追加且继续
if message[i] not in raw:
ciphertext += message[i]
continue
encodechr = chr((ord(message[i]) - ord("A") + ord(key[j]) - ord("A")) % 26 + ord("A"))
# 追加字符
ciphertext += encodechr

# 返回加密后的字符串
return ciphertext

if __name__ == "__main__":
message = "Hello, World!"
key = "key"
text = VigenereEncrypto(message, key)
print(text)
VigenereDecrypto.py
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
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# author:Hector
# datetime:20:14

def VigenereDecrypto(ciphertext, key):
msLen = len(ciphertext)
keyLen = len(key)
key = key.upper()

# 密文空间
raw = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

plaintext = ""

# 开始解密
for i in range(0, msLen):
# 轮询key的字符
j = i % keyLen
# encode
# 判断字符是否为英文字符,不是则直接向后面追加且继续
if ciphertext[i] not in raw:
plaintext += ciphertext[i]
continue
decodechr = chr((ord(ciphertext[i]) - ord("A") - ord(key[j]) - ord("A")) % 26 + ord("A"))
# 追加字符
plaintext += decodechr

# 返回加密后的字符串
return plaintext

if __name__=="__main__":
ciphertext = "RIJVS, AMBPB!"
key = "key"
text = VigenereDecrypto(ciphertext, key)
print(text)

0x03 测试

测试使用的文本

加密后的明文:

解密后的密文

参考链接:维吉尼亚密码

请我吃糖~