流密码LFSR

[CISCN2018] oldstreamgame

flag = "flag{xxxxxxxxxxxxxxxx}"
assert flag.startswith("flag{")
assert flag.endswith("}")
assert len(flag)==14
# 1101
# (1101 & 0001) | 1
# 0101
def lfsr(R,mask):
    output = (R << 1) & 0xffffffff
    #R向左移位,高位丢弃,末尾补0,保留32位
    i=(R&mask)&0xffffffff
    #保留mask原本为1的位置,使其参与运算,形成lastbit
    lastbit=0
    while i!=0:
        lastbit^=(i&1)
        i=i>>1
    #i的每一位与1进行与运算,再与lastbit进行异或运算
    #lastbit = i[3]^i[5]^i[8]^i[12]^i[20]^i[27]^i[30]^i[32],得到lastbit非0即1
    output^=lastbit
    #output末尾为0,与lastbit进行异或,相当于将lastbit进行末位补位
    return (output,lastbit)

R=int(flag[5:-1],16)
mask = 0b10100100000010000000100010010100

f=open("key","w")
for i in range(100):
    tmp=0
    for j in range(8):
        (R,mask)=lfsr(R,mask)
        tmp=(tmp << 1)^out
    f.write(chr(tmp))
f.close()

打开key文件,取32位,也就是八位十六进制

 key = '00100000111111011110111011111000'
mask = '10100100000010000000100010010100'
加密过程如下
R = ????????????????????????????????
x = int(c[-32])^int(R[-3])^int(R[-5])^int(R[-8])^int(R[-12])^int(R[-20])^int(R[-27])^int(R[-30])
R = ???????????????????????????????X
这样依次进行末位补位
R = ?1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
当进行到第31次加密时,如上述所示,此时我们已知32位提换位,第32位flag未知,根据异或的性质
?1 = key[-1]^R[-3]^R[-5]^R[-8]^R[-12]^R[-20]^R[-27]^R[-30]
R = ?2?1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
?2 = key[-2]^R[-3]^R[-5]^R[-8]^R[-12]^R[-20]^R[-27]^R[-30]
以次类推
flag = ?32?31?30?29?28?27?26?25?24?23?22?21?20?19?18?17?16?15?14?13?12?11?10?9?8?7?6?5?4?3?2?1
最后将flag进行倒置,再转十六进制

解题

第一种解法

#mask = 10100100000010000000100010010100
key = '00100000111111011110111011111000'
c = key
flag = ''
for i in range(32):
    output = "?"+key[:31]
    #?0010000011111101111011101111100
    #?1001000001111110111101110111110
    a = int(c[-1-i])^int(output[-3])^int(output[-5])^int(output[-8])^int(output[-12])^int(output[-20])^int(output[-27])^int(output[-30])
    flag += str(a)
    key = str(a)+key[:31]
b = flag[::-1]
print(hex(int(b,2)))

第二种解法

mask = [1,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0]
s = [0,0,1,0,0,0,0,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,0,0]
suf = []
def bitAnd(a, b):
    return list(map(lambda x,y: int(x)&int(y), a, b))
for i in range(32):
    if bitAnd([0] + suf + s[0:31 - i], mask).count(1) % 2 == s[31 - i]:
        suf = [0] + suf
    else:
        suf = [1] + suf
print(suf)

[AFCTF2018]Tiny LFSR

import sys
from binascii import unhexlify

if(len(sys.argv)<4):
    print("Usage: python Encrypt.py keyfile plaintext ciphername")
    exit(1)

def lfsr(R, mask):
    output = (R << 1) & 0xffffffffffffffff #64位
    i=(R&mask)&0xffffffffffffffff
    lastbit=0
    while i!=0:
        lastbit^=(i&1)
        i=i>>1
    output^=lastbit
    return (output,lastbit)

R = 0
key = ""
with open(sys.argv[1],"r") as f:
    key = f.read()
    R = int(key,16)
    f.close

mask = 0b1101100000000000000000000000000000000000000000000000000000000000

a = ''.join([chr(int(b, 16)) for b in [key[i:i+2] for i in range(0, len(key), 2)]])

f=open(sys.argv[2],"r")
#打开Plain.txt flag.txt文件
ff = open(sys.argv[3],"wb")
#写入cipher.txt flag_encode.txt文件
s = f.read()
#密文
f.close()
lent = len(s)

for i in range(0, len(a)):
    ff.write((ord(s[i])^ord(a[i])).to_bytes(1, byteorder='big'))
    #密文的a位数与lsfr生成的密钥流进行异或

for i in range(len(a), lent):
    tmp=0
    for j in range(8):
        (R,out)=lfsr(R,mask)
        tmp=(tmp << 1)^out
        #tmp进行lfsr的加密
    ff.write((tmp^ord(s[i])).to_bytes(1, byteorder='big'))
    #将密文的后半段与tmp进行异或
ff.close()

首先根据题目所给的Plain.txt 和cipher.txt进行密钥流a的求解

#plain[i] ^ a[i] = cipher[i]
#a[i] = cipher[i] ^ plain[i]
#由于mask位64位,那么推断a也为64位
plain = "0111001101100100011001110110011001101010011010110110000101101000"
cipher = "0111001001000111001000100000000111100011110000001010110010000111"
key = ''
for i in range(64):
    key +=str(int(plain[i])^int(cipher[i]))
