Streamcipher Learning1

Streamcipher Learning

LFSR

简介

对于给定的初状态(a1 , ... ,an)和反馈函数f

[反馈函数一般为ai+n=\(\sum_{j=1}^nc_ja_{i+n-j}\)]

有f(ai , ... ,ai+n-1) = (ai+1 , ... ,ai+n)

考虑到f是线性函数,我们将其表示为矩阵的形式

=>(ai+1 , ... ,ai+n) = A(ai , ... ,ai+n-1)

而在学习了矩阵后我们知道移位运算,取位运算,异或运算均能看出线性变换,能够由矩阵乘法表示,这就将本来抽象的位运算转化为了熟悉的矩阵运算

对几种伪随机数生成器的分析都可能会用到这种思想

为了使得密钥流输出更加复杂,会对lfsr进行一些变化,使其成为非线性反馈移位寄存器,常见的有三种:

1.非线性组合生成器,对多个lfsr使用一个非线性组合函数

2.非线性滤波器,对一个lfsr输出使用一个非线性组合函数

3.钟控生成器,使用一个或多个lfsr控制其它lfsr输出

下面我们考虑lfsr的生成周期

通常N位的线性反馈寄存器最多有 2N个不同的状态。但是如果出现初值为N个0的情况,线性反馈寄存器陷入死循环,要排除掉。所以N位线性反馈寄存器能产生最长的不重复序列为 2N-1

引入线性变换的特征多项式f(x)=xn-\(\sum_{i=1}^{n}c_ix^{n-i}\)

定义互反多项式为f'(x)=xnf(\(\frac{1}{x}\))

