求任意8比特数在AES的S-Box中的对应值

2024-05-26 11:08
文章标签 aes 对应 任意 box 比特 数在

本文主要是介绍求任意8比特数在AES的S-Box中的对应值,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目要求:

写一个程序,给定任意8比特数,可求其在S-Box中所对应的值。

首先上课的时候,由于老师经常提到查表得出结果什么的,所以一看到这道题我的第一反应就是首先把课本的S-Box表敲进去,然后直接用行号和列号来查。
后来听同学提醒才知道其实是要先求逆元,再用矩阵变换来计算得到S-Box转换结果。好吧,是我头脑太简单了,我认了。

记得以前看别人的程序经常看到一个大矩阵,当时觉得这是一个很酷的事,于是我也很傻逼地照做了。
先来看看这道题的傻瓜式做法:
#include <iostream>
#include <limits> //numeric_limits 
using namespace std;
int charToInt(char c);int main()
{//  -- 构造S-Box --char *sbox[16][16]={ {"63", "7C", "77", "7B", "F2", "6B", "6F", "C5", "30", "01", "67", "2B", "FE", "D7", "AB", "76"},{"CA", "82", "C9", "7D", "FA", "59", "47", "F0", "AD", "D4", "A2", "AF", "9C", "A4", "72", "C0"},{"B7", "FD", "93", "26", "36", "3F", "F7", "CC", "34", "A5", "E5", "F1", "71", "D8", "31", "15"},{"04", "C7", "23", "C3", "18", "96", "05", "9A", "07", "12", "80", "E2", "EB", "27", "B2", "75"},{"09", "83", "2C", "1A", "1B", "6E", "5A", "A0", "52", "3B", "D6", "B3", "29", "E3", "2F", "84"},{"53", "D1", "00", "ED", "20", "FC", "B1", "5B", "6A", "CB", "BE", "39", "4A", "4C", "58", "CF"},{"D0", "EF", "AA", "FB", "43", "4D", "33", "85", "45", "F9", "02", "7F", "50", "3C", "9F", "A8"},{"51", "A3", "40", "8F", "92", "9D", "38", "F5", "BC", "B6", "DA", "21", "10", "FF", "F3", "D2"},{"CD", "0C", "13", "EC", "5F", "97", "44", "17", "C4", "A7", "7E", "3D", "64", "5D", "19", "73"},{"60", "81", "4F", "DC", "22", "2A", "90", "88", "46", "EE", "B8", "14", "DE", "5E", "0B", "DB"},{"E0", "32", "3A", "0A", "49", "06", "24", "5C", "C2", "D3", "AC", "62", "91", "95", "E4", "79"},{"E7", "C8", "37", "6D", "8D", "D5", "4E", "A9", "6C", "56", "F4", "EA", "65", "7A", "AE", "08"},{"BA", "78", "25", "2E", "1C", "A6", "B4", "C6", "E8", "DD", "74", "1F", "4B", "BD", "8B", "8A"},{"70", "3E", "B5", "66", "48", "03", "F6", "0E", "61", "35", "57", "B9", "86", "C1", "1D", "9E"},{"E1", "F8", "98", "11", "69", "D9", "8E", "94", "9B", "1E", "87", "E9", "CE", "55", "28", "DF"},{"8C", "A1", "89", "0D", "BF", "E6", "42", "68", "41", "99", "2D", "0F", "B0", "54", "BB", "16"}};//  -- 输入要替换的字节并进行查表操作 --int row=0, column=0, i=0;char choose='y', *byte, temp;byte=new char[];while(choose=='y'||choose=='Y'){cout<<"请输入要替换的字节(如0E):";cin>>byte[0];cin>>byte[1];if(cin.get()!=10) // 如果没有输入回车{cout<<"输入字节长度错误"<<endl;cin.ignore(numeric_limits<streamsize>::max(),'\n'); // 清除输入缓冲区中的所有内容}else {row=charToInt(byte[0]); // 行号转换column=charToInt(byte[1]); // 列号转换 if(row==-1||column==-1){cout<<"字节输入错误"<<endl;}else{// 执行S-Box查表操作char *des=sbox[row][column];cout<<"S-Box变换结果为:";for(i=0; i<2; i++){cout<<des[i];}cout<<endl;}}cout<<endl<<"是否继续查表?y/n:";cin>>choose;}return 0;
}/* 将输入的字符转换为整数 */
int charToInt(char c)
{int x=(int)c;if(x>=48&&x<=57) // 0-9{return x-48;}else if(x>=65&&x<=70) // A-F{return x-55;}else if(x>=97&&x<=102) // a-f{return x-87;}else{return -1;}
}

思想很简单,构造S-Box对应的表格,用户输入一个2位十六进制数组例如0E,然后查表格中的第1行第15列也就是求sbox[0][14],最后输出结果。Run看看:


不能说这种方法错了,只能说是不符合老师的要求吧。

