先从简单的单表代替开始说起:要知道,在CTF题中,有很多很多都是单表代替的题,比如说:

BH=CWG=EO=IEI=;DEDEDEY

所有数据长成这样,神TM能够认识对吧,但是要注意,这可是CTF的比赛!所以得分模式很套路:

最后的答案一般都是flag{}或者FLAG{}什么的对吧

那么,计算一下:

ord(‘Y’)-ord(‘}’)= - 36

那么,再试试:ord(‘B’)+36 = ord(‘f’)

所以,直接尝试一发,所以的都是36的偏移就好了,对吧

很简单的kaisamima对吧,本质上是个ascii码表的偏移对应,或者是自己定义的某些字符的循环对应

在数据文本字符情况下足够的情况下,统计英文字频即可简单破解:因为英文中的每个字符的出现概率是有固定的比例的(不是所有的都一定按照顺序,但是大概已经可以基本对应了)


那么,来谈谈什么是Virginia密码:因为单表对应很容易破解,那么换成多表呢?

所以我们确定一种对应的方法:Virginia

这种方法需要密钥,密钥的长度是单表的数量(其实是不同的字符个数)

其实,多个单表的对应关系是这样,可以一个一个算,但是,根据多个单表的思想来理解会更简单

用python代码举例会更简单吧:


import string
s = string.printable[36:62]

word = 'TOBEORNOTTOBETHATISTHEQUESTION'
cipher = 'RELATIONS'
info = ''

for i in range(0,len(word)):
	info += s[(s.find(word[i])+s.find(cipher[i%len(cipher)]))%26]
print info

flag = ''
for i in range(0,len(info)):
	flag += s[(s.find(info[i])+26-s.find(cipher[i%len(cipher)]))%26]
print flag


当然,在实际应用中并不会有这么的简单:我们不可能知道密钥是什么,甚至连密钥的长度我们也无从知道

那么,就只能根据方法来暴力测试:

kasiski测试法,来测得密钥的长度,理论是:当字符数目足够多的话,那么有可能出现,相同的字符串被相同的偏移串加密,那么得到的结果是相同的,我们把这些所有的可能全部统计下来,可以得到这些偏移值之间的相对距离。取他们的公共因子,就可能是密钥的长度

暴力的python代码如下:

def get_len(s):
	val = []
	length = len(s)
	const = 4
	for i in range(0,length-const):
		for j in range(i+1,length):
			if s[i:i+const] == s[j:j+const]:
				val.append(j-i)
	print val

其中的const越大,说明出现的概率越低,数量会越少;const越小,出现的概率越大,数量越多

我们需要取得一个适中的值,让val里大概有个10个数字左右,然后大概看下他们的公因数,一一分析,或者结合其他的方法来进行密钥长度的判断以及下一步计算

接下来就是确定密钥


这里给出两个CTF样例题,可以解释说明得很明白:

https://findneo.tech/171005NuptVigenereWP/#%E5%8F%82%E8%80%83%E9%93%BE%E6%8E%A5

https://findneo.tech/180527suctf/#Magic