已知某个n级线性反馈移位寄存器的特征多项式,那么该序列对应的生成函数为A(x)=\(\frac{p(x)}{f'(x)}\)

p(x)=\(\sum_{i=1}^n(c_{n-i}x^{n-i}\sum_{j=1}^ia_jx^{j-1})\)

序列的周期为生成函数既约真分式的分母的周期

达到最长周期的序列称为m序列

首先python实现一下lfsr的加密过程

实现

def lfsr(seed,mask):
    state=seed
    Mask=int(mask,2)
    statelen=2**len(mask)-1
    t=state&Mask
    out=0
    while t:
        out^=t&1
        t=t>>1
    state=(state<<1^out)&statelen
    return state,out

逆向

下面分别采用位运算和矩阵运算(本质是一样的)对lfsr进行逆向

我们已知生成的连续len(初态)的输出序列(这里为了方便使用(alen(初态)+1,···,a2len(初态)),和掩码

1.矩阵方式

c=''
mask=''
Mask=Matrix.zero(len(mask))
for i in range(len(mask)-1):
	Mask[i,i+1]=1
for i in range(len(mask)):
	Mask[len(mask)-1,i]=mask[i]
Mask=Matrix(GF(2),Mask)
v=[]
for i in range(len(c)):
	v.append(c[i])
V=vector(GF(2),v)
m=Mask^(-1)*V

2.位运算

c=''
c=int(c,2)
def backtrace(state, mask):
    mask=int(mask,2)
    mask = ((mask & (2**7-1)) << 1) + 1
    i = state & mask
    outPut = 0
    while i != 0:
        outPut ^= (i & 1)
        i = i >> 1
    state >>= 1
    return (outPut <<7) + state
for i in range(8):
    c=backtrace(c,mask)
print(bin(c)[2:].rjust(8,'0'))

在位运算操作的时候可以发现mask的首位不为0才能还原,用矩阵同样会发现当首位为1时矩阵是不满秩的,很显然因为第一列是全0的

示例

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)
        
#001010010111101000001101101111010000001111011001101111011000100001100011111000010001100101110110011000001100111010111110000000111011000110111110001110111000010100110010011111100011010111101101101001110000010111011110010110010011101101010010100101011111011001111010000000001011000011000100000101111010001100000011010011010111001010010101101000110011001110111010000011010101111011110100011110011010000001100100101000010110100100100011001000101010001100000010000100111001110110101000000101011100000001100010

常见攻击方式:

给出2n个连续生成数据(ai , ... ,ai+2n-1)

记Sj=(ai+(j-1) , ... ,ai+(j-1)+n-1) (j=1,2,...,n+1)

构造矩阵X=[S1,S2,...,Sn] => Sn+1 = (c1 , ... ,cn)X =>(c1 , ... ,cn) =Sn+1 X-1

对所给数据爆破8位

import hashlib
c1='001010010111101000001101101111010000001111011001101111011000100001100011111000010001100101110110011000001100111010111110000000111011000110111110001110111000010100110010011111100011010111101101101001110000010111011110010110010011101101010010100101011111011001111010000000001011000011000100000101111010001100000011010011010111001010010101101000110011001110111010000011010101111011110100011110011010000001100100101000010110100100100011001000101010001100000010000100111001110110101000000101011100000001100010'
for i in range(256):
    c=c1+bin(i)[2:].rjust(8,'0')
    A=Matrix.zero(256)
    for i in range(256):
        for j in range(256):
            A[i,j]=c[i+j]
    G=GF(2)
    A=Matrix(G,A)
    v=[]
    for i in range(256,512):
        v.append(int(c[i]))
    V=Matrix(G,v)
    try:
        M=V*A^(-1)
        M=list(vector(M))
        maskM=Matrix.zero(256)
        for i in range(255):
            maskM[i,i+1]=1
        for i in range(256):
            maskM[255,i]=M[i]
        maskM=Matrix(G,maskM)
        V=vector(V)
        mask=maskM^512
        m=((mask)^(-1))*V
        key=''
        for i in range(256):
            key+=str(m[i])
        key=int(key,2)
        FLAG="de1ctf{"+hashlib.sha256(hex(key)[2:].rstrip('L').encode()).hexdigest()+"}"
        if FLAG[7:11]=='1224':
            print(FLAG)
    except:
        continue
    c=''

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
	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")
ff = open(sys.argv[3],"wb")
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'))

for i in range(len(a), lent):
    tmp=0
    for j in range(8):
        (R,out)=lfsr(R,mask)
        tmp=(tmp << 1)^out
    ff.write((tmp^ord(s[i])).to_bytes(1, byteorder='big'))
ff.close()

此题并没有考lfsr的细节,因为异或的性质,我们只需爆破完key,重走一遍加密过程即可

代码如下

f=open('cipher.txt','rb')
ff=open('flag_encode.txt','rb')
pt='sdgfjkahblskdjxbvfskljdfbguisldfbvghkljsdfbghsjkldhbgjklsdbgvlkjsdgbkljb sdkljfhwelo;sdfghioeurthgbnjl k'
c=f.read()
flagc=ff.read()
mask = 0b1101100000000000000000000000000000000000000000000000000000000000
def lfsr(R, mask):
    output = (R << 1) & 0xffffffffffffffff
    i=(R&mask)&0xffffffffffffffff
    lastbit=0
    while i!=0:
        lastbit^=(i&1)
        i=i>>1
    output^=lastbit
    return (output,lastbit)

def decrypt1(key, c,m):
    for i in range(len(a)):
        m+=chr(c[i]^ord(key[i]))
    return m

def decrypt2(R,mask,m,c):
    for i in range(len(a),len(c)):
        tmp=0
        for j in range(8):
            (R,out)=lfsr(R,mask)
            tmp=(tmp<<1)^out
        m+=chr(c[i]^tmp)
    return m

for i in range(1,len(c)):
    a1=''
    for j in range(i):
        a1+=chr(c[j]^ord(pt[j]))
    key=''
    for i in range(len(a1)):
        key+=hex(ord(a1[i]))[2:].rjust(2,'0')
    R=int(key,16)
    a = ''.join([chr(int(b, 16)) for b in [key[i:i + 2] for i in range(0, len(key), 2)]])
    m=''
    m+=decrypt1(key,flagc,m)
    m+=decrypt2(R,mask,m,flagc)
    print(m)

FilterRandom[西湖论剑]

import random
from secret import init1,init2,flag
assert flag==b'DASCTF{%d-%d}'%(init1,init2)

class lfsr():
    def __init__(self, init, mask, length):
        self.init = init
        self.mask = mask
        self.lengthmask = 2**length-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

def my_filter(c1,c2):
    if random.random()>0.1:
        return str(c1)
    else:
        return str(c2)

N=64
mask1=random.getrandbits(N)
mask2=random.getrandbits(N)
print(mask1)
print(mask2)
l1=lfsr(init1,mask1,N)
l2=lfsr(init2,mask2,N)
output=''
for i in range(2048):
    output+=my_filter(l1.next(),l2.next())
print(output)
'''
17638491756192425134
14623996511862197922
10001011010100011000100101001011100010110111001100001110000111011011100101101101000111101100010111100011000011111111010101111100101010101100010100000111011010011110111000100000101100101010110100111100011000101010101011011111011011000001101001011000010000011110001111001111011100110011111111101000111101001010000110001110111101001001101011101101001010001101010010110000000000001001101100101011110011010110011010110110011001001111001010100011110111100100010110111100110010000000010010011110001100000011000001110001000000010000100100101100000011100000011110101001011010011010100001101000010100100000011001011001000110000000000111011101000110010110111110010101110010001010001111111000011010000011001110111001000010011000000111010111100000100010011001111101110110100100011111000111000011111101010010110011111100010000100101011000001010101111101111001000011101111000111000101011010111100110001011011100101001010110110110110011100100111100110001101110010100010111100000110000010110100010001100011011001100100110101110010100011101110110010000010011100000011100000101010011011111110000100000010001010111011011111110100111100011100011110110010001011101111001011101010110111001001000111001001111001111110111111100001111100100110011111110110101000011010111110010001100000111100010011100011010000101010111010101101000011001110011000000110110110001101100110101110010010111011100110101000110000011001010100000110000000001110010001010001001101111100001111111011010010011100110010000111010001001111111110000010101110011010100100101101100111000010110100110010001010110111110011000111011101110100010000110110110011001011111011111000000000000001110000001000011000110111000000110100110110001111011111100010010011100101010000111000011111010000001010010011101010010110011000000001111110000000010111011000010001111000100110101110001000011111001101111111100011111011001001110000101001101110100111010011011101000110010000001001000001100110001110101100001000110100100010111101100010100110011111010011100100001101111010000110110101111111001111011100001101100000001101111100100
'''

第一次做带滤波的lfsr,调了一下午总算整出来了,一直给我卡在把sage的^当异或上

上一篇:detectron2入门学习二:实现FruitsNut水果坚果分割任务数据集Mask与coco格式转换处理


下一篇:JS实现遮罩展示图片