流密码立方攻击(基于图算法)

流密码常见概念

流密码(Stream cipher)是对称加密的一种。流密码将明文(Plaintex)看成二进制数据流,通过初始密钥生成加密密钥流 z i z_i zi与明文流 p i p_i pi做异或操作获得密文流 c i c_i ci,即 c i = p i ⊕ z i c_i=p_i\oplus{z_i} ci=pizi。由于异或操作是可逆的,则解密操作可以由相同的 z i z_i zi获得,即 p i = c i ⊕ z i p_i=c_i\oplus{z_i} pi=cizi

反馈位移寄存器

位移寄存器是利用有限长度的密钥生成任意长度的密钥流 z z z的重要工具,其工作原理是每生成一位加密密钥比特 z i z_i zi,都利用寄存器自身的某些比特对寄存器的第1位进行更新,其他比特位则右移。下图展示了一个反馈位移寄存器的工作原理,寄存器的第1到4位直接右移,空出来的第1位由寄存器上一步状态的第4,5位做乘法运算并与第1位做异或运算得到。
图1 反馈位移寄存器
如果寄存器的更新操作中涉及非线性运算(上图中的乘法操作就是非线性的),则称为非线性反馈位移寄存器(Non-Linear feedback shift register,NFSR),否则称为线性反馈位移寄存器(Linear feedback shift register,LFSR)。

轮函数

轮函数实际上是反馈位移寄存器更新操作的数学表达式,如上图展示的寄存器的表达式为: s 1 r = s 1 r − 1 ⊕ s 4 r − 1 s 5 r − 1 s_1^r=s_1^{r-1}\oplus{s_4^{r-1}s_5^{r-1}} s1r=s1r1s4r1s5r1,其中上标 r r r表示轮数,下标 i i i表示寄存器的第 i i i位。通常,为了使流密码足够复杂,在输出第1位加密密钥比特之前要进行 R R R次轮函数迭代。

Ancry

现实使用的流密码为了密码强度都设计得非常复杂(密钥多达几十甚至几百位,初始轮数 R R R也非常大),因此几乎只能从数学上对密码进行立方攻击,而实际上的破解过程需要交由计算机,这对初学者学习立方攻击造成了一定的困扰。为此本文设计了一个名为Ancry的密码算法,该算法只包含5个密钥比特,初始轮数 R = 10 R=10 R=10,每一个工作步骤都十分简洁明了。Ancry流密码的工作流程如下图所示。
Ancry示意图
Ancry的第1个寄存器的初始状态存放5bit的密钥,第2个寄存器的初始状态存放5bit的公开变量,这些变量是公开可控的。令 s = ( x , v ) s=(x,v) s=(x,v),则Ancry的轮函数的数学表达式为: s 1 r = s 8 r − 1 + s 7 r − 1 s 10 r − 1 , ( 1 ) s_1^r=s_8^{r-1}+s_7^{r-1}s_{10}^{r-1},(1) s1r=s8r1+s7r1s10r1,(1) s 6 r = s 2 r − 1 + s 4 r − 1 s 5 r − 1 , ( 2 ) s_6^r=s_2^{r-1}+s_4^{r-1}s_5^{r-1},(2) s6r=s2r1+s4r1s5r1,(2) z i = s 3 i + 9 + s 9 i + 9 z_i=s_3^{i+9}+s_9^{i+9} zi=s3i+9+s9i+9
由上述第3个表达式可以得出,输出第一位加密密钥比特之前进行了10次初始化迭代,即 R = 10 R=10 R=10。以下为Ancry的Python实现代码。

# Author:   AngieJC
# Date:     2022/01/17
# Mail:     htk90uggk@outlook.com

import sys

def Ancry(vec_x, vec_v, plaintext):  # 流密码,vec_x为密钥x,vec_v为公开参数v,plaintext为明文
    z = []  # z为输出的密钥比特

    # 初始轮数r=10
    R = 10
    x = vec_x.copy()
    v = vec_v.copy()
    for i in range(R):
        for j in range(len(vec_x) - 1):
            x[j + 1] = vec_x[j]
        x[0] = vec_v[2] ^ (vec_v[1] * vec_v[4])
        for j in range(len(vec_v) - 1):
            v[j + 1] = vec_v[j]
        v[0] = vec_x[1] ^ (vec_x[3] * vec_x[4])
        vec_x = x.copy()
        vec_v = v.copy()

    # 计算z
    cyphertext = []
    for i in range(len(plaintext)):
        # 添加一位密钥比特
        z.append(vec_x[2] ^ vec_v[3])
        cyphertext.append(z[-1] ^ plaintext[i])

        # 更新x与v
        for j in range(len(vec_x) - 1):
            x[j + 1] = vec_x[j]
        x[0] = vec_v[2] ^ (vec_v[1] * vec_v[4])
        for j in range(len(vec_v) - 1):
            v[j + 1] = vec_v[j]
        v[0] = vec_x[1] ^ (vec_x[3] * vec_x[4])
        vec_x = x.copy()
        vec_v = v.copy()

    return cyphertext

