对称加密算法–简单可以分为对称密码和流密码

特点

  1. 加密方和解密方使用同一个密钥;
  2. 加密解密速度较快,适合数据较长的情况下使用;
  3. 密钥传输过程不安全,容易被破解,且密钥管理较为麻烦
  4. 其安全性依赖于:加密算法足够安全、密钥安全性足够高;
  5. 主要加密算法:DES、3DES、AES、RC4流密码、TEA、IDEA、Blowfish等

DES (Data Encryption Standard–数据加密标准)

一种单一密钥对称加解密算法,通信主体之间只有一个密钥,该密钥不对第三方公开,但是因为密钥长度过短(只有56bit,且在1991年被破解),所以安全性低。

DES的输入参数有三个:Key、Data、Mode;

  1. Key共7个字节56bit(但是在存储和传输时是8个Byte,因为其中对每个Byte都包含一位用来进行奇偶校验,在使用后会被丢弃,实际上密钥的有效长度还是56bit),是DES的工作密钥
  2. Data共8个字节64bit(DES也是分组加密算法的一种,每组大小为64bit),是要加解密的数据
  3. Mode为DES的工作模式——加密或解密。

设计原则:使用了混淆和扩散,目的是抵抗统计密码分析

  1. 混淆confusion:使密文的统计特性和密钥的取值之间的关系尽可能的复杂化,从而实现密钥和密钥取值之间存在的潜在联系不能被攻击人员利用;
  2. 扩散diffusion:将每一位明文的影响尽可能迅速作用到尽可能多的密文上,从而在密文上尽可能的消除明文的影响,并使每一位密文位的影响扩散到尽可能多的密文上,防止被逐段破解;
算法步骤:

初始置换和逆置换分别位于加密过程的第一步和最后一步,对加密而言没有实际意义,只是为了在1970年代的基于8bit的硬件设备中加载,且其中使用的结构为常用的Feistel结构(2-5步,因为其结构是对称的,所以加解密的过程非常相似,对硬件要求低)

