CTF竞赛密码学之 LFSR

news2024/10/6 8:22:39

概述:

线性反馈移位寄存器(LFSR)归属于移位寄存器(FSR),除此之外还有非线性移位寄存器(NFSR)。移位寄存器是流密码产生密钥流的一个主要组成部分。

G F ( 2 ) GF(2) GF(2)上一个n级反馈移位寄存器由n个二元存储器与一个反馈函数 f ( a 1 , a 2 , . . . , a n ) f(a_1,a_2,...,a_n) f(a1,a2,...,an)组成,如下图所示。

FSR.png

移位寄存器的三要素:* 初始状态:由用户确定* 反馈函数: f ( a 1 , a 2 , . . . , a n ) f(a_1,a_2,...,a_n) f(a1,a2,...,an)是n元布尔函数,即函数的自变量和因变量只取0和1这两个可能值* 输出序列

如果反馈函数是线性的,那么我们称其为 LFSR,如下图所示:

LFSR.png

LFSR的输出序列{ a n a_n an }满足:

f ( a 1 , a 2 , . . . , a n ) = c 1 a n ⊕ c 2 a n − 1 ⊕ . . . ⊕ c n a 1 f(a_1,a_2,...,a_n) = c_1a_n⊕c_2a_{n-1}⊕...⊕c_na_1 f(a1,a2,...,an)=c1anc2an1...cna1* a n + 1 = c 1 a n ⊕ c 2 a n − 1 ⊕ . . . ⊕ c n a 1 a{n+1} = c_1a_n⊕c_2a{n-1}⊕...⊕c_na_1 an+1=c1anc2an1...cna1* a n + 2 = c 1 a n + 1 ⊕ c 2 a n ⊕ . . . ⊕ c n a 2 a{n+2} = c_1a{n+1}⊕c_2a_n⊕...⊕c_na_2 an+2=c1an+1c2an...cna2* …* a n + i = c 1 a n + i − 1 ⊕ c 2 a n + i − 2 ⊕ . . . ⊕ c n a i a{n+i} = c_1a{n+i-1}⊕c_2a_{n+i-2}⊕...⊕c_na_i an+i=c1an+i1c2an+i2...cnai(i = 1,2,3,…)

举例:

下面是一个5级的线性反馈移位寄存器,其初始状态为 ( a 1 , a 2 , . . . , a n ) = ( 1 , 0 , 0 , 1 , 1 ) (a_1,a_2,...,a_n)= (1,0,0,1,1) (a1,a2,...,an)=(1,0,0,1,1)

例图.png

反馈函数为: a 5 + i = a 3 + i ⊕ a i a{5+i} = a{3+i}⊕a_i a5+i=a3+iai,(i = 1,2,…)可以得到输出序列为:

1001101001000010101110110001111 100110…

周期为31。

对于 n 级线性反馈移位寄存器,最长周期为 2 n − 1 2^n-1 2n1(排除全零)。达到最长周期的序列一般称为 m 序列

本文涉及相关实验:[CTFCrypto练习之替换密码](https://www.hetianlab.com/expc.do?ec=ECID172.19.104.182015011915454100001&pk_campaign=freebuf-
wemedia)(本实验主要介绍了CTFCrypto练习之替换密码,通过本实验的学习,你能够了解CTF竞赛中的密码学题型,掌握凯撒密码破解方法,学会基于频率的替换密码破解方法。)

解决LFSR问题

Part(1) 2018 强网杯 Streamgame1

考点:已知反馈函数,输出序列,求逆推出初始状态