if __name__ == "__main__":
    x = input("密钥:")
    if(len(x) != 5):
        print("密钥长度应当为5!")
        sys.exit()
    vec_x = []
    for i in range(len(x)):
        vec_x.append(int(x[i]))
    # vec_x = [int(x[0]), int(x[1])]
    v = input("公开参数:")
    if (len(v) != 5):
        print("公开参数长度应当为5!")
        sys.exit()
    vec_v = []
    for i in range(len(v)):
        vec_v.append(int(v[i]))
    # vec_v = [int(v[0]), int(v[1])]
    p = input("明文:")

    plaintext = []
    for i in range(len(p)):
        plaintext.append(int(p[i]))

    cyphertext = Ancry(vec_x, vec_v, plaintext)
    print("明文:", plaintext)
    print("密文:", cyphertext)
Ancry简要分析

在介绍立方攻击之前先对Ancry进行一些简单的分析,以方便理解立方攻击的工作原理。
由于流密码的加密模式为 c i = p i ⊕ z i c_i=p_i\oplus{z_i} ci=pizi,因此攻击者知道明文 p p p和明文 c c c就相当于知道密钥流 z z z
Ancry第1位加密密钥比特 z z z(在不引起歧义的情况下,以下使用 z z z代替 z 1 z_1 z1)的表达式为: z = s 3 10 + s 9 10 z=s_3^{10}+s_9^{10} z=s310+s910根据反馈位移寄存器的特点我们知道,一个比特生成并保存到寄存器的第一个位置后,一直在做右移操作,直到右移到寄存器的最右边被丢弃,而值并不发生任何变化,因此有 s 3 10 = s 1 8 s_3^{10}=s_1^8 s310=s18 s 9 10 = s 6 7 s_9^{10}=s_6^7 s910=s67。再根据等式(1)和等式(2),有 z = s 8 7 + s 7 7 s 10 7 + s 2 6 + s 4 6 s 5 6 z=s_8^7+s_7^7s_{10}^7+s_2^6+s_4^6s_5^6 z=s87+s77s107+s26+s46s56。对 z z z一直进行递归分解,最终可以得到: z = v 1 + x 5 v 3 + x 1 v 3 + x 1 v 2 v 5 + x 5 v 3 + x 5 v 2 v 5 + x 2 x 3 x 5 + x 4 v 2 v 3 + x 4 v 2 v 5 + x 2 x 3 x 4 v 2 + v 2 v 3 + x 2 x 3 v 2 v 3 + v 2 v 5 + x 2 x 3 v 2 v 5 + v 1 v 3 v 4 + x 2 x 3 v 1 v 3 v 4 + v 1 v 2 v 4 v 5 + x 2 x 3 v 1 v 2 v 4 v 5 + x 4 + x 3 v 1 + v 1 v 2 + v 1 v 4 + x 5 v 2 v 3 + x 5 v 1 v 3 v 4 z=v_1+x_5v_3+x_1v_3+x_1v_2v_5+x_5v_3+x_5v_2v_5+x_2x_3x_5+x_4v_2v_3+x_4v_2v_5\\+x_2x_3x_4v_2+v_2v_3+x_2x_3v_2v_3+v_2v_5+x_2x_3v_2v_5+v_1v_3v_4+x_2x_3v_1v_3v_4\\+v_1v_2v_4v_5+x_2x_3v_1v_2v_4v_5+x_4+x_3v_1+v_1v_2+v_1v_4+x_5v_2v_3+x_5v_1v_3v_4 z=v1+x5v3+x1v3+x1v2v5+x5v3+x5v2v5+x2x3x5+x4v2v3+x4v2v5+x2x3x4v2+v2v3+x2x3v2v3+v2v5+x2x3v2v5+v1v3v4+x2x3v1v3v4+v1v2v4v5+x2x3v1v2v4v5+x4+x3v1+v1v2+v1v4+x5v2v3+x5v1v3v4这个表达式称为 z z z的代数范式(Algebraic Normal Form, ANF)。以上表达式是 z 1 z_1 z1的代数表达式,理论上来说,如果我们能够推出所有 z i z_i zi的代数表达式,那么在实际加密过程中,也可以完全抛弃反馈位移寄存器而直接使用代数表达式计算密钥流。