在这里插入图片描述

  1. 初始置换:将输入数据按位重新组合,并把输出分为 L 0 L_0 L0 R 0 R_0 R0两部分,每部分32位;置换规则为:输入的第58位置换到第1位、第50位置换到第2位…依次类推;

    初始置换的置换规则
    在这里插入图片描述

  2. R i R_i Ri使用Feistel进行处理,然后与 L i L_i Li进行异或,得到新的 R i + 1 R_{i+1} Ri+1,将 R i R_i Ri作为 L i + 1 L_{i+1} Li+1,即

    { L i + 1 = R i R i + 1 = F ( R i , K i ) ⊕ L i \left\{ \begin{aligned} L_{i+1} &= R_i \\ R_{i+1} &= F(R_i,K_i) \oplus L_i \end{aligned} \right. {Li+1Ri+1=Ri=F(Ri,Ki)Li

    其中 K i K_i Ki是子密钥。如此迭代16次;

  3. 逆置换:经过16次迭代后,将其结果作为输入进行逆置换,而逆置换是初始置换的逆运算。最后得到密文。

    逆置换的置换规则

在这里插入图片描述

Feistel的处理过程:

在这里插入图片描述

  1. 扩展(E) expansion:通过扩展置换(expansion permutation 具体实现是重复32bit原始数据中一半的内容,形成48bit的数据块)将32bit的 R i R_i Ri扩展到48bit,然后输出8个大小为6bit的小块组成的序列,每个小块其中包含4bit的原始输入信息、每个输入块到任意一侧相邻块的copy(因为是两侧,所以为2bit);(扩展置换的规则在原始数据的两侧添加复制的信息(注意,这里的值是数据的原始索引,不是数据本身,只是为了看起来更加直观才使用的索引值表示),如下图)
    在这里插入图片描述

  2. 密钥混合key mix: 将扩展结果和子密钥 K i K_i Ki i i i表示循环轮次)进行异或操作(子密钥大小为48bit,通过主密钥派生得到);

  3. 代换substitution:在密钥经过混合后,48bit的结果将会被分成8个6bit大小的块,然后使用S-box(每个S-box的输入大小为6bit,输出大小为4bit,但是每个S-box的大小是64bit的)进行处理,每个S-box(共8个)利用非线性变换将6bit的输入变成4bit的输出,S-box的使用增加了DES方法的安全性,若是没有S-box,密文将是线性的,容易被破解;

  4. 置换permutation:上一步得到的32bit的输出将会在P-box中进行置换,得到一个固定的顺序(这样的话可以使得每一个S-box的输出在下一轮循环中分布到四个不同的S-box中),然后输出。

关于Feistel的额外补充:
  1. S-box的内容和实现。

  2. 在这里插入图片描述

    假设上一层的输出为110011......(共48位),前6位为110011,是S-box-1的输入,因为第一位和第六位组合为 1 y y y y 1 1yyyy1 1yyyy1、中间四位组合为 x 1001 x x1001x x1001x,所以在S-box-1的表格中寻找对应的值转换成二进制 ( 11 ) 10 = ( 1011 ) 2 (11)_{10}=(1011)_{2} (11)10=(1011)2即为S-box-1的输出。

  3. P-box对32bit的输入的置换规则(这个规则在同一个算法中是固定的)
    在这里插入图片描述

3DES

就是对同一个数据进行三次DES加密处理,具体的流程为:

3 D E S ( M ) = E 3 ( D 2 ( E 1 ( M , K 1 ) , K 2 ) , K 1 ) 3DES(M) = E_3(D_2(E_1(M,K_1),K_2),K_1) 3DES(M)=E3(D2(E1(M,K1),K2),K1)

根据两个不同的密钥分别进行加密(使用 K 1 K_1 K1)、解密(使用 K 2 K_2 K2)、加密的过程(使用 K 1 K_1 K1),由此来加强算法的安全性。

因为DES的密钥长度只有56bit(在存储和传输时是64bit,其中每个Byte包含用于奇偶校验的1bit),且在1991年已经在理论上被破解,已经不在安全,所以使用3DES来加强其安全性,是DES向AES的过渡算法。

AES(Advanced Encryption Standard—高级加密标准)

因为DES存在的不安全性,所以被弃用,为了替代DES,提出了AES(高级加密标准–注意,是一个标准而不是算法,就比如是冠军,冠军可以是A,也可以是B),最终被选作AES的算法是Rijndael算法的一个变形,不过大家习惯叫该算法为AES。

AES也是基于substitution-permutation network进行设计的,因此在软件和硬件都有较高的效率。

与DES不同,AES没有使用Feistel方法,而是使用了Rijndael算法的一个变形,其块大小为128bit,密钥尺寸可以是128it、192bit或256bit(而Rijndael算法的块大小和密钥尺寸可以是32bit的整数倍,范围在128bit到256bit之间)。

AES处理的数据块是一个4×4的、按列排列Byte数组,如

在这里插入图片描述

密钥长度和变换轮次有关,其相关性为

  1. 对于128bit的密钥,需要变换10次;
  2. 对于192bit的密钥,需要变换12次;
  3. 对于256bit的密钥,需要变换14次;

每一轮变换包含几个处理步骤,其中一个步骤和密钥相关。

算法步骤(对于N次循环的AES算法,前N-1次循环执行3-6步,第N次循环仅执行3、4、6步):

  1. 密钥扩展key expansion:通过AES密钥方法从原始密钥中派生出多个round keys,AES在每一轮都要额外添加一个128bit的round key block;
  2. 初始化并添加round key:将数据块矩阵与此时的round key进行异或计算
  3. SubBytes(子字节变换):一个非线性的替换步骤,根据给定的查找表,将每一个byte换成另一个byte;
  4. ShiftRows(可以理解为行变换):一个转置的步骤,矩阵的最后三行循环移位一定数量的步骤;
  5. MixColumns(可以理解为列变换):一个线性混合操作,对于状态的列进行操作,将每一列的四个字节组合在一起;
  6. AddRoundKey(添加round key):添加round key,具体操作和初始化添加一样。

额外补充

  1. AddRoundKey的具体实现:因为每一个round key是从主密钥中根据Rijndael方法派生出来的,大小为128bit,而AES处理的数据块是4Byte×4Byte大小的,共128bit,正好可以逐位进行异或运算;

    在这里插入图片描述

  2. SubBytes的具体实现:在步骤中,矩形数据块中的每一个Byte根据一个8bit的 substitution box(S-box 替换表)进行替换;具体的替换规则为 b i , j = S ( a i , j ) b_{i,j}=S(a_{i,j}) bi,j=S(ai,j)

在这里插入图片描述

  1. 通过替换操作,为密文的生成提供了非线性,因为所使用的S-box所使用的衍生方法的倒数(multiplicative inverse)的有限域(finite field)超过 2 8 2^8 28,所以具有良好的非线性特性;

  2. 为了根据数学规律进行攻击(simple algebraic properties attack),S-box是通过逆函数和可逆仿射变换进行结合生成的;

  3. 同样,S-box也选择不会生成固定关系的进行使用,如不会出现 S ( a i , j ) ≠ a i , j ] , S ( a i , j ) ⊕ a i , j ≠ F F 16 S(a_{i,j}) \ne a_{i,j]},S(a_{i,j}) \oplus a_{i,j} \ne {FF}_{16} S(ai,j)=ai,j]S(ai,j)ai,j=FF16

  4. 在进行解密时,首先使用SubBytes的逆步骤,这需要先计算放射变换的逆,再求倒数(前面逆函数的倒数)。

  5. ShiftRows的具体实现:该步骤中,每行的四个Byte循环移动一定的偏移量,在AES算法中,第一行不动,从第二行开始,分别向左移动 i − 1 i-1 i1位,这样可以有效避免每列被单独加密从而被破解;

