something:要考试了,原谅窝再水一个wp(! - !)

一、维吉尼亚密码简介

维吉尼亚密码是古典密码的一种,从凯撒密码演变而来,用多个凯撒密码组成,是多表密码的简单实现。简单说,就是按照这张表来实现:

二、题目:

数据如下
faprepeapmsstwmcxdfwfaprepeapmsstwmcxdfwfaprepeapmsstwmcxdfwfaprepeapmsstwmcxdfwfaprepeapmsstwmcxdfwdteprdxcrsnlwtghealcegnzyahzeleutgircdgebpawxhpidtogidiqjxaqecixektglhispdwanhavokxoisiwpylixxetthzgctgpbptgtinrttwucrzrtgdwpaqapxodqtkogyfwthxxtlnheypxseleqpwpaahzlahxewfpcdpiztprgapyhsspgmdqtnohpbmythdqeriwpcsttxxowpgibttysuicfqbtgphbnrcmtxrdedxslwspndxhtqlplheweswtoaiiwrslsrzpogxykihffmtthtqpaneleqtdxagdfrdetcgecixsrtpngugpeitwpyxhtqlpljhphaiucenrtelaczdxobtemcjazysitdxicvmcsrxprtxhewicvpvmpcjxhtizrgjteaihitrgcpeyrtdqmthrzrttcewcdcqmrbhelaiisiwdgwhcjemelawlwcdbpeldcraanucsmiwppepisirpcopartdzagxpxyiwlxwphnsmbdyesgtniniajesiwpwtwtqivtgysvphdicgteedxslwspndmsxidvasxnelantqpgdgidhnyxaritgfdpxensjymqjtvriiiphrphnleaulfrxrrmvtcelaiismsxhdypeddididxektisibpawjahipvacsavokxoitwtqvetztgkhepgipatwthatoeqtnohpbhmtwbzveedhirxixeycdefehjctrxhtrgiwlxgdpwoetepvsaxvibjuqsnpgpynwpatyhelmnvdlpkttairetovordyxrtglwspxoxhtqlmlprewsiglrgtajahxaphacxdlkttairiwzqahhzvechprasbtxttsrpodbtpyiwlxiilzylsecsbpqwcrthfptxcxsrthaicipnylpgrsaahlwavdlpkttairndflakteslxkpaiiweleupnxtwpexhtbloeghnvepipfaaadjogisibtcpjiidqwtgxvirhwpwaxsmifdgppepktrgrdainwprinudcwojisoogtlfuidfxfxtwhpapjirhwlzepadswtxrlesxyaiiwnviixnmsbblryhpjmnvisibpawmsidzpivweensisirtuzvewpchtdrzrtgdwmthqtkacstxsidzpivwenaepywjxytrelhlkecrjuudiphbgpkmlxpyjogllvdtstpsdclwspntrgtpcpitgelihbzrtwlsmltheviztcvikpwhohpthiihzertsesoupcahtcvmcztonojgyelxhewaiisimpxytrthdgeciciicnzoowpxehpkpfetcrmvtcelerwlrctizxrndfxtwtqivtgysvpucsmiwptecpwxyhezxwxisxhtptqouwtxtxcrwptrtelipckeihtrtwtrsaahzjagupahpkpfetclfltizwcdgpqogtelacutzedjesfityeliwzygwismsbpjlaktwmtiapxosdhmtwisiqjpwmtndqxhtqlplejedasbtxsiwlxtwtmelaxdsniwppivwewistzjfxulwtdvcemlttkhigpuuxgpqecimythpjwiixdroqxrkegisenegpzidjdfaaadxhtrzrtgdgirhnzzegisibpawelhdsespczjfexeghsxxinhxzricsfwtgntrsxspvshpjmtbpjfecdnsicrthecrpxhpiapantcwfgdxfrpotpsedywogtofypsthahgtzaactoewpgibttyemdcrxhtqlplhbzwtkdnmftgzysrgtxirhelehpximxvsxgduzvtwtavaxhphihwphojiqsriwpfaaamcbtrvlabdyiouisimpxytlpnpvsjhphtdecsmdipedxslwefjttmtce

1:找出秘钥长度

Kasiski测试法:

若用给定的m个密钥表周期地对明文字母加密,则当明文中有两个相同字母组在明文序列中间隔的字母数为m的倍数时,这两个明文字母组对应的密文字母组必相同。但反过来,若密文中出现两个相同的字母组,它们所对应的明文字母组未必相同,但相同的可能性很大。如果我们将密文中相同的字母组找出来,并对其相同字母数综合研究,找出它们的相同字母数的最大公因子,就有可能提取出有关密钥字的长度m的信息。

理解起来其实很简单,在加密后的文本中,出现的重复单词,很可能就是由相同的原文,通过相同的秘钥段加密得到的,而这些重复单词的间距,是秘钥长度的倍数,多个间距的gcd大概率就是秘钥长度。可以找出所有长度超过3的重复单词,统计他们间距的gcd,然后看一看哪一个最合适当公钥长度。只要文本量足够大,就可以提取出足够多的有效信息。

