0%

几道比赛中遇到的密码题

比赛中的Crypto题复现

今年比赛中做到的一些高质量的密码题。

2021蓝帽杯初赛classic

题目:

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
from random import randint
from secret import l1, l2, text, key, flag

# text is a plain English text which only consists of lowercase letters (without any symbol)
table = 'abcdefghijklmnopqrstuvwxyz'

assert key in text
assert l1 * l2 < 100

k1 = []
k2 = []

fib = [0, 1]
modulus = randint(12345,6789010)
for i in range(1 << 16):
fib.append((fib[-1] + fib[-2]) % modulus)

for i in range(l1):
k1.append(fib[randint(0, 1 << 16)] % 26)

for i in range(l2):
k2.append(fib[randint(0, 1 << 16)] % 26)

c = ''.join(table[((ord(x) - 97) * (k1[i % l1]) + k2[i % l2]) % 26] for i, x in enumerate(text))

from Crypto.Cipher import AES
import base64

aes = AES.new(key.encode(), AES.MODE_CBC, b'\0' * 16)
print(c)
print(base64.b64encode(aes.encrypt(flag + b'\0' * (16 - len(flag) % 16))))

exp:

Python2环境:

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
#coding:utf_8
import gmpy2 as gm

c =
#太长了不写了

best_index_of_Coincidence = 0.065

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

print best_freq


def index_of_coincidence(s):
'''
计算字符串s的重合指数,即所有字符出现概率的平方和
:param s:密文字符串
:return:s的重合指数
'''
zimubiao = 'abcdefghijklmnopqrstuvwxyz'
freq = {}
for x in zimubiao:
freq[x] = 0
for x in s:
freq[x] = freq[x] + 1
index = 0
for x in zimubiao:
# index = index + pow(float(freq[x]) / len(s), 2)
index = index + float(freq[x] * (freq[x] - 1)) / (len(s) * (len(s) - 1))
return index


def index_of_coincidence_2(s):
'''
计算明文s的拟重合指数,即s中字母的频率与英文字母的统计规律吻合程度
:param s:解出的明文
:return:s的拟重合指数
'''
zimubiao = 'abcdefghijklmnopqrstuvwxyz'
freq = {}
for x in zimubiao:
freq[x] = 0
for x in s:
freq[x] = freq[x] + 1
index = 0
for x in zimubiao:
index = index + float(freq[x]) / len(s) * best_freq[x]
return index


def guessMN():
'''
根据题意,该加密应当会周期使用密钥,该周期是key_a长度和key_k长度的最小公倍数。
遍历周期1到100,分别测试不同周期下各个子密文段的重合指数,然后求平均
:return:无返回值,打印出所有与最佳重合指数相差小于0.01的周期
'''
for l in range(1, 100):
avergage_index = 0
for i in range(l):
s = ''.join([c[j * l + i] for j in range(0, len(c) / l)])
index = index_of_coincidence(s)
avergage_index += index

avergage_index = avergage_index / l - best_index_of_Coincidence
if abs(avergage_index) < 0.01:
print 'l=', l
print avergage_index

print '开始猜测周期'
#guessMN()#结果显示,重合指数得分较高的都是6的整数倍,所以周期极有可能是6
l=55


def decryptChar(c, i, j):
'''
对单个密文字符解密。
:param c: 单个密文字符
:param i: 与字符c相乘的那个密钥
:param j: 用于位移的密钥
:return: 明文字符
'''
i_inv = gm.invert(i, 26)
p = chr((ord(c) - ord('a') - j) * i_inv % 26 + ord('a'))
return p


def decrypt(s, i, j):
'''
用固定的i和j,解密子密文段
:param s: 使用相同i和j加密的子密文段
:param i: 与字符c相乘的那个密钥
:param j: 用于位移的密钥
:return: 明文字符串
'''
p = ''
for c in s:
p += decryptChar(c, i, j)
return p


def guessKey(c):
'''
对子密文段爆破它所使用的i和j
:param c: 子密文段
:return: 无返回值,但是打印拟重合指数最佳的i和j,即解出的明文统计规律与英文字符统计规律最吻合的i和j
'''
for i in range(26):
if i % 2 == 0 or i == 13: #若i与26不互素,则解除的明文不唯一,所以i一定不是2和13的倍数
continue
for j in range(26):
s = decrypt(c, i, j)
# print s
index = index_of_coincidence_2(s)
index = abs(index - 0.065)
if index < 0.01:
print i, j, index

def guessAllKeys():
'''
以l为周期,将完整密文c切分成l个子密文段,对这l个子密文段分别爆破其所使用密钥i和j
:return: 无返回值,但打印出最佳的密钥组合
'''
for i in range(l):
s = ''.join([c[j * l + i] for j in range(0, len(c) / l)])
print i
guessKey(s)

print '开始猜测密钥组合'
#guessAllKeys()
# 根据打印结果,发现最佳组合依次是
# 19,10
# 7,9
# 23,3
# 19,24
# 7,14
# 23,15
# 将l设置成12、18、24或更多,还是可以得到这样的组合的重复
# 现在基本可以确定密钥应该是这样的
key_a = [23, 25, 21,3,19]
key_k = [9, 21, 9, 10, 16,3, 22,13,14,21,15]