题目:from flag import flagassert flag.startswith(“flag{”)assert flag.endswith(“}”)# 作用:判断字符串是否以指定字符 开头或结尾assert len(flag)==25def lfsr(R,mask):output = (R << 1) & 0xffffff #将R向左移动1位,bin(0xffffff)='0b111111111111111111111111’i=(R&mask)&0xffffff#按位与运算符&:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0lastbit=0while i!=0:lastbit^=(i&1) #按位异或运算,得到输出序列i=i>>1output^=lastbit#将输出值写入 output的后面return (output,lastbit)R=int(flag[5:-1],2)#flag为二进制数据mask= 0b1010011000100011100f=open(“key”,“ab”) #以二进制追加模式打开for i in range(12):tmp=0for j in range(8):(R,out)=lfsr(R,mask)tmp=(tmp << 1)^outf.write(chr(tmp)) #将lfsr输出的序列每8个二进制为一组,转化为字符,共12组f.close()考点:def lfsr(R,mask):output = (R << 1) & 0xffffffi=(R&mask)&0xfffffflastbit=0while i!=0:lastbit^=(i&1) i=i>>1 # R和mask进行异或操作,得到输出序列值output^=lastbit #将输出值设置为output的最后一位return (output,lastbit)题目已知条件为 flag长度为19bits,mask长度也为19bits.

由LFSR的输出序列{ a n a_n an }满足的条件:* a n + i = c 1 a n + i − 1 ⊕ c 2 a n + i − 2 ⊕ . . . ⊕ c n a i a{n+i} = c_1a{n+i-1}⊕c_2a_{n+i-2}⊕...⊕c_na_i an+i=c1an+i1c2an+i2...cnai(i = 1,2,3,…)

可知,输出值 a n + i a{n+i} an+i的结果与c的值相关,即题目中的mask。只有当c的值为1时, c 1 a n + i − 1 , . . . , c n a i c_1a{n+i-1},...,c_na_i c1an+i1,...,cnai的值才可能为1

题目中mask中只有第(3,4,5,9,13,14,17,19)位为1,其余都是0(mask这里右边才是第一位,从右往左增大)

现在我们的目的就是为了求出前19位seed的值,而我们已知了seed后面输出序列的值(题目中给的附件key.txt)。那么我们逆推就能得到seed的值了。lfsr(R,mask)函数执行的是19bits的值。那么我们获取到输出序列前19bits值,即:

key = 0101010100111000111

现在需要计算 a 19 a{19} a19的值,假设我们将 R =
a 19010101010011100011 a{19}010101010011100011 a19010101010011100011,进行lfsr(R,mask)运算,那么我们将得到输出值为 key[-1]=1。

因为mask中只有第(3,4,5,9,13,14,17,19)位为1,所以线性反馈函数只取这几位对应的a值

1= a 19 a_{19} a19(R[-3])(R[-4])(R[-5])(R[-9])(R[-13])(R[-14])^(R[-17])

得1= a 19 a{19} a19^0,得到 a 19 a{19} a19=1

同理:R = a 18 a 1901010101001110001 a{18}a{19}01010101001110001 a18a1901010101001110001 的输出值为 key[-2]=1,求得 a 18 a_{18} a18=1

第一种方法#python3from Crypto.Util.number importf = open(‘key.txt’,‘rb’).read()r = bytes_to_long(f)bin_out = bin®[2:].zfill(128)R = bin_out[:19]#获取输出序列中与掩码msk长度相同的值print®mask = ‘1010011000100011100’#顺序 c_n,c_n-1,。。。,c_1key ='0101010100111000111’R = ‘‘for i in range(19):output = ‘x’+key[:18]out = int(key[-1])int(output[-3])int(output[-4])int(output[-5])int(output[-9])int(output[-13])int(output[-14])^int(output[-17])R += str(out)key = str(out)+key[:18]print(‘flag{’+R[::-1]+’}’)### 第二种方法