话不多说,上代码(python3):

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
def Kasiski(data): #搜索相同的3个字符,在文本中出现的位置偏移量,并求得他们的gcd,
dict={}
t=0
for i in range(len(data) - 2): #其实是穷举了所有出现在4次以上的3个连续字符,
if t > 1000000: #这个break条件不加无所谓,数据量非常大可以加一加
break
item = data[i:i + 3]
if item in dict.keys(): #如果这次的3个字符已经统计过了,就continue
continue
if data.count(item) >= 4: #只统计出现超过4次的,只出现一两次,基本是没意义的
dict[item] = []
t = t + 1
# print(item,i)
j = i + 3
while j <= len(data) - 2:
pos = data.find(item, j)
# print(pos)
if pos > 0:
dict[item].append(pos - i) #统计的是,第pos次出现的位置和第一次出现位置的差值。这些差值很可能是秘钥长度的倍数。
j = pos + 3 #小细节,防止无效统计
else:
break
keylen=[]
for item in dict.keys():
x=math.gcd(dict[item][0],dict[item][1]) #算一个gcd
for i in dict[item][2:]:
x=math.gcd(x,i)
if x>2:
keylen.append(x)
print(keylen) #打印出来,一般就很明显了。

原始data进过Kasiski检测,打印出来是:[20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 10, 20, 20, 20, 20, 20, 20, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5],很明显了,秘钥长度是5,而且说明这数据有很多重复。

2:求得秘钥的每个字母

求得秘钥的关键在于,确定了秘钥长度 $k$ 之后,可以把密文的第 $1$个,第$k+1$个,第$2k+1$个….字符提取出来组成一个字符串,这串字符都是由秘钥的第一个字符加密得到的,相当于一个凯撒密码。然后利用重合指数法一个个试,这个网上有很多说明,也很好理解。只要他给的原文文本是意义的,符合英文文本的正常规律就可以了。

代码(python3):

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
def divstr(str, i, n):   #分割函数,知道列表切片就很好懂
c = str[i::n]
return c

def getkey(data,n):
p = [0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, 0.06094, 0.06966, 0.00153, 0.00772, 0.04025,
0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758, 0.00978, 0.02360, 0.00150,
0.01974, 0.00074]
key=''
for i in range(n):
str = divstr(data, i, n).lower()
Mi = []
for i in range(26):
r = []
sum_m = 0
for y in range(0, 26):
r.append(str.count(chr(97 + (y + i) % 26)))
# 统计字串中a-z 偏移i位后得到的字符在每组中的数量,
for x in range(0, 26):
f = (r[x] * p[x]) / len(str)
#当偏移i位后 得到的字符所做拟合指数(sum_m)最接近0.065(最大)
sum_m = sum_m + f
Mi.append(sum_m)
key += chr(97 + Mi.index(max(Mi)))
return key

运行结果:

请选择秘钥长度:5
apple

3:按照秘钥和表进行解密

然后就是,按照维吉尼亚表进行替换,解密一下,这个也还算好写,转ascii再转char,中间注意mod一下26。

代码(python3):

1
2
3
4
5
6
7
8
def decrypt(miwen,key,keylen):
mingwen=''
for i in range(len(miwen)):
# mingwen+=chr(65+(ord(miwen[i])+ord(key[i%keylen])-130)%26)#加密
mingwen+=chr(65 + ((ord(miwen[i])) - ord(key[i%keylen]) + 26) % 26)#解密

print(mingwen.lower())
return mingwen