#利用key_a, key_k解密完整的密文,得到明文
p = ''
for i in range(len(c)):
p += decryptChar(c[i], key_a[i % 5], key_k[i % 11])
print p
#在最后得到密码frequencyisoeasy

Python3解AES:

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

知识点:

image-20210509202737039

其余部分可以参考

srtiving写的题目杂记6

参考链接:

题目改编自NUCA的Crypto赛题babycrypto

nuca_crypto_babycrypto_writeup

srtiving写的题目杂记6

重合指数——百度百科

ctfshow大牛杯:小二的R54(前半部分)

题目:

整理下得到:

1
2
3
4
5
6
7
8
x, y = [random_prime(2 ^ 1024 - 1, False, 2 ^ 1023) for _ in range(2)]
n = x * y,
tmp = pow(2021 * x + 501 * y, x * y - x - y, x * y),
c = pow(flag, 0o200001, x * y)

n=20947495659013288660808536751393787394664606045798093048128257278988208709333248671898749660848208653968668634891579612784633367362177864996602736258460476691940723323282467207875842974409286563660436709535601954405015261428106261369927836045794170912665351432105165546188591486357060490032334793140396757102052999128194027485573053073959574695808224922102635888141991154365047911830780778957642166757152369955362399379720841279167832886144458760347392316082994786119404006382441787685301119197529946566027319295285387108473752590621030421978808950305190250697199878929419723511578437404000924310974770501204226510397,
tmp = 12911378830212711575909332427930495830030418987483519620282504671823307660633472092466534392403086505995560725428252134905285658936113891795434303336259751169171583600394870893708505805256284455729584616439559184469715186920464999723861722097244025658190194027561300165723184060071016117033960821040587421503448139025974851980482004179865110864844573575034406782936965166402665401330436229441569042660851847498727291447251591027480750458209012729510702196684303778564353025395186191064801000127420683298000173389589468742142444444759536629401472836827952997758216526858512433131954439154124668711408079361172485321041,
c = 13390681135321846035598057088735733735860895610541899486616159864716324918810264721878447895634342127744578566110322466944217562868186608760962032192994397783118528288276520451944892998435079744244578731427626946331165523865930693902700790185275273534104979885060728696532991031786741950704918951536399577118136416956670893081637730646528913282395731901667720418372650030593319596584787752412110672058692368924987360383096340538971725402687347195347344826404005229912821371282465882351660619944919637382790572267512735645269618163597227604601321699186335016345484182059187046972681187078878556533926780789183784240737]

exp:

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
import gmpy2
from z3 import *
from Crypto.Util.number import *

n=20947495659013288660808536751393787394664606045798093048128257278988208709333248671898749660848208653968668634891579612784633367362177864996602736258460476691940723323282467207875842974409286563660436709535601954405015261428106261369927836045794170912665351432105165546188591486357060490032334793140396757102052999128194027485573053073959574695808224922102635888141991154365047911830780778957642166757152369955362399379720841279167832886144458760347392316082994786119404006382441787685301119197529946566027319295285387108473752590621030421978808950305190250697199878929419723511578437404000924310974770501204226510397
tmp=12911378830212711575909332427930495830030418987483519620282504671823307660633472092466534392403086505995560725428252134905285658936113891795434303336259751169171583600394870893708505805256284455729584616439559184469715186920464999723861722097244025658190194027561300165723184060071016117033960821040587421503448139025974851980482004179865110864844573575034406782936965166402665401330436229441569042660851847498727291447251591027480750458209012729510702196684303778564353025395186191064801000127420683298000173389589468742142444444759536629401472836827952997758216526858512433131954439154124668711408079361172485321041
c=13390681135321846035598057088735733735860895610541899486616159864716324918810264721878447895634342127744578566110322466944217562868186608760962032192994397783118528288276520451944892998435079744244578731427626946331165523865930693902700790185275273534104979885060728696532991031786741950704918951536399577118136416956670893081637730646528913282395731901667720418372650030593319596584787752412110672058692368924987360383096340538971725402687347195347344826404005229912821371282465882351660619944919637382790572267512735645269618163597227604601321699186335016345484182059187046972681187078878556533926780789183784240737

x=Int('x')
y=Int('y')
s = Solver()
s.add(inverse(tmp,n)==2021*x+501*y)
s.add(x*y==n)
s.add(x > 1)
s.add(y > 1)
assert s.check()==sat

print('x=',s.model()[x])
print('y=',s.model()[y])

x=int(str(s.model()[x]))
y=int(str(s.model()[y]))
phi = (x-1)*(y-1)
e=65537
print(long_to_bytes(pow(c,inverse(e,phi),n)))

知识点:

后半部分的维吉尼亚还没有解出来。

更新:循环维吉尼亚,密码shosho

-------------本文结束感谢您的阅读-------------