seed值只可能是0和1构成,所以猜就行了。from Crypto.Util.number importimport os,sysos.chdir(sys.path[0])f = open(‘key.txt’,‘rb’).read()c = bytes_to_long(f)bin_out = bin©[2:].zfill(128) #将key文本内容转换为 2 进制数,每个字节占 8 位R = bin_out[0:19]#取输出序列的前19位mask = 0b1010011000100011100def lfsr(R,mask):output = (R << 1) & 0xffffffffi=(R&mask)&0xfffffffflastbit=0while i!=0:lastbit=(i&1)i=i>>1output=lastbitreturn (output,lastbit)#根据生成规则,初始状态最后一位拼接输出序列#我们可以猜测seed的第19位(0或1),如果seed19+R[:18]输出值等于R[:19],那么就可以确定seed值了def decry():cur = bin_out[0:19]#前19位 2 进制数res = ''for i in range(19):if lfsr(int(‘0’+cur[0:18],2),mask)[0] == int(cur,2):res += '0’cur = ‘0’+cur[0:18]else:res += '1’cur = ‘1’ + cur[0:18]return int(res[::-1],2)r = decry()print(bin®)### 第三种方法import os,sysos.chdir(sys.path[0])from Crypto.Util.number import *key = '0101010100111000111’mask = 0b1010011000100011100R = ""index = 0key = key[18] + key[:19]while index < 19:tmp = 0for i in range(19):if mask >> i & 1:tmp ^= int(key[18 - i])R += str(tmp)index += 1key = key[18] + str(tmp) + key[1:18]print (R[::-1])## Part(1) 2018 强网杯 Streamgame2

考点:已知反馈函数,输出序列,求逆推出初始状态

题目from flag import flagassert flag.startswith(“flag{”)assert flag.endswith(“}”)assert len(flag)==27def lfsr(R,mask):output = (R << 1) & 0xffffffi=(R&mask)&0xfffffflastbit=0while i!=0:lastbit=(i&1)i=i>>1output=lastbitreturn (output,lastbit)R=int(flag[5:-1],2)mask=0x100002f=open(“key”,“ab”)for i in range(12):tmp=0for j in range(8):(R,out)=lfsr(R,mask)tmp=(tmp << 1)^outf.write(chr(tmp))f.close()解法与 2018 强网杯 Streamgame1不能说是毫不相干,简直是一m0一样from Crypto.Util.number import*bin_out = open(‘key.txt’,‘rb’).read()key = bin(bytes_to_long(bin_out))[2:]# print(key[0:21])# print(bin(int(‘0x100002’,16)))key = '101100101110100100001’mask= '100000000000000000010’R = ''for i in range(21):output = ‘?’ + key[:20]ans = int(key[-1]) ^ int(output[-2])R += str(ans)key = str(ans) + key[:20]print(R[::-1])## Part(3) [CISCN2018]oldstreamgame

考点:和前面的题目一样都是给出输出序列和反馈函数,求seed(初始状态)

题目:flag = “flag{xxxxxxxxxxxxxxxx}“assert flag.startswith(“flag{”)assert flag.endswith(”}”)assert len(flag)==14def lfsr(R,mask):output = (R << 1) & 0xffffffffi=(R&mask)&0xfffffffflastbit=0while i!=0:lastbit=(i&1)i=i>>1output=lastbitreturn (output,lastbit)R=int(flag[5:-1],16)mask = 0b10100100000010000000100010010100f=open(“key”,“w”)for i in range(100):tmp=0for j in range(8):(R,out)=lfsr(R,mask)tmp=(tmp << 1)^outf.write(chr(tmp))f.close()exp#python3 import os,sysos.chdir(sys.path[0])from Crypto.Util.number importf = open(‘key.txt’,‘rb’).read()key = bytes_to_long(f)bin_out = bin(key)[2:].zfill(1008)# print(bin_out[:32]) #前32位就是keykey ='00100000111111011110111011111000’mask = '10100100000010000000100010010100’R = ''for i in range(32):output = ‘x’ + key[:31]ans = int(key[-1]) ^ int(output[-3]) ^ int(output[-5]) ^ int(output[-8]) ^ int(output[-12]) ^ int(output[-20]) ^ int(output[-27]) ^ int(output[-30])R += str(ans)key = str(ans) + key[:31]R = str(hex(int(R[::-1],2))[2:])flag = “flag{” + R + "}"print(flag)## Part(4) [De1CTF2019]Babylfsr

考点:B-M 算法

题目给了度为256的lfsr,和输出长度为504的输出序列,并提示了FLAG的特征。

在CTFWiki中有介绍道 B-M 算法:如果我们知道了长度为 2n 的输出序列,那么就可以通过构造矩阵来求出 mask,时间复杂度: O ( n 2 ) O(n^2) O(n2)
次比特操作,空间复杂度: O ( n ) O(n) O(n) 比特。