在这里插入图片描述

  1. MixColumns的具体实现:在该步骤中,每列的四个Byte根据可逆的线性变换进行结合,将每列的四个Byte作为输入,输出四个Byte,其中输入的每个Byte同时会对输出四个Byte产生影响;当执行这个操作时,每一列会使用一个固定的矩阵完成变换,可以看作每一列都与一个固定的多项式相乘;

在这里插入图片描述

RC4流密码

特点:实现简单且加密速度快。

存在的一些问题:当不丢弃输出密钥流的开头,或使用非随机或相关性较强的密钥时,非常的不安全,易被破解。

算法步骤

  1. 使用密钥调度算法(key schedule algorithm)对密钥的排列S(S是程度为256的所有可能byte的permutation)进行初始化,密钥的长度通常在40-2048bit之间;
  2. 使用伪随机生成算法(pseudo-random generate algorithm)生成比特流;

额外补充

  1. KSA的具体实现:首先把S初始化,然后对S进行256次迭代:

    for(int i=0;i<256;i++)
        s[i] = i;
    
    for(int i=0;i<256;i++)
    {//key是密钥  keylength是密钥的长度,通常的范围为40-2048
        j = ( j + s[i] + key[i % keylength] ) % 256;
        temp = s[i];
        s[i] = s[j];
        s[j] = temp;
    }
    
  2. PRGA的具体实现

    1. 初始化 i = 0 , j = 0 i=0,j=0 i=0,j=0
    2. 根据自增量 i = ( i + 1 ) % 256 i = (i+1) \% 256 i=(i+1)%256计算得到 j = ( j + s [ i ] ) % 256 j=(j+s[i]) \% 256 j=(j+s[i])%256
    3. 此时交换 s [ i ] s[i] s[i] s [ j ] s[j] s[j]的值;
    4. 然后得到密钥的第 i − 1 i-1 i1 K i − 1 = S [ ( s [ i ] + s [ j ] ) % 256 ] K_{i-1} = S[(s[i]+s[j]) \%256] Ki1=S[(s[i]+s[j])%256]
    5. 根据密文的长度选择合适的迭代次数,迭代上述的过程,最终得到完整的密文。

TEA(tiny encryption algorithm微型加密算法)

分组加密算法,可逆。

该方法使用一个128bit的密钥,数据分组大小为64bit,因为采用Feistel结构,所以成对处理(每个数据块分成两个32bit的数据块进行处理)64轮,每一轮称为一个周期。该方法的密钥生成是非常简单的,每个周期都是使用同样的方法混合所有的元素生成密钥。

该方法利用magic constant的不同倍数来抵御对每轮的对称攻击,其中magic constant为2654435769 或者说是 0x9E3779B9,是根据 2 32 ϕ \frac{2^{32}}{\phi} ϕ232得到的,其中 ϕ \phi ϕ是黄金分割率,因此一旦看到2654435769 或 0x9E3779B9就知道是TEA或是其衍生加密算法。

