综述

SPN线性密码分析:

  • 基于S盒子逼近的分析方法;
  • 是已知明文的分析方法,需要较多的名密文对;
  • 此方法只能分析最后一轮子密钥,缩小了密钥穷举范围(当分析出最后一轮密钥时,由于密钥生成算法固定,因此也为分析第一轮密钥提供了可能)。

相关概念

  • 定义对于{0,1}\{0,1\}{0,1}上的离散随机变量XiX_iXi​,pi=P(Xi=0)p_i=P(X_i=0)pi​=P(Xi​=0)。
  • 定义XiX_iXi​的偏差为:ϵi=pi−12\epsilon_i=p_i-\frac{1}{2}ϵi​=pi​−21​。
  • 堆积引理: 设Xi1,Xi2,…,XikX_{i_1},X_{i_2},\dots,X_{i_k}Xi1​​,Xi2​​,…,Xik​​是独立随机变量,ϵi1,ϵi2,…,ϵik\epsilon_{i_1},\epsilon_{i_2},\dots,\epsilon_{i_k}ϵi1​​,ϵi2​​,…,ϵik​​分别表示随机变量Xi1,Xi2,…,XikX_{i_1},X_{i_2},\dots,X_{i_k}Xi1​​,Xi2​​,…,Xik​​的偏差,那么对变量Xi1⨁Xi2⨁⋯⨁XikX_{i_1}\bigoplus X_{i_2}\bigoplus \dots\bigoplus X_{i_k}Xi1​​⨁Xi2​​⨁⋯⨁Xik​​的偏差,则有:ϵi1,i2,…,ik=2k−1∏j=1kϵij\epsilon_{i_1,i_2,\dots,i_k}=2^{k-1}\prod_{j=1}^{k}\epsilon_{i_j}ϵi1​,i2​,…,ik​​=2k−1∏j=1k​ϵij​​。

线性分析过程

  • 收集大量明密文对;
  • 选择一个固定的输入位in(x,y)=(∑i=14⊕aixi)⊕(∑i=14⊕biyi)in(x,y)=(\sum_{i=1}^{4}\oplus a_ix_i)\oplus(\sum_{i=1}^{4}\oplus b_iy_i)in(x,y)=(∑i=14​⊕ai​xi​)⊕(∑i=14​⊕bi​yi​),如:选择x1⊕x3⊕y2x_1\oplus x_3\oplus y_2x1​⊕x3​⊕y2​;
  • 通过收集的明密文对,根据上面构造的in(x,y)in(x,y)in(x,y)来构建线性逼近表;
  • 根据输入,选取线性逼近表中偏差最大的作为输出,找到对应位置进行输入;再根据线性逼近表找到输出;以此类推,构建出线性逼近链(偏差越大,越具有线性关系);
  • 根据该线性逼近链,通过将中间过程中的输入输出相异或来化简过程,最终化简为只剩下输入和最后一轮输入异或的关系式test()test()test();
  • 遍历所有可能的密钥,遍历所有收集到的明密文对,通过y和当前测试的密钥计算出最后一轮输入,将该值带入关系式test()test()test()中,若该关系式为0,则该密钥对应countcountcount值加1;
  • 遍历结束后输出countcountcount值最大的密钥。

线性分析原理

线性分析基于三个事实:

  • 找到一组S盒子,对于输入明文XXX在经过该S盒子后,将得到固定的密文YYY,我们可以列出所有明文XXX对应的密文YYY的情况。选出需要的“逼近中的活动S盒”,计算这些活动S盒中输入随机变量和输出随机变量的异或的偏差。并利用堆积引理计算这些“逼近中的活动S盒”的总偏差。
  • 根据输入随机变量经过这些S盒子的过程可以推算出仅包含明文比特和S盒子最后一轮输入比特的关系式。而通过已知的密文YYY即可反推回最后一轮的输出值,再反推回最后一轮的输入值。这样我们便可以计算该关系式。
  • 令X=(x1,x2,…,xn)X=(x_1,x_2,\dots,x_n)X=(x1​,x2​,…,xn​),其对应的加密值Y=(y1,y2,…,yn)Y=(y_1,y_2,\dots,y_n)Y=(y1​,y2​,…,yn​),即Y=πs(X)Y=\pi_s(X)Y=πs​(X)。
    因此必有X⊕Y=0X\oplus Y=0X⊕Y=0。换言之,对于任意情况下的变量X、YX、YX、Y,若存在关系X⊕Y=0X\oplus Y=0X⊕Y=0,则必有 YYY为XXX的对应密文。