读者也可以自己推出 z z z的代数表达式
注意:由于二进制中有以下特性
性质1: 1 n = 1 , 0 n = 0 1^n=1,0^n=0 1n=1,0n=0
性质2: 1 + 1 = 0 , 0 + 0 = 0 1+1=0,0+0=0 1+1=0,0+0=0

因此 z z z的代数表达式中 x n x^n xn可以简化成 x x x x + x x+x x+x可以直接约去

立方攻击

立方攻击由Dinur和Shamir在2009年的欧密会上提出,其中的Shamir就是设计了RSA算法的三位作者中的S。
立方攻击只关心输出的第1位加密密钥比特,其中心思想是:选取一个关于公开变量 v v v的立方索引 I I I,把 z z z的代数表达式分解成: z = p ( x , v ) t I + q ( x , v ) z=p(x,v)t_I+q(x,v) z=p(x,v)tI+q(x,v)其中 t I t_I tI为被 I I I索引的公开变量的连乘,即 t I = ∏ i ∈ I v i t_I=\prod_{i\in{I}}v_i tI=iIvi。说直白一点就是对 z z z的代数表达式提取公因子 t I t_I tI p ( x , v ) p(x,v) p(x,v)为提取 t I t_I tI之后的多项式, q ( x , v ) q(x,v) q(x,v)则为无法提取 t I t_I tI的多项式。

例子1:
x = ( x 1 , x 2 , x 3 ) , v = ( v 1 , v 2 , v 3 ) x=(x_1,x_2,x_3),v=(v_1,v_2,v_3) x=(x1,x2,x3),v=(v1,v2,v3)
z = x 1 v 1 v 3 + x 1 v 2 + x 2 v 1 v 2 + x 2 x 3 v 1 v 3 + v 1 v 3 z=x_1v_1v_3+x_1v_2+x_2v_1v_2+x_2x_3v_1v_3+v_1v_3 z=x1v1v3+x1v2+x2v1v2+x2x3v1v3+v1v3
I = { 1 , 3 } I=\{1,3\} I={1,3}
z = ( x 1 + x 2 x 3 + 1 ) v 1 v 3 + x 1 v 1 + x 2 v 1 v 2 z=(x_1+x_2x_3+1)v_1v_3+x_1v_1+x_2v_1v_2 z=(x1+x2x3+1)v1v3+x1v1+x2v1v2
其中 p ( x , v ) = x 1 + x 2 x 3 + 1 , t I = v 1 v 3 , q ( x , v ) = x 1 v 1 + x 2 v 1 v 2 p(x,v)=x_1+x_2x_3+1,t_I=v_1v_3,q(x,v)=x_1v_1+x_2v_1v_2 p(x,v)=x1+x2x3+1,tI=v1v3,q(x,v)=x1v1+x2v1v2

z z z分解成 p ( x , v ) t I + q ( x , v ) p(x,v)t_I+q(x,v) p(x,v)tI+q(x,v)后我们可以得到一个非常有趣的结论,即 ∑ v ∈ C z = p ( x , v ) , ( 3 ) \sum_{v\in{C}}z=p(x,v),(3) vCz=p(x,v),(3)其中 C C C I I I所代表的立方,即 v i ∈ I v_i\in{I} viI取遍所有的 2 ∣ I ∣ 2^{|I|} 2I个0-1组合, ∣ I ∣ |I| I代表集合 I I I中元素的个数。