运行结果:
lrgmgvvrkoyjkroiouaylrgmgvvrkoyjkroiouaylrgmgvvrkoyjkroiouaylrgmgvvrkoyjkroiouaylrgmgvvrkoyjkroiouayjkvktjotmutcnoinvrgekxeuagyqznklkbkxtubghgrrzngzyvuxzykwaovsktzsgqkxgjojgyygeyvxubojkyznkarzosgzkyuiikxkdvkxoktikoyatiutzxurrghrkzuuhomuxpayzyosvreyzavojznkhgrrgryungyozylgtyroqkktmrgtjyjgbojhkiqngshazyulgxznkeykkszungbkhkktuaztashkxkjheixozoiygjojgyygeyznkhgrryvrgynkjcoznmurjiuruxotmoywaozkyosvreznkhkyzgxuatjvkxiktzsuxkgiiaxgzkzngtznkhgrraykjgzlxgtikzngtqyzuskzoiaruayzkyzotmheyioktzoyzyotmkxsgteznkzutmakzcoyzotmtgzaxkulozyiutzktzyiutloxsyzngzznkcuxrjiavhgrrngyiuskgrutmcgelxusznkrkgznkxgtjrgikybgxokzezngzcgyiussutgyxkiktzregyznkyznklkbkxtubgyykixkzgjojgyygeyoyozyxgjoigrreosvxubkjyetzgizoilugsgtjatowakqtozzkjxgyinkrlghxoimobktzngzznoyoyyavvuykjzusgqkznkhgrrlgyzkxgtjvxubojkznklxkkqoiqyvkiogroyzyroqkhkiqngscoznsuxkvuckxozsgetuzhkyaxvxoyotmzngzmugrqkkvkxyroqkhallutgxkatngvveyvgotmugrqkkvkxvkjxuiutzxkxgyygojznkhgorgizyyzxgtmkrecnorkjgtoynqkkvkxznusgyyuxktyktgjsozzkjmruusorezngzozcuarjvxuhghrexkyarzotsuxkyvkizgiargxmugrygygmugrqkkvkxeuangbkzurobkcoznznklgizzngzznksgqkxyixkgzkhgrryluxznkhktklozulyzxoqkxynkygojhkluxkrkgbotmiuvktngmktluxyuaznquxkghazuazlokrjvrgekxyngbkgryuckomnkjotcoznixozoioyssgteygeotmznkhgrroyzuuromnzgtjznkxkluxkngxjzuiutzxurozyhomgtjozyzuuromnzpgvgtypopotkcygmktiewauzkjhxgforogtluxcgxjkjoryutgyygeotmkgxrokxznoysutzncnorkyzxoqkxxobgrjuygojozyugxkjzuulgxcnktqoiqkjpuaxtgroyzygzznksgotvxkyyiktzxkoteuqungsgngbkhkktmobktznkingtikzuzxeuazznklkbkxtubglxusznkvktgrzeyvuzcoznznkgosulnozzotmyvkiogrzgxmkzyotznkmugryulgxlkcngbkhkktghrkzuyiuxksuxkzngtlobkuazulzktgrznuamnznoysgengbkrozzrkzujucoznznkwagrozeulznkhgrrvazfgjsozyzngzznkhgrroyutznkromnzyojkullolgyzumxgsckomnzxkwaoxksktzhazygeyozoytuhommkxzngtvxkbouayhgrryznkiutzxubkxyeubkxznkhgrrgryungygtullvozinjosktyoutotjayzxeotyojkxyygeozsgehktuiuotiojktikzngzvrgekxylxushxgforyvutyuxkjhegjojgyxobgrtoqkngbkhkktgsutmznkhgrrysuyzbuiolkxuayixozoiyznkygsksomnzmuluxznkvxgoykjoynkjuazluxznkhgrrhehkiqngsutkulznksgotvrgekxyaykjzuvxusuzkgjojgykwaovsktz

发现啥也看不出来,不过仔细观察一下,很容易看出前面有重复字符lrgmgvvrkoyjkroiouay出现,后面就不在重复了,可惜我并没有产生敏感,这其实就是flag。
不过我面对这堆字符,没办法,就想是不是加密了不只一遍(其实是维吉尼亚基本只能加密一遍,因为再加密的时候,是无意义的密文再加密,不符合英文的基本分布规律。)
我又跑了几遍发现:

[20, 20, 20, 20, 20, 20, 20, 4, 20, 20, 20, 20, 20, 20, 4, 4, 3, 6]
请选择秘钥长度:2
gg
请输入秘钥


[20, 20, 20, 20, 20, 20, 20, 4, 20, 20, 20, 20, 20, 20, 4, 4, 3, 6]
请选择秘钥长度:4
gggg
请输入秘钥

然后可以确定是经过凯撒过的东西,于是直接把这一段lrgmgvvrkoyjkroiouay跑个26个凯撒。

代码(python3):

1
2
3
4
5
6
data='lrgmgvvrkoyjkroiouay'
for k in range(97,123):
mingwen=''
for i in data:
mingwen+=chr(97+(ord(i)+k-194)%26)
print(mingwen)

结果:
lrgmgvvrkoyjkroiouay
mshnhwwslpzklspjpvbz
ntioixxtmqalmtqkqwca
oujpjyyunrbmnurlrxdb
pvkqkzzvoscnovsmsyec
qwlrlaawptdopwtntzfd
rxmsmbbxquepqxuouage
syntnccyrvfqryvpvbhf
tzouoddzswgrszwqwcig
uapvpeeatxhstaxrxdjh
vbqwqffbuyitubysyeki
wcrxrggcvzjuvcztzflj
xdsyshhdwakvwdauagmk
yetztiiexblwxebvbhnl
zfuaujjfycmxyfcwciom
agvbvkkgzdnyzgdxdjpn
bhwcwllhaeozaheyekqo
cixdxmmibfpabifzflrp
djyeynnjcgqbcjgagmsq
ekzfzookdhrcdkhbhntr
flagappleisdelicious
gmbhbqqmfjtefmjdjpvt
hncicrrngkufgnkekqwu
iodjdssohlvgholflrxv
jpekettpimwhipmgmsyw
kqflfuuqjnxijqnhntzx

根据提示整理 flag{apple_is_delicious}

CSDN链接:csdn