BUUCTF N1BOOK [第七章 CTF之CRYPTO章]LFSR
初次接触流密码 学到了很多
题目给的加密源码:
seed = 0x00000000 # you need to solve this
flag = 'n1book{%x}' % seed
state = seed
mask = 0b10000000000000000000000001010111
def lfsr():
global state, mask
output = state & 1
now = state & mask
new = 0
while now:
new ^= now & 1
now >>= 1
state = (new << 31) | (state >> 1)
return output
for i in range(32):
lfsr()
print ('%x' % state) # 155a796b
了解了一下什么是LFSR:线性反馈移位寄存器
也就是 右移过后最高位会被补充 而补充的过程是通过一系列线性计算
以这道题为例 线性运算其实就是 x32 ^ x7 ^ x5 ^ x3 ^ x2 ^ x1
我们已知 反馈函数和最终序列要解初始序列 这里我想到的有两种方法:
第一种 解32元方程组
这里只是展示大概 因为忘了z3不能直接处理异或运算...要用BitVec...所以打了半天跑不出结果(就当手动过一遍LFSR过程罢)
点击查看代码
from z3 import *
s = Solver()
x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20,x21,x22,x23,x24,x25,x26,\
x27,x28,x29,x30,x31,x32 = \
Ints("x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 x21 x22 x23 x24 x25 x26 x27 x28 x29 x30 x31 x32")
s.add(x32^x7^x5^x3^x2^x1==1)
s.add(1^x8^x6^x4^x3^x2==1)
s.add(1^x9^x7^x5^x4^x3==0)
s.add(0^x10^x8^x6^x5^x4==1)
s.add(1^x11^x9^x7^x6^x5==0)
s.add(0^x12^x10^x8^x7^x6==1)
s.add(1^x13^x11^x19^x8^x7==1)
s.add(1^x14^x12^x10^x9^x8==0)
s.add(0^x15^x13^x11^x10^x9==1)
s.add(1^x16^x14^x12^x11^x10==0)
s.add(1^x17^x15^x13^x12^x11==0)
s.add(0^x18^x16^x14^x13^x12==1)
s.add(1^x19^x17^x15^x14^x13==1)
s.add(1^x20^x18^x16^x15^x14==1)
s.add(1^x21^x19^x17^x16^x15==1)
s.add(1^x22^x20^x18^x17^x16==0)
s.add(0^x23^x21^x19^x18^x17==0)
s.add(0^x24^x22^x20^x19^x18==1)
s.add(1^x25^x23^x21^x20^x19==0)
s.add(0^x26^x24^x22^x21^x20==1)
s.add(1^x27^x25^x23^x22^x21==1)
s.add(1^x28^x26^x24^x23^x22==0)
s.add(0^x29^x27^x25^x24^x23==1)
s.add(1^x30^x28^x26^x25^x24==0)
s.add(0^x31^x29^x27^x26^x25==1)
s.add(1^x32^x30^x28^x27^x26==0)
s.add(0^1^x31^x29^x28^x27==1)
s.add(1^1^x32^x30^x29^x28==0)
s.add(0^0^1^x31^x30^x29==1)
"""
1011111001101110101100111011111
"""
check = s.check()
print(s.model())
# 10101010110100111100101101011
自己由答案推几个发现思路是没问题的...
第二种 直接32次逆向得到初始状态
这个lfsr加密的特性就是每次最高的31位是不会改变的
只是将最低位的值参与运算后反馈到新的最高位而已
所以利用位运算的知识可以较容易的还原
代码:
state = 0b10101010110100111100101101011
mask = 0b10000000000000000000000001010111
"""
(1<<31)-1就是31个1
而(state&((1<<31)-1))<<1 就是取state的第2~32位
由题目给的lfsr算法 我们可以确定每次变换
pre的高31位原封不动右移一位 pre的最低位可能会影响new的值
而最低位只有两种情况 所以稍微判断一下就可以逐步逆向还原了
"""
def decode():
global state,mask
lowbit = (state & (1<<31))>>31
state = (state & ((1<<31)-1))<<1
now = state & mask
new = 0
while now:
new ^= now & 1
now >>= 1
if new == lowbit:
pass
else:
state |= 1
for i in range(32):
decode()
print(hex(state))
总结
作为最基本的流密码题 涵盖了流密码的基本考点 重点是要能理解加密过程的本质(bit) 合理利用位运算逆向求解