#print(key)
from Crypto.Util.number import *
a = "0000000100100011010001010110011110001001101010111100110111101111"
s = "0100100001001101011001010000010011100110110001101011110110011010"
flag1 = ''
for i in range(0, len(a)):
    flag1 += str(((int(s[i])))^((int(a[i]))))
print(flag1)

再根据题目加密过程进行解密

from binascii import unhexlify
def lfsr(R, mask):
    output = (R << 1) & 0xffffffffffffffff #64位
    i=(R&mask)&0xffffffffffffffff
    lastbit=0
    while i!=0:
        lastbit^=(i&1)
        i=i>>1
    output^=lastbit
    return (output,lastbit)

R = 0
key = "0123456789abcdef"
R = int(key,16) 
mask = 0b1101100000000000000000000000000000000000000000000000000000000000
a = ''.join([chr(int(b, 16)) for b in [key[i:i+2] for i in range(0, len(key), 2)]])
f=open("flag_encode.txt","rb").read()
lent = len(f)
flag = ''
for i in range(len(a), lent):
    tmp=0
    for j in range(8):
        (R,out)=lfsr(R,mask)
        tmp=(tmp << 1)^out
    flag +=(chr(tmp^f[i]))
print(flag)

De1CTF2019]Babylfsr

import hashlib
from secret import KEY,FLAG,MASK

assert(FLAG=="de1ctf{"+hashlib.sha256(hex(KEY)[2:].rstrip('L')).hexdigest()+"}")
assert(FLAG[7:11]=='1224')

LENGTH = 256

assert(KEY.bit_length()==LENGTH)
assert(MASK.bit_length()==LENGTH)

def pad(m):
    pad_length = 8 - len(m)
    return pad_length*'0'+m

class lfsr():
    def __init__(self, init, mask, length):
        self.init = init
        self.mask = mask
        self.lengthmask = 2**(length+1)-1

    def next(self):
        nextdata = (self.init << 1) & self.lengthmask 
        i = self.init & self.mask & self.lengthmask 
        output = 0
        while i != 0:
            output ^= (i & 1)
            i = i >> 1
        nextdata ^= output
        self.init = nextdata
        return output

if __name__=="__main__":
    l = lfsr(KEY,MASK,LENGTH)
    r = ''
    for i in range(63):
        b = 0
        for j in range(8):
            b = (b<<1)+l.next()
        r += pad(bin(b)[2:])
    with open('output','w') as f:
        f.write(r)
#r = 001010010111101000001101101111010000001111011001101111011000100001100011111000010001100101110110011000001100111010111110000000111011000110111110001110111000010100110010011111100011010111101101101001110000010111011110010110010011101101010010100101011111011001111010000000001011000011000100000101111010001100000011010011010111001010010101101000110011001110111010000011010101111011110100011110011010000001100100101000010110100100100011001000101010001100000010000100111001110110101000000101011100000001100010

key和mask的位数为256,唯一的已知量为504位的lsfr的加密序列,这样的话我们相当于得到了两组的加密序列,只是第二组加密后的序列缺少了8位,但由于位数较少,我们可以动过爆破得到符合条件的一组

assert(FLAG=="de1ctf{"+hashlib.sha256(hex(KEY)[2:].rstrip('L')).hexdigest()+"}")
assert(FLAG[7:11]=='1224')

根据lsfr的反馈函数可以由此来计算mask

 

三组矩阵,我们相当于已经知道了两组,也就是r的前256位为已知的序列,通过lfsr的加密计算得到后256位的序列,那么想要求解mask就是相当于用后256位乘前256位的逆矩阵

得到mask的值后,正常求解即可

import itertools, hashlib, numpy as np

def bin2int(a):
    return reduce(lambda x,y: x*2+y, a)
#进行lfsr的解密
def bitAnd(a, b):
    assert len(a) == len(b)
    return list(map(lambda x,y: int(x)&int(y), a, b))

def test(padding):
    s = [int(x) for x in '001010010111101000001101101111010000001111011001101111011000100001100011111000010001100101110110011000001100111010111110000000111011000110111110001110111000010100110010011111100011010111101101101001110000010111011110010110010011101101010010100101011111011001111010000000001011000011000100000101111010001100000011010011010111001010010101101000110011001110111010000011010101111011110100011110011010000001100100101000010110100100100011001000101010001100000010000100111001110110101000000101011100000001100010'] + padding

    M = matrix(GF(2), 256, 256)
    T = vector(GF(2), 256)

    for i in range(len(s) - 256):
        M[i] = s[i : i + 256]
        T[i] = s[i+256]
    try:
        mask = M.inverse() * T
    except:
        return

    suf = []
    for i in range(256):
        if bitAnd([0] + suf + s[0:255 - i], mask).count(1) % 2 == s[255 - i]:
            suf = [0] + suf
        else:
            suf = [1] + suf

    key = hex(bin2int(suf))[2:]
    sha = hashlib.sha256(key.encode()).hexdigest()

    if sha[:4] == '1224':
        print('de1ctf{' + sha + '}')
#爆破后八位数字获取
for x in itertools.product([0, 1], repeat = 8):
    test(list(x))