题目:import hashlibfrom secret import KEY,FLAG,MASKassert(FLAG==“de1ctf{”+hashlib.sha256(hex(KEY)[2:].rstrip(‘L’)).hexdigest()+“}”)assert(FLAG[7:11]==‘1224’)LENGTH = 256assert(KEY.bit_length()==LENGTH)assert(MASK.bit_length()LENGTH)def pad(m):pad_length = 8 - len(m)return pad_length*‘0’+mclass lfsr():def init(self, init, mask, length):self.init = initself.mask = maskself.lengthmask = 2**(length+1)-1def next(self):nextdata = (self.init << 1) & self.lengthmask i = self.init & self.mask & self.lengthmask output = 0while i != 0:output ^= (i & 1)i = i >> 1nextdata ^= outputself.init = nextdatareturn outputif name"main":l = lfsr(KEY,MASK,LENGTH)r = ''for i in range(63):b = 0for j in range(8):b = (b<<1)+l.next()r += pad(bin(b)[2:])with open(‘output’,‘w’) as f:f.write®> 这题中输出序列只给出了504个值,根据 B-M 算法,我们需要确定512个值 (即长度为2n的序列,n为lfsr的度,这里是256) 才能求出 mask

,所以我们可以爆破序列后面缺失的 8 位,可以得到 256 种 mask 可能值,用这 256 个 mask 恢复出 256 个key
值,再用限制条件筛选出 flag.#sageimport hashlibkey = ‘001010010111101000001101101111010000001111011001101111011000100001100011111000010001100101110110011000001100111010111110000000111011000110111110001110111000010100110010011111100011010111101101101001110000010111011110010110010011101101010010100101011111011001111010000000001011000011000100000101111010001100000011010011010111001010010101101000110011001110111010000011010101111011110100011110011010000001100100101000010110100100100011001000101010001100000010000100111001110110101000000101011100000001100010’#将二进制数据填充为8位def pad(x):pad_length = 8 - len(x)return ‘0’pad_length+x# 获取 256个 key 可能值def get_key(mask,key):R = ""index = 0key = key[255] + key[:256]while index < 256:tmp = 0for i in range(256):if mask >> i & 1:# tmp ^= int(key[255 - i])tmp = (tmp+int(key[255-i]))%2R = str(tmp) + Rindex += 1key = key[255] + str(tmp) + key[1:255]return int(R,2)# 将二进制流转化为十进制def get_int(x):m=''for i in range(256):m += str(x[i])return (int(m,2))# 获取到256个 mask 可能值,再调用 get_key()函数,获取到key值,将结果导入到 sm 中sm = []for pad_bit in range(2**8): #爆破rr中缺失的8位r = key+pad(bin(pad_bit)[2:])index = 0a = []for i in range(len®):a.append(int(r[i])) #将 r 转换成列表a = [0,0,1,…,]格式res = []for i in range(256):for j in range(256):if a[i+j]==1:res.append(1)else:res.append(0)sn = []for i in range(256):if a[256+i]==1:sn.append(1)else:sn.append(0)MS = MatrixSpace(GF(2),256,256)#构造 256 * 256 的矩阵空间MSS = MatrixSpace(GF(2),1,256) #构造 1 * 256 的矩阵空间A = MS(res)s = MSS(sn) #将 res 和 sn 的值导入矩阵空间中try:inv = A.inverse()# 求A 的逆矩阵except ZeroDivisionError as e:continuemask = sinv #构造矩阵求mask,B-M 算法# print(mask[0])#得到 256 个 mask 值(),type元组# print(get_int(mask[0]))# print(key_list)# print(key[:256])# print(hex(solve(get_int(mask[0]),key[:256])))# break sm.append(hex(get_key(get_int(mask[0]),key[:256]))) # 通过限制条件确定 最终 的flag值for i in range(len(sm)):FLAG = hashlib.sha256(sm[i][2:].encode()).hexdigest()if FLAG[:4]==‘1224’:print(‘flag{’+FLAG+’}')output:flag{1224473d5e349dbf2946353444d727d8fa91da3275ed3ac0dedeb7e6a9ad8619}上面是我关于LFSR学习的一点总结,希望对大家有所帮助,后面会介绍关于LFSR更多的知识点.

