建立在他人博客的推文上对于LFSR的初步了解与尝试
LFSR指给定前一状态的输出,将该输出的线性函数再用作输入的移位寄存器。线性反馈移位寄存器(LFSR)归属于移位寄存器(FSR)。
GF(2) 上一个 n 级反馈移位寄存器由 n 个二元存储器与一个反馈函数
f(a1,a2,⋯,an) 组成:
img
移位寄存器三要素:
初始状态:由用户确定
反馈函数:f(a1,a2,⋯,an) 是 n
元布尔函数,即函数的自变量和因变量只取0和1这两个可能值
输出序列
如果反馈函数是线性的,那么我们称其为线性反馈移位寄存器(LFSR):
img
LFSR的输出序列 {an} 满足: 对于 n 级线性反馈移位寄存器,最长周期 为2n − 1 (排除全0),达到最长周期的序列一般称为
m 序列。
实例
假设给定了一个5级的LFSR,其初始状态(a1到a5这五个二元存储器的值)为
(a 1 , a 2 , a 3 , a 4 , a 5 ) = (1, 0, 0, 1, 1)
它的反馈函数为
f (a 1 , a 2 , a 3 , a 4 , a 5 ) = a 4 ⊕ a 1
它的输出过程如下
img
然后 a 6 = a 4 ⊕ a 1 = 1 ⊕ 1 = 0
a 7 = a 5 ⊕ a 2 = 1 ⊕ 0 = 1
所以我们可以由此推出反馈函数 a n = a n − 2 ⊕ a n − 5
对于一个n级 的LFSR来讲,其最大周期为2n − 1
,因此对于我们上面的5级 LFSR来讲,其最大周期为 25 − 1 = 31 .
2018 CISCN 线上赛 oldstreamgame
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 flag = "flag{xxxxxxxxxxxxxxxx}" assert flag.startswith("flag{" )assert flag.endswith("}" )assert len (flag)==14 def lfsr (R,mask ): output = (R << 1 ) & 0xffffffff i=(R&mask)&0xffffffff lastbit=0 while i!=0 : lastbit^=(i&1 ) i=i>>1 output^=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,out)=lfsr(R,mask) tmp=(tmp << 1 )^out f.write(chr (tmp)) f.close()
已知条件:
flag包裹内容为8位十六进制数字也就是32位二进制数也就是我们需要的求的初态
反馈函数已知要转化成数学表达式
已知输出和mask掩码
1 2 3 4 5 6 7 8 9 10 def lfsr (R,mask ): output = (R << 1 ) & 0xffffffff i=(R&mask)&0xffffffff lastbit=0 while i!=0 : lastbit^=(i&1 ) i=i>>1 output^=lastbit return (output,lastbit)
1 2 3 4 5 6 7 8 f=open ("key" ,"w" ) for i in range (100 ): tmp=0 for j in range (8 ): (R,out)=lfsr(R,mask) tmp=(tmp << 1 )^out f.write(chr (tmp)) f.close()
1 2 key=20FDEEF8A4C9F4083F331DA8238AE5ED083DF0CB0E7A83355696345DF44D7C186C1F459BCE135F1DB6C76775D5DCBAB7A783E48A203C19CA25C22F60AE62B37DE8E40578E3A7787EB429730D95C9E1944288EB3E2E747D8216A4785507A137B413CD690C
对flag做了100次循环得到了100个16进制数
判断
mask只有第3、5、8、12、20、27、30、32这几位为1,其余位均为0。
mask与R做按位与运算得到i,当且仅当R的第3、5、8、12、20、27、30、32这几位中也出现1时,i中才可能出现1,否则i中将全为0。
lastbit是由i的最低位向i的最高位依次做异或运算得到的,在这个过程中,所有为0的位我们可以忽略不计(因为0异或任何数等于任何数本身,不影响最后运算结果),因此lastbit的值仅取决于i中有多少个1:当i中有奇数个1时,lastbit等于1;当i中有偶数个1时,lastbit等于0。
当R的第3、5、8、12、20、27、30、32这几位依次异或结果为1时,即R中有奇数个1,因此将导致i中有奇数个1;当R的第3、5、8、12、20、27、30、32这几位依次异或结果为0时,即R中有偶数个1,因此将导致i中有偶数个1。
因此我们可以建立出联系:lastbit等于R的第3、5、8、12、20、27、30、32这几位依次异或的结果。
写成反馈函数,也就是 l a s t b i t = R 3 ⊕ R 5 ⊕ R 6 ⊕ R 12 ⊕ R 20 ⊕ R 27 ⊕ R 30 ⊕ R 32
我们将key全部转成二进制
1 2 3 4 5 6 x='20FDEEF8A4C9F4083F331DA8238AE5ED083DF0CB0E7A83355696345DF44D7C186C1F459BCE135F1DB6C76775D5DCBAB7A783E48A203C19CA25C22F60AE62B37DE8E40578E3A7787EB429730D95C9E1944288EB3E2E747D8216A4785507A137B413CD690C' b=bin (int (x,16 ))[2 :] print (b)print (len (b))
手动再补充2位0
因为是需要反推32位,所以我们只需要取最高位的前32位数据即可
1 32位Key值:00100000111111011110111011111000
img
第 个 输 出 的 的 第 位 未 知
第 个 输 出 的 的 第 位 未 知 以此类推,R的全部32位我们都可以依次求出了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 key = "00100000111111011110111011111000" mask = "10100100000010000000100010010100" R = "" tmp = key for i in range (32 ): n = '?' +key[:31 ] m = int (n[-3 ])^int (n[-5 ])^int (n[-8 ])^int (n[-12 ])^int (n[-20 ])^int (n[-27 ])^int (n[-30 ])^int (tmp[-1 -i]) R += str (m) key = str (m) + key[:31 ] print ("flag{" + hex (int (R[::-1 ],2 )) + "}" )
不是很懂,目前先进行一个大概看看,后续有关lfsr的题目再进行补充
2025NPC CTF river
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 class LFSRStreamCipher : def __init__ (self, key: int ): if not (0 <= key < 2 **16 ): raise ValueError("Key must be a 16-bit integer" ) self .state = key self .poly = 0b1010000000000101 def lfsr_step (self ) -> int : feedback = self .state & 1 self .state >>= 1 if feedback: self .state ^= self .poly return feedback def generate_keystream (self, length: int ) -> bytes : keystream = bytearray () for _ in range (length): byte = 0 for i in range (8 ): byte |= self .lfsr_step() << i keystream.append(byte) return bytes (keystream) def encrypt (self, plaintext: bytes ) -> bytes : """使用密钥流加密""" keystream = self .generate_keystream(len (plaintext)) return bytes (p ^ k for p, k in zip (plaintext, keystream)) def decrypt (self, ciphertext: bytes ) -> bytes : """使用密钥流解密(加密与解密是相同的)""" return self .encrypt(ciphertext) key = 0b1101011010110101 cipher = LFSRStreamCipher(key) ciphertext = cipher.encrypt(flag) print ("Ciphertext:" , ciphertext.hex ())
常规的LFSR题目,加密方式和反馈多项式都给了,并且因为异或具有可逆性,所以只需要再将密文按照这个逻辑即可解密。需要注意的是要在初始化的时候将LFSR内部重置一下。
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 from Crypto.Util.number import *class LFSRStreamCipher : def __init__ (self, key: int ): if not (0 <= key < 2 **16 ): raise ValueError("Key must be a 16-bit integer" ) self .initial_key = key self .poly = 0b1010000000000101 self .reset() def reset (self ): self .state = self .initial_key def lfsr_step (self ) -> int : feedback = self .state & 1 self .state >>= 1 if feedback: self .state ^= self .poly return feedback def generate_keystream (self, length: int ) -> bytes : keystream = bytearray () for _ in range (length): byte = 0 for i in range (8 ): byte |= self .lfsr_step() << i keystream.append(byte) return bytes (keystream) def decrypt (self, ciphertext: bytes ) -> bytes : self .reset() keystream = self .generate_keystream(len (ciphertext)) return bytes (p ^ k for p, k in zip (ciphertext, keystream)) key = 0b1101011010110101 cipher = LFSRStreamCipher(key) ciphertext = 0xbd8b802f4a05ed77abace36b6cf9adbe627d3632edff818c556120ad131b50dbedd0f4af4483 decrypted = cipher.decrypt(long_to_bytes(ciphertext)) print ("Decrypted:" , decrypted)
总结
lfsr的基本原理还是不难看懂的,关键在于各个题目中代码转换成数学公式的能力和反推回去。
码力和理解能力还是太差了(悲