基于已知部分明文的单个LFSR序列密码的攻击

基于已知部分明文的单个LFSR序列密码的攻击

单个LFSR的工作原理

查看源图像

在该通用LFSR中,初始加载值为s0,…,sm-1,且在计算sm以及sm+1等值的时候会用到前m个s和m个p。称p为反馈系数。p的值为0,1。

那么LFSR的输出公式可以表示为:
i = 0 ,   s m = p m − 1 s m − 1 + . . . + p 1 s 1 + p 0 s 0   m o d   2 i = 1 ,   s m + 1 = p m − 1 s m + . . . + p 1 s 2 + p 0 s 1   m o d   2 . . . i = m − 1 ,   s 2 m − 1 = p m − 1 s 2 m − 2 + . . . + p 1 s m + p 0 s m − 1   m o d   2 i=0,\ s_m=p_{m-1}s_{m-1}+...+p_1s_1+p_0s_0\ mod\ 2\\ i=1,\ s_{m+1}=p_{m-1}s_{m}+...+p_1s_2+p_0s_1\ mod\ 2\\ .\\ .\\ .\\ i=m-1,\ s_{2m-1}=p_{m-1}s_{2m-2}+...+p_1s_m+p_0s_{m-1}\ mod\ 2\\ i=0, sm=pm1sm1+...+p1s1+p0s0 mod 2i=1, sm+1=pm1sm+...+p1s2+p0s1 mod 2...i=m1, s2m1=pm1s2m2+...+p1sm+p0sm1 mod 2
所以知道最开始的输出值以及p系数的所有值,可以一直推出LFSR的输出,而对于p的求解显然要用到高斯消去、矩阵求逆等其他线性代数的知识。

对于LFSR的攻击

攻击的讨论基于《深入浅出密码学》中的一题(仅做部分摘录并有所更改)。

现在我们攻击另一个基于LFSR的序列密码。为了方便处理字母,26个大写字母和数字0,1,2,3,4,5都使用下 面的映射表示成一个5位向量:

A <–> 0 = 000002

Z <–> 25 = 110012

0 <–> 26 = 110102

5 <–> 31 = 111112

我们碰巧已知该系统以下信息:

  • LFSR的度m=6.
  • 每个消息都是以WPI头部开始。

并在信道上发现此系统的以下信息(第四个字母为0):

j5a0edj2b

。。。

所以明文是什么?

此题的关键便是求出LFSR的反馈系数,然后生成所有的密钥从而获得明文。

由于每个信息二点头部都为WPI,用 m ⊗ c = k m \otimes c = k mc=k可以得到部分密钥,从而得到LFSR的初始输入(前m个二进制位)。

题目中已经知道了消息头部,可以得出15个二进制位,而此LFSR的度仅为6,因此可以求出反馈系数。

所以另A = [ s 0 s 1 ⋯ s m − 1 s 1 s 2 ⋯ s m ⋮ ⋮ ⋱ ⋮ s m − 1 s m ⋯ s 2 m − 1 ] \left[ \begin{matrix} s_0 & s_1 & \cdots & s_{m-1} \\ s_1 & s_2 & \cdots & s_{m} \\ \vdots & \vdots & \ddots & \vdots \\ s_{m-1} & s_{m} & \cdots & s_{2m-1} \\ \end{matrix} \right] s0s1sm1s1s2smsm1sms2m1,B = [ p 0 p 1 ⋮ p m ] \left[ \begin{matrix} p_0\\p_1\\ \vdots\\ p_m \end{matrix} \right] p0p1pm,C = [ s m s m + 1 ⋮ s 2 m − 1 ] \left[ \begin{matrix} s_m\\ s_{m+1} \\ \vdots \\ s_{2m-1} \end{matrix} \right] smsm+1s2m1

那么可列方程A x B mod 2 = C,及B = A-1 x C mod 2。

得出B后,便可以利用LFSR中的递推关系来构造后面的s。

python攻击脚本

hash map构造题目的映射