例子1续:
I = { 1 , 3 } I=\{1,3\} I={1,3}
C = { ( 0 , 0 , 0 ) ( 0 , 0 , 1 ) ( 1 , 0 , 0 ) ( 1 , 0 , 1 ) C= \begin{cases} (\textcolor{red}0,0,\textcolor{red}0)\\ (\textcolor{red}0,0,\textcolor{red}1)\\ (\textcolor{red}1,0,\textcolor{red}0)\\ (\textcolor{red}1,0,\textcolor{red}1) \end{cases} C=(0,0,0)(0,0,1)(1,0,0)(1,0,1)
由于 v 2 v_2 v2并不是立方元素,可以是任意值或者直接置0

证明:
∑ v ∈ C z = ∑ v ∈ C p ( x , v ) t I + ∑ v ∈ C q ( x , v ) \sum_{v\in{C}}z=\sum_{v\in{C}}p(x,v)t_I+\sum_{v\in{C}}q(x,v) vCz=vCp(x,v)tI+vCq(x,v)
p ( x , v ) t I = { p ( x , v ) 所 有 的 v i ∈ I 均 等 于 1 ( C 中 的 最 后 一 种 情 况 ) 0 C 中 其 他 三 种 情 况 p(x,v)t_I= \begin{cases} p(x,v)&&所有的v_i\in{I}均等于1(C中的最后一种情况)\\ 0&&C中其他三种情况 \end{cases} p(x,v)tI={p(x,v)0viI1(C)C
∑ v ∈ C p ( x , v ) t I = p ( x , v ) \sum_{v\in{C}}p(x,v)t_I=p(x,v) vCp(x,v)tI=p(x,v)

又由于 v 2 = 0 v_2=0 v2=0,则 q ( x , v ) = x 1 v 1 + x 2 v 1 v 2 = x 1 v 1 q(x,v)=x_1v_1+x_2v_1v_2=x_1v_1 q(x,v)=x1v1+x2v1v2=x1v1 ∑ v ∈ C q ( x , v ) = 0 x 1 + 0 x 1 + 1 x 1 + 1 x 1 = x 1 + x 1 \sum_{v\in{C}}q(x,v)=0x_1+0x_1+1x_1+1x_1=x_1+x_1 vCq(x,v)=0x1+0x1+1x1+1x1=x1+x1,由性质2可知, ∑ v ∈ C q ( x , v ) = 0 \sum_{v\in{C}}q(x,v)=0 vCq(x,v)=0
事实上,由于 C C C中共有 2 ∣ I ∣ 2^{|I|} 2I个元素,即偶数个元素,根据性质2, ∑ v ∈ C q ( x , v ) \sum_{v\in{C}}q(x,v) vCq(x,v)必然为0

综上, ∑ v ∈ C z = p ( x , v ) \sum_{v\in{C}}z=p(x,v) vCz=p(x,v)得证

现在我们我们把目光再次聚焦到Ancry, z z z的表达式已经知道,根据立方 I I I选取的不同,可以将 z z z分解成一下几种形式(由于 ∑ v ∈ C q ( x , v ) = 0 \sum_{v\in{C}}q(x,v)=0 vCq(x,v)=0,我们并不关心其具体表达式,因此在下列例子中都没有显式给出 q ( x , v ) q(x,v) q(x,v)的表达式):

  1. I = { 1 , 2 , 3 , 4 , 5 } , 无 法 分 解 I=\{1,2,3,4,5\},无法分解 I={1,2,3,4,5},
  2. I = { 1 , 2 , 4 , 5 } , p ( x , v ) = x 2 x 3 + 1 I=\{1,2,4,5\},p(x,v)=x_2x_3+1 I={1,2,4,5},p(x,v)=x2x3+1
  3. I = { 1 , 3 , 4 } , p ( x , v ) = x 2 x 3 + x 5 + 1 I=\{1,3,4\},p(x,v)=x_2x_3+x_5+1 I={1,3,4},p(x,v)=x2x3+x5+1
  4. I = { 2 , 3 } , p ( x , v ) = x 2 x 3 + x 4 + x 5 + 1 I=\{2,3\},p(x,v)=x_2x_3+x_4+x_5+1 I={2,3},p(x,v)=x2x3+x4+x5+1
  5. I = { 2 , 5 } , p ( x , v ) = x 1 + x 2 x 3 + x 4 + x 5 + 1 I=\{2,5\},p(x,v)=x_1+x_2x_3+x_4+x_5+1 I={2,5},p(x,v)=x1+x2x3+x4+x5+1
  6. I 只 有 1 个 元 素 分 解 意 义 不 大 I只有1个元素分解意义不大 I1
Ancry攻击实例

基本信息:
x = ( 1 , 0 , 0 , 1 , 0 ) x=(1,0,0,1,0) x=(1,0,0,1,0)
I = { 2 , 5 } I=\{2,5\} I={2,5}
p ( x , v ) = x 1 + x 2 x 3 + x 4 + x 5 + 1 p(x,v)=x_1+x_2x_3+x_4+x_5+1 p(x,v)=x1+x2x3+x4+x5+1

根据实际加密结果,有:
z = { 1 , v = ( 0 , 0 , 0 , 0 , 0 ) 1 , v = ( 0 , 0 , 0 , 0 , 1 ) 1 , v = ( 0 , 1 , 0 , 0 , 0 ) 0 , v = ( 0 , 1 , 0 , 0 , 1 ) z= \begin{cases} 1,v=(0,\textcolor{red}0,0,0,\textcolor{red}0)\\ 1,v=(0,\textcolor{red}0,0,0,\textcolor{red}1)\\ 1,v=(0,\textcolor{red}1,0,0,\textcolor{red}0)\\ 0,v=(0,\textcolor{red}1,0,0,\textcolor{red}1) \end{cases} z=1,v=(0,0,0,0,0)1,v=(0,0,0,0,1)1,v=(0,1,0,0,0)0,v=(0,1,0,0,1)
∑ v ∈ C z = p ( x , v ) = x 1 + x 2 x 3 + x 4 + x 5 + 1 = 1 + 1 + 1 + 0 = 1 \sum_{v\in{C}}z=p(x,v)=x_1+x_2x_3+x_4+x_5+1=1+1+1+0=1 vCz=p(x,v)=x1+x2x3+x4+x5+1=1+1+1+0=1,即 x 1 + x 2 x 3 + x 4 + x 5 = 0 , ( 4 ) \textcolor{red}{x_1+x_2x_3+x_4+x_5=0},(4) x1+x2x3+x4+x5=0,(4)
在没有等式(4)之前,想要通过穷举的方式破解Ancry需要遍历 2 5 = 32 2^5=32 25=32种密钥可能的取值。而符合等式(4)的密钥取值为 x = { ( 0 , 0 , 0 , 0 , 0 ) ( 0 , 0 , 0 , 1 , 1 ) ( 0 , 0 , 1 , 0 , 0 ) ( 0 , 0 , 1 , 1 , 1 ) ( 0 , 1 , 0 , 0 , 0 ) ( 0 , 1 , 0 , 1 , 1 ) ( 0 , 1 , 1 , 0 , 1 ) ( 0 , 1 , 1 , 1 , 0 ) ( 1 , 0 , 0 , 0 , 1 ) ( 1 , 0 , 0 , 1 , 0 ) , 正 确 密 钥 ( 1 , 0 , 1 , 0 , 1 ) ( 1 , 0 , 1 , 1 , 0 ) ( 1 , 1 , 0 , 0 , 1 ) ( 1 , 1 , 0 , 1 , 0 ) ( 1 , 1 , 1 , 0 , 0 ) ( 1 , 1 , 1 , 1 , 1 ) x= \begin{cases} (0, 0, 0, 0, 0)\\ (0, 0, 0, 1, 1)\\ (0, 0, 1, 0, 0)\\ (0, 0, 1, 1, 1)\\ (0, 1, 0, 0, 0)\\ (0, 1, 0, 1, 1)\\ (0, 1, 1, 0, 1)\\ (0, 1, 1, 1, 0)\\ (1, 0, 0, 0, 1)\\ \textcolor{red}{(1, 0, 0, 1, 0)},正确密钥\\ (1, 0, 1, 0, 1)\\ (1, 0, 1, 1, 0)\\ (1, 1, 0, 0, 1)\\ (1, 1, 0, 1, 0)\\ (1, 1, 1, 0, 0)\\ (1, 1, 1, 1, 1) \end{cases} x=(0,0,0,0,0)(0,0,0,1,1)(0,0,1,0,0)(0,0,1,1,1)(0,1,0,0,0)(0,1,0,1,1)(0,1,1,0,1)(0,1,1,1,0)(1,0,0,0,1)(1,0,0,1,0),(1,0,1,0,1)(1,0,1,1,0)(1,1,0,0,1)(1,1,0,1,0)(1,1,1,0,0)(1,1,1,1,1)共16种情况,再加上遍历立方 C C C的4种情况,一共需要20个步骤即可破解Ancry,比穷举破解Ancry的32种情况要优秀不少。

参考文献

[1] Delaune, S., Derbez, P., Gontier, A., & Prud’homme, C. (2021). A Simpler Model for Recovering Superpoly onTrivium. Cryptology ePrint Archive.

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值