TEA方法的缺点:若128bit的密钥为等效密钥(32bit为一个周期循环相等),那么此时有效密钥长度就只有126bit了,因此TEA作为加密哈希函数时表现非常差。

IDEA(international data encryption algorithm国际数据加密算法)

属于块加密。

该算法使用128bit的密钥,分组大小为64bit,整个加密过程包括8轮相同的变换和一个输出变换,IDEA算法通过在多组数据之间交叉的进行操作——模块加法和乘法、按位异或,从而获得较强的安全性。

其中加法是模 2 16 2^{16} 216的加法,乘法是模 2 16 + 1 2^{16}+1 216+1的乘法,在输入中的 0 x 0000 0x0000 0x0000定义为 2 16 2^{16} 216,而输出中的 2 16 2^{16} 216被解释为 0 x 0000 0x0000 0x0000

在这里插入图片描述

8轮相同的变换细节

  1. 因为分块大小为64bit,通过上图可以看出是四个输入,因此每个输入16bit;

  2. 每一轮中,需要使用6个子密钥,而半轮需要4个密钥,因为共8.5轮,所以一共需要52个密钥;每个子密钥16bit,子密钥是通过128bit的主密钥派生得到的,具体的规则为:前8个子密钥是直接在主密钥中截取的,其中密钥 K 1 K_1 K1是主密钥的低16bit,其余类推;然后8个bit一组,将主密钥循环左移25bit,按照上面的方式继续进行密钥划分,再次得到8个密钥,因为只需要52个子密钥,所以只需要循环左移6次就可以满足需求;

  3. 每一轮的计算为:(其中第 i i i轮的输入定义为 I i , 1 , I i , 2 , I i , 3 , I i , 4 I_{i,1},I_{i,2},I_{i,3},I_{i,4} Ii,1,Ii,2,Ii,3,Ii,4,模块加法定义为 ⊞ \boxplus ,模块乘法定义为 ⊙ \odot ,异或为 ⊕ \oplus

    A 1 = ( I i , 1 ⊙ K 1 ) ⊕ ( I i , 3 ⊞ K 3 ) A 2 = ( I i , 4 ⊙ K 4 ) ⊕ ( I i , 2 ⊞ K 2 ) ) A 3 = K 5 ⊙ A 1 A 4 = A 3 ⊞ A 2 A 5 = K 6 ⊙ A 4   A 6 = A 5 ⊞ A 3 I i + 1 , 1 = A 5 ⊕ ( I i , 1 ⊙ K 1 ) I i + 1 , 2 = A 5 ⊕ ( I i , 3 ⊞ K 3 ) I i + 1 , 3 = A 6 ⊕ ( I i , 2 ⊞ K 2 ) I i + 1 , 4 = A 5 ⊕ ( I i , 4 ⊙ K 4 ) A_1=(I_{i,1} \odot K_1)\oplus(I_{i,3} \boxplus K_3) \\ A_2=(I_{i,4} \odot K_4)\oplus (I_{i,2} \boxplus K_2)) \\A_3= K_5 \odot A_1 \\A_4=A_3 \boxplus A_2 \\A_5= K_6 \odot A_4 \ \\A_6= A_5 \boxplus A_3\\I_{i+1,1}= A_5 \oplus(I_{i,1} \odot K_1) \\I_{i+1,2}=A_5 \oplus(I_{i,3} \boxplus K_3) \\I_{i+1,3}= A_6 \oplus(I_{i,2} \boxplus K_2) \\I_{i+1,4}=A_5 \oplus(I_{i,4} \odot K_4) A1=(Ii,1K1)(Ii,3K3)A2=(Ii,4K4)(Ii,2K2))A3=K5A1A4=A3A2A5=K6A4 A6=A5A3Ii+1,1=A5(Ii,1K1)Ii+1,2=A5(Ii,3K3)Ii+1,3=A6(Ii,2K2)Ii+1,4=A5(Ii,4K4)

在这里插入图片描述