好吧,还是规规矩矩地直接用课本的转换方法做吧(来自CANS第五版5.3.1):
AES的S盒按如下方式构造:
(1)按字节值升序逐行初始化S盒(16 * 16),共256个。
(2)把S盒中的每个字节映射为它在GF(2^8)中的逆元,{00}被映射为它自身。
(3)记S盒中每个字节的8个构成位为(b7, b6, b5, b4, b3, b2, b1, b0),对S盒中的每个字节的每个位做如下的变换:b[i] ' = b[i] xor b[(i+4)mod8] xor b[(i+5)mod8] xor b[(i+6)mod8] xor b[(i+7)mod8] xor c[i]。其中(c7,c6,c5,c4,c3,c2,c1,c0)  = 01100011。

按照以上规则,若输入某个数a,对其进行S-Box转换的方法为:
(1)求 a的逆元a-1。00H的逆元为00H。
(2)对a-1进行矩阵变换,也就是对每一位进行以上(3)的操作。

分析完毕,看代码部分。
int main()
{   int a[8], b[8], c[8], i=0, bdec;int temp[8];char choose='y';bool finished;while(choose=='y'||choose=='Y'){//  -- 输入要转换的数a --int x=input(a, 'a');if(x==0) // 如果输入a没有出错{finished=false; // 初始设定尚未找到转换结果for(bdec=1; bdec<256; bdec++) // 枚举GF(2^8)中的数,寻找a[8]的逆元{if(finished==true) // 如果已经完成S-Box转换操作,就跳出枚举逆元的for循环break;//  -- 初始化程序的各个参数 --state=0; // 清空当前左移位数for(i=0; i<8; i++){c[i]=0; // 清空转换结果 temp[i]=a[i]; // 为了保存a[i]数组用于下一次循环,将a[8]数组赋予temp[8]}decToBin(bdec, b); // 将bdec转换为二进制数组b//  -- 执行乘法运算a*b,结果存到c中 --for(i=7; i>=0; i--){if(b[i]==1){xor(c, leftshift(temp, 7-i)); // 求和}}//  -- 判断是否逆元,如果是则进行转换并输出结果 --if(isInverse(c)==true) // 如果c是1,即b为a的逆元{matrixTrans(b, temp); // 进行矩阵计算变换finished=true; // 完成S-Box转换}}}else if(x==-1) // 如果输入了00000000,那么S-Box变换结果为63H{cout<<"01100011";}//  -- 是否继续执行程序 --cout<<endl<<endl<<"是否继续?y/n:";choose=cin.get();if(cin.get()==10){// 跳过输入y/n后的回车键,防止影响下面的输入}}return 0;
}
主函数的流程很简单:输入数a —— 求a的逆元a-1(如果为0,直接输出01100011) —— 对a-1进行矩阵变换并输出转换结果 —— 是否循环执行。
其中在求a的逆元时,涉及到扩展Euclid算法,那个真心不会,而且光是用手来写表格求都麻烦,更别提用代码实现(个人看法),加上GF(2^8)中最多才256个数(去掉0的话255个),所以决心从1到255枚举GF(2^8)求逆元。


input函数和之前的在GF(2^8)下可做任意两个数乘法的程序(一)略有变化,加上了输入为00000000的返回结果为-1:
/* * 分别输入两个GF(8)内的乘数 * 参数temp[]用于保存输入的二进制数组* 参数name为变量名称,如a,b* 返回结果为输入后的状态,若为0则成功,若为-1表示输入的数为00000000,若非0或-1则出错*/
int input(int temp[], char name)
{char c;int i=0;cout<<"请按8位二进制格式输入乘数"<<name<<",以回车结束:";c=cin.get();while(c!=10) // 若输入的不是回车{switch(c){case '0':temp[i++]=0;break;case '1':temp[i++]=1;break;default:cout<<"程序出错:数字输入错误,不是0或1";cin.ignore(numeric_limits<streamsize>::max(),'\n'); // 清除输入缓冲区中的所有内容return 1;}c=cin.get();if(c==10&&i!=8){cout<<"程序出错:输入的数位数不等于8";return 2;}}int sum=0;for(i=0; i<8; i++){sum+=temp[i];if(sum>0){return 0;}}if(sum==0){return -1; // 输入的二进制数为00000000}return 0;
}

在枚举求a的逆元时,假设该数的十进制形式为bdec,先要转换成二进制数组b,再计算a * b,若结果为00000001,那么b为a的逆元。在这里涉及到十进制转换为二进制decToBin,以及判断是否逆元isInverse两个函数:
/* 将十进制数转换为二进制数组 */
void decToBin(int d, int b[])
{int i=7;while(i>=0){b[i--]=d%2;d/=2;}
}/* 在枚举寻找逆元时,判断其乘积结果是否为00000001 */
bool isInverse(int c[])
{for(int i=0; i<7; i++){if(c[i]!=0)return false;}if(c[7]==1){return true;}else {return false;}
}

乘法所用到的leftshift, shift1, xor, bitxor函数沿用了在GF(2^8)下可做任意两个数乘法的程序(一) 中的函数(感受到了Java老师所说的代码复用的思想)。

在求出逆元后,再对其进行矩阵变换即得到结果,使用了matrixTrans函数:
/* 将二进制数组进行S-Box的矩阵转换 */
void matrixTrans(int b[], int nb[])
{// 由于在每次行列求乘积的时候b要保持不变,所以将b复制一份给nbfor(int i=0; i<8; i++){nb[i]=b[i];}// nb[i]=b[i] xor b[i+1] xor b[i+2] xor b[i+3] xor b[i+4] xor (01100011中的对应位)for(i=0; i<8; i++){nb[i]=bitxor(nb[i], b[(i+4)%8]);nb[i]=bitxor(nb[i], b[(i+3)%8]);nb[i]=bitxor(nb[i], b[(i+2)%8]);nb[i]=bitxor(nb[i], b[(i+1)%8]);if(i==0||i==3||i==4||i==5){nb[i]=bitxor(nb[i], 0);}else{nb[i]=bitxor(nb[i], 1);}}cout<<"转换结果为:";for(i=0; i<8; i++){cout<<nb[i];}
}

完成。Run一下看看(运行结果可以对比CANS第五版表5.2看看)


比较两种方法,明显第一种方法运行效率更高,是用开发者的开发效率换来的。很可惜不符合老师要求。
第二种方法用了枚举方法来求逆元,由于GF(2^8)最多才256个数,所以对程序运行效率影响不大,但是如果该域数量变得很大,那就只能用其它方法来求逆元了。

好吧,AES的S-Box会做了(尽管算法并不够好),等我学到了新东西再更新吧。

这篇关于求任意8比特数在AES的S-Box中的对应值的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1004294

相关文章

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果: 解密后的数据就是正常数据: 后端:使用的是spring-cloud框架,在gateway模块进行操作 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency> 编写一个AES加密

论文翻译:ICLR-2024 PROVING TEST SET CONTAMINATION IN BLACK BOX LANGUAGE MODELS

PROVING TEST SET CONTAMINATION IN BLACK BOX LANGUAGE MODELS https://openreview.net/forum?id=KS8mIvetg2 验证测试集污染在黑盒语言模型中 文章目录 验证测试集污染在黑盒语言模型中摘要1 引言 摘要 大型语言模型是在大量互联网数据上训练的,这引发了人们的担忧和猜测,即它们可能已

linux 内核提权总结(demo+exp分析) -- 任意读写(四)

hijack_modprobe_path篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm     原理同hijack_prctl, 当用户执行错误格式的elf文件时内核调用call_usermod

linux 内核提权总结(demo+exp分析) -- 任意读写(三)

hijack_prctl篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   prctl函数: 用户态函数,可用于定制进程参数,非常适合和内核进行交互 用户态执行prctl函数后触发prctl系统

linux 内核提权总结(demo+exp分析) -- 任意读写(二)

hijack_vdso篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm     vdso: 内核实现的一个动态库,存在于内核,然后映射到用户态空间,可由用户态直接调用 内核中的vdso如果被修改

linux 内核提权总结(demo+exp分析) -- 任意读写(一)

cred篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   每个线程在内核中都对应一个线程结构块thread_infothread_info中存在task_struct类型结构体 struct t

定位cpu占用过高的线程和对应的方法

如何定位cpu占用过高的线程和对应的方法? 主要是通过线程id找到对应的方法。 1 查询某个用户cpu占用最高的进程号 top -u 用户名 2 查询这个进程中占用cpu最高的线程号 top –p 进程号-H    3 查询到进程id后把进程相关的代码打印到jstack文件 jstack -l pid > jstack.txt 4 在jstack文件中通过16进制的线程id搜索到

一台电脑对应一个IP地址吗?‌探讨两台电脑共用IP的可能性

在当今数字化时代,‌IP地址作为网络世界中的“门牌号”,‌扮演着至关重要的角色。‌它负责在网络上唯一标识每一台设备,‌使得数据能够在庞大的互联网中准确无误地传输。‌然而,‌对于IP地址与电脑之间的对应关系,‌许多人可能存有疑惑:‌一台电脑是否必须对应一个IP地址?‌两台电脑又是否可以共用一个IP地址呢?‌本文将深入探讨这些问题,‌带您一窥IP地址背后的奥秘。‌ 一台电脑对应一个IP地址吗?‌

git如何灵活切换本地账号对应远程github的两个账号

git如何灵活切换本地账号对应远程github的两个账号 问题: 有时候我们会同时维护两个github的账号里面的仓库内容,这时候本地git需要频繁的切换ssh,以方便灵活的与两个账号的仓库可以通信。这篇日记将阐述我是怎么解决这个问题的。1. 第一个账户 生成本地SSH2. 注意 我们要设置第二个账户的 本地 SSH 时3. 两个账号来回切换 问题: 有时候我们会同时维护两个git