最后

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

同时每个成长路线对应的板块都有配套的视频提供:


当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。

因篇幅有限,仅展示部分资料,有需要的小伙伴,可以【点下方卡片】免费领取:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/859960.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

matlab使用教程(12)—随机数种子和随机数流

1.生成可重复的随机数 1.1指定种子 本示例显示如何通过首先指定种子来重复生成随机数数组。每次使用相同种子初始化生成器时&#xff0c;始终都可以获得相同的结果。首先&#xff0c;初始化随机数生成器&#xff0c;以使本示例中的结果具备可重复性。 rng( default ); 现在…

django实现登录和登录的鉴权

1、创建数据库的管理员表 在models.py 中定义admin表&#xff0c;为了简单&#xff0c;表里只有用户名和密码还有默认加的id 三个字段 from django.db import models# Create your models here.class Admin(models.Model):username models.CharField(verbose_name"用户…

新利好带动 POSE 持续上扬,月内几近翻倍

PoseiSwap 是 Nautilus Chain 上的首个 DEX&#xff0c;得益于 Nautilus Chain 的模块化 Layer3 构架&#xff0c;PoseiSwap 正在基于 zk-Rollup 方案构建全新的应用层&#xff0c;并基于此构建隐私、合规等全新的特性&#xff0c;为未来其布局 RWA 领域推动 Web2、Web3 世界的…

布谷鸟配音:一站式配音软件

这是一款智能语音合成软件&#xff0c;可以快速将文字转换成语音&#xff0c;拥有多种真人模拟发音&#xff0c;可以选择不同男声、女声、童声&#xff0c;以及四川话、粤语等中文方言和外语配音&#xff0c;并且可对语速、语调、节奏、数字读法、多音字、背景音等进行全方位设…

【gridsample】地平线如何支持gridsample算子

文章目录 1. grid_sample算子功能解析1.1 理论介绍1.2 代码分析1.2.1 x,y取值范围[-1,1]1.2.2 x,y取值范围超出[-1,1] 2. 使用grid_sample算子构建一个网络3. 走PTQ进行模型转换与编译 实操以J5 OE1.1.60对应的docker为例 1. grid_sample算子功能解析 该段主要参考&#xff1a;…

最大子数组和——力扣53