最后输出的半轮变换

  1. 首先把上一轮交换的 K 2 , K 3 K_2,K_3 K2,K3交换回来;

  2. 然后与四个子密钥进行对应的操作即可

    O 1 = I i , 1 ⊙ K 1 O 2 = I i , 2 ⊞ K 2 O 3 = I i , 3 ⊞ K 3 O 4 = I i , 4 ⊙ K 4 O_1=I_{i,1} \odot K_1\\O_2 = I_{i,2} \boxplus K_2 \\ O_3=I_{i,3} \boxplus K_3\\ O_4 = I_{i,4} \odot K_4 O1=Ii,1K1O2=Ii,2K2O3=Ii,3K3O4=Ii,4K4

  3. 最终输出4个16bit的加密结果。

需要注意的是,IDEA算法采用Lai-Massey结构,在加密过程中,将明文分成两个部分进行处理,为了达到更好的效果,在一轮处理过后,交换两部分内容的位置,再进行一轮处理,最终得到加密结构(解密过程与其类似)。

在这里插入图片描述

每一轮的处理为(其中H函数是half-round函数,而F函数是round函数):

  1. 假设上一轮的输出为 ( L i − 1 , R i − 1 ) (L_{i-1},R_{i-1}) (Li1,Ri1),本层的输出为 ( L i ′ , R i ′ ) = H ( L i − 1 ′ + T i , R i − 1 ′ + T i ) (L'_{i},R'_{i}) = H(L'_{i-1} + T_i,R'_{i-1} + T_i) (Li,Ri)=H(Li1+Ti,Ri1+Ti),其中 ( L i − 1 ′ , R i − 1 ′ ) = H ( L i − 1 , R i − 1 ) (L'_{i-1} ,R'_{i-1})=H(L_{i-1} ,R_{i-1}) (Li1,Ri1)=H(Li1,Ri1) T i = F ( L i − 1 ′ − R i − 1 ′ , K i ) T_i = F(L'_{i-1} - R'_{i-1},K_i) Ti=F(Li1Ri1,Ki)
  2. H函数通常情况下与密钥有关,若无关,则最后一次使用H函数的过程可以取消掉,因为已经它的逆运算是已知的。

Blowfish加密算法

分组算法,分组大小为64bit,密钥长度在32-448bit之间。是一个16轮Feistel加密的、使用大量与密钥相关的S-box的算法(DES也是16轮Feistel加密、使用大量S-box,但是使用的S-box是固定的)。

在这里插入图片描述

算法步骤为:

在该算法中,P-box和S-box是固定的,一般情况下使用 π \pi π的小数部分每32位为一组对P-box和S-box分别进行赋值(其中P-box大小位32bit,共18个,S-box大小为32bit×256,共四个),在加密过程中,根据密钥Key对P-box和S-box进行变换(也就是所谓的和密钥相关的S-box),然后根据变换后的P-box和S-box执行Feistel过程;

  1. 首先根据 K i K_i Ki对P-box和S-box进行变换;

  2. 将明文分成两部分 L 0 、 R 0 L_0、R_0 L0R0

  3. L 0 L_0 L0与根据 K i K_i Ki进行变换的P-box进行异或操作,然后将得到的32bit结果传入四个根据 K i K_i Ki进行变换的S-box进行处理;

  4. 将四个S-box的输出 S i , 1 , S i , 2 , S i , 3 , S i , 4 S_{i,1},S_{i,2},S_{i,3},S_{i,4} Si,1,Si,2,Si,3,Si,4做如下操作,形成新一轮的 L i + 1 L_{i+1} Li+1 R i + 1 R_{i+1} Ri+1

    L i + 1 = ( ( ( S i , 1 ⊞ S i , 2 ) ⊕ S i , 3 ) ⊞ S i , 4 ) ⊕ R i R i + 1 = L i ⊕ K i L_{i+1}=(((S_{i,1} \boxplus S_{i,2}) \oplus S_{i,3}) \boxplus S_{i,4}) \oplus R_i\\R_{i+1}=L_i \oplus K_i Li+1=(((Si,1Si,2)Si,3)Si,4)RiRi+1=LiKi

  5. 步骤3-4是完整的一轮,共重复16轮;

  6. 在完成16论迭代后,首先把上一轮最后交换的L和R交换回来,然后使用 K 17 、 K 18 K_{17}、K_{18} K17K18分别对交换后的L和R进行异或操作,然后将两部分结果结合起来形成最终的加密结果。

参考

本文参考了百度百科、Wiki百科,以及众多的博客文章等,因为涉及的来源过多,就不一一列举了,在此向上述内容贡献者表示感谢。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