def map_fun():
    hash_map = {}
    for idx in range(0, 26):
        hash_map[chr(ord('A') + idx)] = idx
    hash_map['0'] = 26
    hash_map['1'] = 27
    hash_map['2'] = 28
    hash_map['3'] = 29
    hash_map['4'] = 30
    hash_map['5'] = 31
    return hash_map

当然,不同的序列密码可能使用不同的映射,甚至没有映射,代码仅针对此题使用。

解方程得反馈系数

用映射将WPI转为相应的二进制流,再与对应长度的密文转换的二进制流进行异或可得到密钥流及输入LFSR的初始向量。之后解方程得到系数。

def get_pi(Bin_K, m):
    s = list(map(int, Bin_K))
    martix_s = []
    
    for idx in range(0, m):
        martix_s.append(s[idx:idx+m])
    
    S = np.array(martix_s)
    C = np.array(s[m:2*m]).reshape(m, 1)
    P = np.matmul(inv_martix(S), C)

    pi = list(P)
    for idx in range(0, len(pi)):
        pi[idx] = int(pi[idx] % 2)

    return pi

构造LFSR PRG

利用已知的反馈系数以及初始输入值来推出整个密文。

def LFSR_PRG(p, seed, L):
    k = seed
    m = len(seed)
    for idx in range(m, L):
        sidx = 0
        for t in range(0, m):
            sidx += p[t] * int(k[idx-m+t])
        sidx = sidx % 2
        k += str(sidx)

    return k

完整代码

import numpy as np

#get the invert of the martix
def inv_martix(C):
    inv_C = np.linalg.inv(C)
    return inv_C

#get the value of pi(i from 0 to m-1)
def get_pi(Bin_K, m):
    s = list(map(int, Bin_K))
    martix_s = []
    
    for idx in range(0, m):
        martix_s.append(s[idx:idx+m])
    
    S = np.array(martix_s)
    C = np.array(s[m:2*m]).reshape(m, 1)
    P = np.matmul(inv_martix(S), C)

    pi = list(P)
    for idx in range(0, len(pi)):
        pi[idx] = int(pi[idx] % 2)

    return pi

#some strange map functions
def map_fun():
    hash_map = {}
    for idx in range(0, 26):
        hash_map[chr(ord('A') + idx)] = idx
    hash_map['0'] = 26
    hash_map['1'] = 27
    hash_map['2'] = 28
    hash_map['3'] = 29
    hash_map['4'] = 30
    hash_map['5'] = 31
    return hash_map

def s2b(s, map_fun, m):
    bin_str = ""
    f = "{:0" + str(m) + "b}"

    for idx in range(0, len(s)):
        bin_str += f.format(map_fun[s[idx]])
    
    return bin_str

def bin_xor(a, b):
    if(len(a) > len(b)):
        return "".join([str(int(x) ^ int(y)) for (x, y) in zip(a[:len(b)], b)])
    else:
        return "".join([str(int(x) ^ int(y)) for (x, y) in zip(a, b[:len(a)])])

def LFSR_PRG(p, seed, L):
    k = seed
    m = len(seed)
    for idx in range(m, L):
        sidx = 0
        for t in range(0, m):
            sidx += p[t] * int(k[idx-m+t])
        sidx = sidx % 2
        k += str(sidx)

    return k
        

#begin
m = 6
hash_map = map_fun() 
Chose_PT = s2b("WPI", hash_map, 5)
CT = "j5a0edj2b"
CT = CT.upper()
CT = s2b(CT, hash_map, 5)

s = bin_xor(Chose_PT, CT)
pi = get_pi(s, m)
k = LFSR_PRG(pi, s[0:m], len(CT) * 5)

PT = bin_xor(CT, k)
message = ""

for idx in range(0, len(PT), 5):
    c = PT[idx:idx+5]
    for key in hash_map:
        if(hash_map[key] == int(c, 2)):
            message += key

print(message) 
#end

(脚本中的数字5是映射后的二进制位数,根据题目决定)

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alice&Bob

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值