因此,当我们遍历可能的密钥空间,并计算相应的关系式的值,当为0时我们进行计数(为0表示此时明文与密文对应),结束后输出计数值最大的密钥,密钥越正确,对应的明密文则越多。
实际上真正的密钥计数器值应接近12±ϵ\frac{1}{2}\pm\epsilon21​±ϵ,因为12±ϵ=pi=P(X⊕Y=0)\frac{1}{2}\pm\epsilon=p_i=P(X\oplus Y=0)21​±ϵ=pi​=P(X⊕Y=0)。

代码


  首先使用书中给出的线性分析链,分析出第5轮第2、4部分的密钥。再选择新的线性分析链,在第2、4部分密钥已知的基础上分析出第1、3部分的密钥。接着在已知起始密钥低16位的基础上,穷举高16位密钥对给出的8000个明密文对进行验证。由于在加密过程中进行了5轮的S代换和P置换,导致相同明文在不同密钥下得到相同密文的概率极低,因此在实际验证过程中并不需要验证8000个明密文对是否对应,而仅需验证3个即可判断出密钥是否合适。
  需要注意的是:第一,由于虽然可以选取到仅包含第5轮第1、3部分的线性分析链,但是由于偏差不大,因此代表性较差,可能导致对于1、3部分密钥可能性较大部分的遍历过多,而导致时间开销较大,所以自选的线性分析链应该首先选择偏差较大的链条(尽管该链条可能还包含第5轮第2或第4部分密钥)。第二,由于线性分析是基于概率的分析,因此count值最大的并不一定是真正密钥,因此需要在一定范围内遍历count值较大的所有可能密钥并进行验证。
  基于以上两点,需要有两层主循环,第一层主循环遍历可能的第5轮第2、4部分密钥,第二层在已知第5轮第2、4部分密钥的基础上生成并遍历可能的第5轮第1、3部分密钥,同时穷举高16位密钥并进行验证。
综上程序流程为:读入明密文对并存入数组;根据明密文对和书中已知线性分析链计算第5轮第2、4部分密钥对应的count值并存起来;开始两层循环;找到后退出循环并输出结果。
  读入和输出采用快速读入和输出。