文章目录 题目描述解法一 动态规划题目描述 解法一 动态规划 int maxSubArray(vector<int>& nums){int pre=0, res=nums

spring boot策略模式实用: 告警模块为例

spring boot策略模式实用: 告警模块 0 涉及知识点 策略模式, 模板方法, 代理, 多态, 反射 1 需求概括 场景: 每隔一段时间, 会获取设备运行数据, 如通过温湿度计获取到当前环境温湿度;需求: 对获取回来的进行分析, 超过配置的阈值需要产生对应的告警 2 方案设计 告警的类…

详解双端队列单调队列

1. 双端队列 双端队列&#xff08;Double-ended Queue&#xff09;&#xff0c;简称Deque&#xff0c;是一种具有特殊功能的线性数据结构。它支持从两端进行元素的插入和删除操作&#xff0c;因此可以在队列和栈之间灵活地切换操作。双端队列在编程中经常用于需要在队列和栈之间…

MySQL多表连接查询2

目录 1 所有有门派的人员信息 2 列出所有用户&#xff0c;并显示其机构信息 3 列出不入派的人员 4 所有没人入的门派 5 列出所有人员和门派的对照关系 6 列出所有没入派的人员和没人入的门派 7 求各个门派对应的掌门人名称: ​8 求所有当上掌门人的平均年龄: 9 求所…

6.4 (通俗易懂)可视化详解多通道 多通道输入输出卷积代码实现

以前对多通道和多通道输入输出的卷积操作不理解&#xff0c;今天自己在草稿纸上画图推理了一遍&#xff0c;终于弄懂了。希望能帮助到大家。 多通道可视化 一通道的2x2矩阵 torch.Size([2,2]) 相当于 torch.Size([1,2,2])&#xff0c;是一通道的2x2矩阵 二通道的 2x2矩阵 …

go-zero 是如何实现令牌桶限流的?

原文链接&#xff1a; 上一篇文章介绍了 如何实现计数器限流&#xff1f;主要有两种实现方式&#xff0c;分别是固定窗口和滑动窗口&#xff0c;并且分析了 go-zero 采用固定窗口方式实现的源码。 但是采用固定窗口实现的限流器会有两个问题&#xff1a; 会出现请求量超出限…

断续模式(DCM)与连续模式(CCM)

断续模式&#xff08;DCM&#xff09;与连续模式&#xff08;CCM)是开关电源最常用的两种工作模式。当初级开关管导通前&#xff0c;初级绕组还存在能量&#xff0c;不完全传递到次级&#xff0c;这种情况就叫连续模式。若初级绕组能量完全传递到次级&#xff0c;则为断续模式。…

Linux与安卓安全对抗

导读大家都知道安卓是基于Linux内核&#xff0c;而且大家也知道Linux的安全性是公认的&#xff0c;那为什么和Linux有着类似嫡系关系的安卓却一直被人诟病不安全呢&#xff1f;要想说清楚这个问题&#xff0c;我们需要了解一下安卓和Linux到底是什么关系&#xff0c;而且这两个…

中国信通院高质量数字化转型产品及服务全景图发布,合合信息多项AI产品入选

随着5G、人工智能、大数据等新一代技术的发展&#xff0c;企业在商业竞争中正面临更多不确定性。中国信通院高度关注企业数字化转型中遇到的痛点&#xff0c;发起“铸基计划-高质量数字化转型行动”&#xff0c;链接企业数字化转型供、需两侧的发展需求&#xff0c;以期推动国家…

MySQL—缓存

目录标题 为什么要有Buffer Poolbuffer pool有多大buffer pool缓存什么 如何管理Buffer Pool如何管理空闲页如何管理脏页如何提高缓存命中率预读失效buffer pool污染 脏页什么时候会被刷入到磁盘 为什么要有Buffer Pool 虽然说MySQL的数据是存储在磁盘中&#xff0c;但是也不能…

C++——缺省参数

缺省参数的定义 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数的时候&#xff0c;如果没有指定实参&#xff0c;则采用该形参的缺省值&#xff0c;否则使用指定的实参。 void Func(int a 0) {cout << a << endl; } int main() { Func()…

【C++学习手札】new和delete看这一篇就够了!

​ 食用指南&#xff1a;本文在有C基础的情况下食用更佳 &#x1f340;本文前置知识&#xff1a; C类 ♈️今日夜电波&#xff1a; Prover—milet 1:21 ━━━━━━️&#x1f49f;──────── 4:01 …

OI易问卷协助企业服务好员工,收集员工反馈与信息

OI易问卷——企业问卷调查工具 OI易问卷&#xff0c;是群硕专为企业打造&#xff0c;对内服务员工的调查问卷。 集成于办公联合创新平台&#xff0c;并进一步帮助客户实现与微信或企业微信等其他平台的对接。 可以有效促进员工服务数字化&#xff0c;提高各部门工作效率&…

mysql的相关指令

mysql的相关指令 DML 数据操作语言DQL数据查询 mysql -uroot -p //启动数据库 show databases; //查看有哪些数据库 use 数据库名; //使用某个数据库 show tables; //查看数据库内有哪些表 exit; //退出mysql的命令环境 create database 数据库名称 charset utf8; //创建数据…

四项代表厂商,Kyligence 入选 Gartner 数据及人工智能相关领域多项报告

近日&#xff0c;全球权威的技术研究与咨询公司 Gartner 发布了《2023 年中国数据、分析及人工智能技术成熟度曲线》、《2023 年分析与商业智能技术成熟度曲线报告》、《2023 年数据管理技术成熟度曲线报告》&#xff0c;Kyligence 分别入选这三项报告的指标平台 Metrics Store…