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) 合理利用位运算逆向求解

posted @ 2023-10-01 13:10  N0zoM1z0  阅读(112)  评论(0编辑  收藏  举报