#include <stdio.h>
#include <string.h>
#define abs(a) {if(a >= 4000) a -= 4000; else a = 4000 - a;}
typedef unsigned short ushort;
typedef unsigned int uint;const int MAX = 8005;
int n, count13[2][16][16], cnt13[16][16], cnt24[16][16];
ushort plaintext[MAX], ciphertext[MAX], tail_key;
int key51, key52, key53, key54;
uint key;//SPN statement
const unsigned short sBox_4[16] = {0xe, 0x4, 0xd, 0x1, 0x2, 0xf, 0xb, 0x8, 0x3, 0xa, 0x6, 0xc, 0x5, 0x9, 0x0, 0x7};
const unsigned short inverse_sBox[16] = {0xe, 0x3, 0x4, 0x8, 0x1, 0xc, 0xa, 0xf, 0x7, 0xd, 0x9, 0x6, 0xb, 0x2, 0x0, 0x5};
const unsigned short pos[17] = {0x0,0x8000, 0x4000, 0x2000, 0x1000,0x0800, 0x0400, 0x0200, 0x0100,0x0080, 0x0040, 0x0020, 0x0010,0x0008, 0x0004, 0x0002, 0x0001};
const unsigned short pBox[17] = {0x0,0x8000, 0x0800, 0x0080, 0x0008,0x4000, 0x0400, 0x0040, 0x0004,0x2000, 0x0200, 0x0020, 0x0002,0x1000, 0x0100, 0x0010, 0x0001};
unsigned short sBox_16[65536], spBox[65536];void get_spBox(){  //获得spBox for(int i = 0; i < 65536; ++i){sBox_16[i] = (sBox_4[i >> 12] << 12) | (sBox_4[(i >> 8) & 0xf] << 8) | (sBox_4[(i >> 4) & 0xf] << 4) | sBox_4[i & 0xf];spBox[i] = 0;for(int j = 1; j <= 16; ++j){if(sBox_16[i] & pos[j]) spBox[i] |= pBox[j];}}
}inline ushort read(){char ch;ushort buf = 0;for(int i = 0; i < 4; ){ch = getchar();if(ch >= '0' && ch <= '9'){buf = (buf << 4) | (ch ^ 48);i++;}else if(ch >= 'a' && ch <= 'z'){buf = (buf << 4) | (ch - 'a' + 10);i++;}}return buf;
}void output(){char buf[8];  //输出缓冲区for(int i = 0; i < 8; ++i){buf[7 - i] = key & 0xf;if(buf[7 - i] < 10) buf[7 - i] += '0';else buf[7 - i] = (buf[7 - i] - 10) + 'a'; key >>= 4;}for(int i = 0; i < 8; ++i) putchar(buf[i]);putchar('\n');
}inline void input(){for(int i = 1; i <= 8000; ++i){plaintext[i] = read();ciphertext[i] = read();}
}int main(){get_spBox();scanf("%d", &n);bool flag;ushort u1, u2, u3, u4;ushort x_init, y_init, z;ushort x[13], y[5];for(int i = 0; i < n; ++i){input();flag = false;//linear24();  //先分析第2、4位 memset(cnt24, 0, 256 * sizeof(int));for(int group = 1; group <= 8000; ++group){//提前处理要用到的对应位值 x_init = plaintext[group];for(int pos = 1; pos <= 12; ++pos){x[pos] = (x_init >> (16 - pos)) & 0x1;}y_init = ciphertext[group];for(int pos = 1, k = 12; pos <= 4; ++pos, k -= 4){y[pos] = (y_init >> k) & 0xf;}for(int L1 = 0; L1 < 16; ++L1){for(int L2 = 0; L2 < 16; ++L2){u2 = inverse_sBox[L1 ^ y[2]];u4 = inverse_sBox[L2 ^ y[4]];z = (x[5] ^ x[7] ^ x[8] ^ (u2 >> 2) ^ u2 ^ (u4 >> 2) ^ u4) & 0x1;if(!z) cnt24[L1][L2]++;}}}//处理count相加值for(int L1 = 0; L1 < 16; ++L1){for(int L2 = 0; L2 < 16; ++L2){abs(cnt24[L1][L2]);}}//外循环 for(int round24 = 0; round24 < 64; ++round24){//计算最大的2、4位对应密钥值 int max24 = -1;for(int L1 = 0; L1 < 16; ++L1){for(int L2 = 0; L2 < 16; ++L2){if(cnt24[L1][L2] > max24){max24 = cnt24[L1][L2];key52 = L1;key54 = L2;}}}cnt24[key52][key54] = 0;//根据2、4位对应密钥值计算1、3位对应密钥值; //linear13();memset(count13, 0, 512 * sizeof(int));for(int group = 1; group <= 8000; ++group){//提前处理要用到的对应位值 x_init = plaintext[group];for(int pos = 1; pos <= 12; ++pos){x[pos] = (x_init >> (16 - pos)) & 0x1;}y_init = ciphertext[group];for(int pos = 1, k = 12; pos <= 4; ++pos, k -= 4){y[pos] = (y_init >> k) & 0xf;}//开始计算count for(int L1 = 0; L1 < 16; ++L1){for(int L2 = 0; L2 < 16; ++L2){u1 = inverse_sBox[y[1] ^ L1];u2 = inverse_sBox[y[2] ^ key52];u3 = inverse_sBox[y[3] ^ L2];u4 = inverse_sBox[y[4] ^ key54];z = (x[1] ^ x[2] ^ x[4] ^ (u1 >> 3) ^ (u2 >> 3) ^ (u3 >> 3) ^ (u4 >> 3)) & 0x1;if(!z) count13[0][L1][L2]++;z = (x[9] ^ x[10] ^ x[12] ^ (u1 >> 1) ^ (u2 >> 1) ^ (u3 >> 1) ^ (u4 >> 1)) & 0x1;if(!z) count13[1][L1][L2]++;}}}//处理count相加值for(int L1 = 0; L1 < 16; ++L1){for(int L2 = 0; L2 < 16; ++L2){abs(count13[0][L1][L2]);abs(count13[1][L1][L2]);cnt13[L1][L2] = count13[0][L1][L2] + count13[1][L1][L2];}}for(int round13 = 0; round13 < 2; ++round13){int max13 = -1;for(int L1 = 0; L1 < 16; ++L1){for(int L2 = 0; L2 < 16; ++L2){if(cnt13[L1][L2] > max13){max13 = cnt13[L1][L2];key51 = L1;key53 = L2;}} }cnt13[key51][key53] = 0;tail_key = (key51 << 12) | (key52 << 8) | (key53 << 4) | key54;              //穷举int count, fore_key, k1, k2, k3, k4, k5;for(fore_key = 0; fore_key < 65536; ++fore_key){key = (fore_key << 16) | tail_key;//get_roundKey();k5 = tail_key;k4 = (key >> 4) & 0xffff;k3 = (key >> 8) & 0xffff;k2 = (key >> 12) & 0xffff;k1 = (key >> 16) & 0xffff;for(count = 1; count < 4; ++count){//encrypt: ciphertext = sBox_16[spBox[spBox[spBox[plaintext ^ k1] ^ k2] ^ k3] ^ k4] ^ k5; if((sBox_16[spBox[spBox[spBox[plaintext[count] ^ k1] ^ k2] ^ k3] ^ k4] ^ k5) != ciphertext[count]) break; }if(count == 4){flag = true;break;}}if(flag) break; }if(flag) break;}output();}return 0;
}

相关资料

差分分析【附code】

SPN线性密码分析【附code】相关推荐

  1. 线性分组码c语言实验报告,C语言线性分组码(附注释).doc

    C语言线性分组码(附注释).doc 下载提示(请认真阅读)1.请仔细阅读文档,确保文档完整性,对于不预览.不比对内容而直接下载带来的问题本站不予受理. 2.下载的文档,不会出现我们的网址水印. 3.该 ...

  2. C语言实现linear search线性搜索算法(附完整源码)

    实现linear search线性搜索算法 linear search线性搜索算法的完整源码(定义,实现,main函数测试) linear search线性搜索算法的完整源码(定义,实现,main函数 ...

  3. 图像线性灰度变换(附Matlab实现)

    图像的线性灰度变换还是比较有意思的,就是直接对灰度图的灰度值进行处理,一般来说符合一元线性方程: y=ax+b x是起使灰度值:y是经过处理的灰度值:a是图像对比度(知道电视里面的对比度是啥了吧):b ...

  4. qq好友列表获取导出,利用QQ协议实现好友数据备份,包含:qq好友、QQ分组、QQ群、qq群成员【附code源码】

    qq好友列表获取导出,利用QQ协议实现qq好友数据备份,包含:qq好友.QQ分组.QQ群.qq群成员. 我们是在浏览器中的操作,接下来看看数据到底怎么获取的,我们通过Fiddler的查找功能,就可以查 ...

  5. 利用对位相乘法计算线性卷积-附Matlab代码

    目录 1.线性卷积原理 2.利用对位相乘法计算线性卷积 3.Matlab实操 3.1源代码 3.2仿真结果 线性卷积原理 公示(1)为两个离散非周期序列进行线性卷积 一般我们计算线性卷积时使用图解法最 ...

  6. 【CF1100F】 Ivan and Burgers (分治+线性基)

    description 戳我看题目(づ ̄3 ̄)づ╭❤- solution 异或和最大 --关联线性基 线性基: 原序列的每一个数都能由线性基里若干个数异或得到 线性基里若干个数的异或结果不可能为0 如 ...

  7. [清华集训2015 Day1]玛里苟斯-[线性基]

    Description Solution 考虑k=1的情况.假设所有数中,第i位为1的数的个数为x,则最后所有的子集异或结果中,第i位为1的个数为$(C_{k}^{1}+C_{k}^{3}+...)$ ...

  8. 引导方法深度补全系列—基于SPN模型—1—《Depth estimation via affinity learned with convolutional spatial propagat》文章细读

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 创新点 方法详解 对比SPN 总结 创新点 1.改进了SPN网络,主要是更新方式上从串行扫描改为局部同时更新,也就是CSPN 网 ...

  9. matlab线性相位滤波器设计,关于第二类线性相位滤波器问题分析

    线性相位滤波器是移动相位与频率成比例的滤波器,因此不改变波形而引入一常数延迟.线性相位滤波器是一个混合相位的滤波器,它按照与频率成正比地对频率分量作时移.因而在通常频带内相位移与频率的关系图是线性的, ...

  10. AES和RSA前后端加解密

    先了解AES和RSA加密算法 AES算法 1.运算速度快,在有反馈模式.无反馈模式的软硬件中,Rijndael都表现出非常好的性能. 2.对内存的需求非常低,适合于受限环境. 3.Rijndael 是 ...

最新文章

  1. oracle如何查询虚拟列,Oracle11g新特性之--虚拟列(VirtualColumn)
  2. VPLS(Virtual Private LAN Service)
  3. 什么样的模型是好的模型 好的数据胜于好的特征,好的特征胜于好的算法
  4. 跟我学习php文件和目录常用函数-下篇
  5. SAP ECC6.0-中建信息版
  6. 教你解决ChartDirector Linux下中文乱码
  7. 到无限(溪流)和超越!
  8. 修改TOMCAT的JVM虚拟机内存大小几种方式
  9. 设定所有tableView中cell的分隔线颜色
  10. 精通javascript笔记(智能社)——数字时钟
  11. animation-fill-mode的一些思考
  12. LaTex写实验报告
  13. 3ds Max中Vray分布式渲染
  14. 钛资本研究院:保险科技行业现状及趋势分析
  15. exe后门程序生成之Quasar
  16. 误删阿里云mysql恢复数据恢复_阿里云数据库表数据误删恢复
  17. 【工具使用系列】PostScript工具 GhostScript,GSview,Epstool,RedMon
  18. $reday和window.onload()
  19. yarn打包报错:error during build: Error: Assigning to rvalue (Note that you need plugins to import files
  20. 教你一个快递查询单号查询物流的简单方法

热门文章

  1. 摘抄(SAP所有模块用户出口(User Exits) )
  2. B. Diverse Garland
  3. Oracle间隔(interval)分区
  4. Python绘制心形图案
  5. 2697v3只支持服务器内存,Intel 18核心E5-2697 v4实测:虐杀桌面顶级8核i7-5960X!
  6. Eclipse Mars2中Augular2开发环境的搭建过程记录
  7. Vue中使用echarts,echarts 封装以及使用的事项
  8. Android实现简单的欢迎界面
  9. Python可视化数据学习
  10. python+django大学教室自习室预约管理系统