发布于 

vegenere再探究

蓝帽的re终究是没能做出来,所以只能先摸一下这个密码。

比赛中

比赛中这个题做到了找出循环节这一步,但由于之前对维吉尼亚的误区所以没有继续往下做。

在此先说明之前的做法:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
s=' '
s=s.replace('\n','')
print(s)
#引入字符串并去除多余的换行符
s2_list={}

di={}

def gcd1(a):
g=a[0]
for i in a:
g=gcd(i,g)
return g
#求列表的最大公因数
for i in range(len(s)-2):
s1=s[i]+s[i+1]+s[i+2]
if s1 not in s2_list:
s2_list[s1]=[]
s2_list[s1].append(i)
#取任意连续三个字母为一组,判断其出现的位置
for i in s2_list:
if len(s2_list[i])>2:
di[i]=[]
print(i+":"+str(s2_list[i]))
for j in range(1,len(s2_list[i])):
di[i].append(s2_list[i][j]-s2_list[i][j-1])
print(di[i])
print(gcd1(di[i]))
#di列表是位置差分,再对其求公因数判断密钥长度
def f(s):
a=[chr(i) for i in range(ord('a'),ord('z')+1)]
ans=0
for i in a:
ans+=(s.count(i))*(s.count(i)-1)/(len(s)*(len(s)-1))
return ans
#重合指数
def check(n):
ave=0
t=['' for i in range(n)]
for i in range(len(s)):
t[i%n]+=s[i]
for i in t:
a=f(i)
print('%.3f'%a,end=' ')
ave+=a
print("ave is %.3f"%(ave/n))
#检验前一步猜测的密钥是否符合重合指数

for i in range(1,19):
print('%2d'%i,end=':')
check(i)

def fn(s1,s2,k):
a1=[chr(i) for i in range(ord('a'),ord('z')+1)]
a2=[ (a1[(i+k)%26]) for i in range(26)]
ans=0
for i in range(len(a1)):
ans+=(s1.count(a1[i]))*(s2.count(a2[i]))/(len(s1)*(len(s2)))
return ans
#重合互指数
def checkn(n):
ave=0
t=['' for i in range(n)]
for i in range(len(s)):
t[i%n]+=s[i]
for i in range(n):
for j in range(n):
if i<=j:
print("(%d,%d):"%(i,j),end='')
for k in range(26):
m=10*fn(t[i],t[j],k)
if 6<=m*10 <=7:
print("%.2f "%(m),end='|')
else:
print(end=" |")
print('\n'+'-'*27*6)
print('\n ',end='')


for i in range(26):
print('%4d|'%i,end=' ')

print()
checkn(6)
#制表,输出相对误差不大于0.005的位置
'''
key[2]=key[0]+22
key[3]=key[0]+13
key[4]=key[0]+17
key[5]=key[0]+12
key[2]=key[1]+7
key[3]=key[1]+24
key[4]=key[1]+2
key[5]=key[1]+23
key[3]=key[2]+17
key[4]=key[2]+21
key[4]=key[3]+4
key[5]=key[4]+21
#是得到的约束关系
'''

key=[0,15,22,13,17,12]
sk=''
for i in range(26):
for j in range(6):
sk+=chr(ord('a')+((i+key[j])%26))
print(sk)
sk=''
#输出所有可能密钥
#得到密钥:crypto
#利用在线脚本解密(网址http://www.atoolbox.net/Tool.php?Id=856)

赛后反思

在专业内学的这个算法主要是从数统分析角度加以人工来解决的,使用的是手动判断循环节+重合指数+互指数约束,对于解决一般的维吉尼亚是有用的,但并不自动化。

这次赛题则启示我从正向角度进行分析,即先预设循环节长度,求出重合指数,然后取可行的利用拟重合指数进行密钥爆破,并取符合概率范围的自动化往下跑就行。

以下是参考了striving神仙的博客重构的代码

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
from gmpy2 import *

def savelowerletter(s):

m=''

for i in s:

if 'a'<=i<='z':

m+=i

return m

def check(string):

n = 0

m = 0

alpha = {'a':0,'b':0,'c':0,'d':0,'e':0,'f':0,'g':0,'h':0,'i':0,'j':0,'k':0,'l':0,'m':0,'n':0,'o':0,'p':0,'q':0,'r':0,'s':0,'t':0,'u':0,'v':0,'w':0,'x':0,'y':0,'z':0}

n = len(string)

n = float(n*(n-1))

for i in string:

alpha[i] += 1

for i in alpha:

i = alpha[i]

m += i*(i-1)

m = m/n

return m



def find_keylength(text):

kl = 1

while True:

s = 0.0

for i in range(kl):

s+=check(text[i::kl])



s= s/kl

if s >= 0.06 and s <= 0.07:

break

else:

kl += 1

return kl



def find_keyword(C,kl):

cl = list(C)

S = {'a':0.08167,'b':0.01492,'c':0.02782,'d':0.04253,'e':0.12702,'f':0.02228,'g':0.02015,'h':0.06094,'i':0.06966,'j':0.00153,'k':0.00772,'l':0.04025,'m':0.02406,'n':0.06749,'o':0.07507,'p':0.01929,'q':0.00095,'r':0.05987,'s':0.06327,'t':0.09056,'u':0.02758,'v':0.00978,'w':0.02360,'x':0.00150,'y':0.01974,'z':0.00074}

while True:

key1=[]

key2=[]

for i in range(kl):

clnow = cl[i::kl]

M = 0



for m in range(26):

if gcd(m,26)==1:

for n in range(26):

pcnow = 0

for L in set(clnow):

Lf = clnow.count(L) / len(clnow)

k = chr(invert(m,26)*(ord(L)-n)%26 +97)

pcnow += Lf * S[k]

if pcnow > M:



M = pcnow

k1=m

k2=n

key1.append(k1)

key2.append(k2)



break

return key1,key2





def decrypt(Ciphertext,key1,key2,length):

message=""

flag=0

for i in Ciphertext:

if 'a'<=i<='z':

message+=chr(invert(key1[flag%length],26)*(ord(i)-key2[flag%length])%26+97)

flag+=1

else:

message+=i

return message





C =open(r'test.txt','rb').read().decode().lower()

Ciphertext=savelowerletter(C)

l=find_keylength(Ciphertext)

print(l)

key1,key2=find_keyword(Ciphertext,l)

print(key1)



print(key2)



f=open(r"flag.txt","w")

f.write(decrypt(Ciphertext,key1,key2,l))

之后就是AES解密。

1
2
3
4
5
6
from Crypto.Cipher import AES
import base64
key="frequencyisoeasy"
aes = AES.new(key.encode(), AES.MODE_CBC, b'\0' * 16)
cipher=b'XpOY4zBvK6h//jAgIraYzBBK1lXz9pw7DxXGt6XoODZrSUCpjFzgw5pCo3ffclKM'
print(aes.decrypt(base64.b64decode(cipher)))

简而言之,虽然是古典密码,但突然提示了我学习的路径应该有所变化。

另外

本题是怎么保证的仿射系数一定有逆的啊啊啊啊

还有那个wasm逆向

汇报一下,通过那个题我学会了

  1. wasm 可以嵌入web开发
  2. chrome 可以直接调试wasm,而且看到值
  3. 如何让网站在本地跑起来
    • 通过面板
    • python -m http.server 8000
  4. CE好玩,但怎么才能调试出受保护不可访问的地址啊(怀疑自己是进程错了)

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本站由 [@Zuni](http://example.com/) 创建,使用 Stellar 作为主题。