看到帖子上的一个题,看WP样子说是暴力的,程序很长没仔细看,感觉可以不用暴力。
from random import shuffle
from secret import secret_msg
ALPHABET = '0123456789abcdef'
class Cipher:
def __init__(self, key):
self.key = key
self.n = len(self.key)
self.s = 7
def add(self, num1, num2):
res = 0
for i in range(4):
res += (((num1 & 1) + (num2 & 1)) % 2) << i
num1 >>= 1
num2 >>= 1
return res
def encrypt(self, msg):
key = self.key
s = self.s
ciphertext = ''
for m_i in msg:
c_i = key[self.add(key.index(m_i), s)]
ciphertext += c_i
s = key.index(m_i)
return ciphertext
plaintext = b'The secret message is:'.hex() + secret_msg.hex()
key = list(ALPHABET)
shuffle(key)
cipher = Cipher(key)
ciphertext = cipher.encrypt(plaintext)
print(ciphertext)
#85677bc8302bb20f3be728f99be0002ee88bc8fdc045b80e1dd22bc8fcc0034dd809e8f77023fbc83cd02ec8fbb11cc02cdbb62837677bc8f2277eeaaaabb1188bc998087bef3bcf40683cd02eef48f44aaee805b8045453a546815639e6592c173e4994e044a9084ea4000049e1e7e9873fc90ab9e1d4437fc9836aa80423cc2198882a
加密过程比较简单(虽然写得比较复杂),先把明文转16进制,然后从key里找对应的索引,用索引异或s后得到密文的索引。key是shuffle生成的。明文的头部已经给出,可以通过这些明密对应关系求key
这里密文第3个和明文第3个都是6也就是明文密文索引相同则前一个字符4的索引是0,如果量够大就可以计算出全部的key 。所以这里用z3来一把梭
先把第个字符(0-f)每个给一个索引变量,然后根据明文密文计算 a[i]^seed == a[j] (比如第1个字符5的索引与seed 7异或后得到8的索引,a[5]^7 == a[8])
求出key以后,密文的索引异或seed得到的就是明文的索引
c = '85677bc8302bb20f3be728f99be0002ee88bc8fdc045b80e1dd22bc8fcc0034dd809e8f77023fbc83cd02ec8fbb11cc02cdbb62837677bc8f2277eeaaaabb1188bc998087bef3bcf40683cd02eef48f44aaee805b8045453a546815639e6592c173e4994e044a9084ea4000049e1e7e9873fc90ab9e1d4437fc9836aa80423cc2198882a'
#m = b'The secret message is:'.hex() + secret_msg.hex()
#key = '0123456789abcdef' shuffle(key)
#c_i = key[self.add(key.index(m_i), s)]
#s = key.index(m_i)
key = [0 for i in range(16)]
m1 = b'The secret message is:'.hex()
s = 7
keystr = '0123456789abcdef'
from z3 import *
#给16个字符每个分配一个索引变量,根据明文密文列公式计算索引值
a = [BitVec(f'a_{i}', 4) for i in range(16)]
s = Solver()
for i in range(1,16):
for j in range(i):
s.add(a[i] != a[j])
seed = 7
for i,v in enumerate(m1):
m_i = int(v,16)
c_i = int(c[i], 16)
s.add( (a[m_i]^seed) == a[c_i])
seed = a[m_i]
print(s.check())
d = s.model()
print(d)
for i in range(16):
key[d[a[i]].as_long()] = keystr[i]
print(key)
seed = 7
m = ''
for v in c:
seed ^=key.index(v)
m += key[seed]
print(bytes.fromhex(m))
#b"The secret message is: Nice job! I hope you enjoyed the challenge. Here's your flag: DUCTF{d1d_y0u_Us3_gu3ss1nG_0r_l1n34r_4lg3bRA??}"