S-DES加密算法的分析与代码实现(C语言)

目录

基本概念

打印函数

子密钥生成

初始化必要数组

获取初始密钥k 

 获取初始密钥k的十个二进制位

获取PC-1

转换字符数组至整型数组 

利用PC-1改变数组K中元素的排列顺序

拆分元素顺序改变后的数组K

拆分后数组元素向左循环位移

将左移后的数组合并

获取PC-2

获取子密钥K1 

 将之前拆分后的数组元素再次向左循环位移

将二次左移后的数组继续合并成新数组

获取子密钥K2

明文加密

初始化必要数组

获取明文数组s 

获取明文数组s的十个二进制位

获取初始换位IP  

 利用IP改变数组SGroup中元素的排列顺序

第一轮迭代运算 

拆分元素顺序改变后的数组SGroup

存储第一轮迭代运算中的右值作为第二次迭代运算的左值

获取EP

EP扩展右值数组

扩展后的右值数组与子密钥K1进行异或运算形成新数组

缩小并分割新数组的两个子数组 

获取P

合并分割并缩减后的数组 

利用P改变数组ORALL中元素的排列顺序 

获取第二轮右值 

第二轮迭代运算 

存储第二轮迭代运算中的右值作为最终结果的左值

EP扩展右值数组

扩展后的右值数组与子密钥K2进行异或运算放入原XOR数组(更新XOR数组)

缩小并分割XOR数组的两个子数组(更新OR0和OR1) 

合并分割并缩减后的数组 

利用P改变数组ORALL中元素的排列顺序  

获取最终结果的左值 

合并最终结果的左值和右值

获取逆置换IP

获取最终密文 

 完整代码

test.h文件

encrypt.c文件

keys.c文件

public.c文件

test.c文件


基本概念

        S-DES(Simplified-DES)是DES算法的简易版本,该算法作用于8比特的数据分组,初始密钥为10比特的数据分组。

        初始有效密钥首先进入PC-1置换,并分为C0、D0两部分,每部分5比特;两部分分别循环左移1位,得到C1、D1;C1、D1经过PC-2置换后得到子密钥k1;C1、D1分别循环左移2位得到C2、D2,C2、D2进入PC-2置换后得到子密钥k2,子密钥生成过程如下图所示:

        明文数据分组首先进行IP置换,置换后的数据经过两次迭代运算,迭代运算开始时,置换后数据被分为两部分,每部分4bit大小。在第1次迭代运算中,右值作为新一轮的左值;右值通过F( )函数与子密钥结合后,再与左值异或运算,得到新一轮的右值。在第2次迭代运算中,右值作为输出结果的右值,右值通过F( )函数与子密钥结合后,再与左值异或运算,得到输出结果的左值。将迭代运算的结果进行IP-1运算得到加密后的8比特密文,密文生成过程如下图所示:

        F( )函数的执行过程为:右值经过EP扩展为8比特,与8比特的子密钥进行异或运算;结果进入两个S盒,每个S盒输入4比特,输出2比特;输出结果合并后放入P盒置换:

打印函数

打印函数地位很重要😍,不然你怎么知道你每一步到底对了没有?

//打印各类数组
void printfArray(int* arr, int size)//(要打印的数组名,数组大小)
{
	for (int i = 0; i < size; i++)
	{
		printf("%d ", *(arr + i));//arr[i];
	}
	system("pause");//暂停程序只有按任意键后才会继续执行:为检查结果是否正确提供时间
	printf("\n");
	system("cls");//清屏:为下一次的输入或者打印数组留出足够的空间(腾位置)
}

子密钥生成

初始化必要数组

int k;                     //初始密钥(十进制整数)
int K[10];                 //存放初始密钥的前十个二进制比特位的整型数组
char TempPC[10];           //用于存放输入的PC-1字符的临时数组
char TempPC2[8];           //用于存放输入的PC-2字符的临时数组
int PC1[10], PC2[8];       //整型数组PC-1和PC-2
int K1[8], K2[8];          //存放子密钥K1和K2的整型
int C0[5], D0[5];          //被分割的数组C0和D0
int C1D1[10], C2D2[10];    //合并后数组C1D1和C2D2

获取初始密钥k 

        需要人为输入指定的整数作为初始密钥,getchar()用于清除scanf函数输入后在输入缓冲区中留下的换行符‘\n’ (没有会导致后序人为输入其他数组时报错),system("cls")用于清屏,保证代码的美观性(需要包含<stdlib.h>头文件):

printf("请输入初始密钥k的值:");
scanf("%d", &k);
getchar();
system("cls");

 获取初始密钥k的十个二进制位

        由于我们输入的数据在代码执行过程中最终都是以其对应的二进制补码形式存在的,一般为32位,而明文数组和初始密钥对应的二进制位数只需要10个二进制位,所以需要人为截断它们的补码并将截断结果放入相应的数组中:

//获取初始密钥k的十个二进制位放入数组K
int sz = sizeof(K) / sizeof(K[0]);    //获取数组K的大小
GetLimitedArray(K, k, sz);            //(数组K,初始密钥的十进制整数,要获得的二进制个数)
printf("数组K:\n");
printfArray(K, sz);                   //打印数组K

//获取有限的二进制位组成的数组
void GetLimitedArray(int* arr, int num, int size)
{
	for (int i = size - 1; i >= 0; i--)  //不能交换int i = szie-1; i >= 0的顺序,否则二进制就是0010010000,倒着来了明显不符合要求
	{
		*(arr + i) = num % 2;//arr[i] = num % 2,利用%获取该数的二进制位
		num = num / 2; //利用/使得该数不断减小
		//%和/的使用是基于十进制转二进制的计算办法
	}
}

获取PC-1

        我们这里获得的只是字符数组,但是我们为了后序使用的方便还需要将该字符数组转变为整型数组,不过那就是TransformArray(TempPC,PC1,sz)该干的活儿了(能力有限关于输入字符数组这一块直接用占位符写了,写循环的时候总会出错)

//获取PC-1
sz = sizeof(TempPC) / sizeof(TempPC[0]);//更新此时sz的值
GetPC(TempPC, sz);
getchar();
sz = sizeof(PC1) / sizeof(PC1[0]);//更新此时sz的值
TransformArray(TempPC,PC1,sz);
printf("输入的PC-1:\n");
printfArray(PC1, sz);

//获取包含字符的PC数组
void GetPC(char* arr, int size)//(字符数组,字符数组大小)
{
	printf("向PC数组中写入%d个数据:\n",size);
	scanf("%c %c %c %c %c %c %c %c %c %c", &arr[0], &arr[1], &arr[2], &arr[3], &arr[4], &arr[5], &arr[6] ,&arr[7] ,&arr[8], &arr[9]);
}

转换字符数组至整型数组 

        输入字符数组中的元素只有能是0~10,A~F,对于那些0~10的字符可以在判断是否属于'0'~'9'范围内,如果是将该字符转为对应的整数:

根据ASCII码我们可以知道:

'1' - '0' = 49 - 48 = 1

'3' - '0' = 51 - 48 = 3

所以,一个数字加上字符'0'就可以得到它的字符型。即:

1 +  '0' = 1 + 48 = 49 =  '1'

3 +  '0' = 3 + 48 = 51 =  ‘3’

        同时对于A~F而言,我们想要的其实是十六进制的A所代表的十进制数10,但是在程序运行中我们字符A只能其相应的ASCII码值,所以我们可以人为规定,一个字符的ASCII码值为65的,可以将整数10赋值给接收该字符ASCII码值的整数变量......(可以循环实现也可以向下面这样用switch语句实现)

//转换字符数组至整型数组
void TransformArray(char* arr1, int* arr2, int size)//(字符数组,整型数组,整型数组大小)
{
	for (int i = 0; i < size; i++)
	{

		if (arr1[i]>='0' && arr1[i] <= '9')//元素为整数就利用atoi函数将该字符转换为对应的整数
		{
			arr2[i] = arr1[i] - '0';
		}
		else
		{
			int num = arr1[i];
			switch (num)
			{
			case 65:
				arr2[i] = 10;
				break;
			case 66:
				arr2[i] = 11;
				break;
			case 67:
				arr2[i] = 12;
				break;
			case 68:
				arr2[i] = 13;
				break;
			case 69:
				arr2[i] = 14;
				break;
			case 70:
				arr2[i] = 15;
				break;
			}
		}
	}
}

atoi函数:http://t.csdnimg.cn/Pndqt

利用PC-1改变数组K中元素的排列顺序

//利用PC1改变数组K的内容
sz = sizeof(K) / sizeof(K[0]);//更新此时sz的值
Mapping(K, PC1, sz);//(数组K,数组PC1,数组K大小),K和PC1大小相同
printf("最新的初始密钥数组K:\n");
printfArray(K, sz);

设定临时数组,用于存放原数组中的数据(排列顺序),然后进行原数组中元素顺序的更改,如果不这样做会导致出错(也可能不会,你可以尝试只留最后一个for循环试试😘) 

//映射改变原数组中二进制数的排列顺序(处理映射后不形成新数组只在原本数组上进行更改的情况)
void Mapping(int* arr1, int* arr2, int size)//(原数组名,映射数组名,数组大小)
{
	int arr[100];//设定一个足够大的临时数组,如果利用临时数组就会导致PC1 + K的结果不为0100000010,而是0110000000
	int* temp = arr;//temp指向该临时数组(可要可不要)
	for (int i = 0; i < size; i++)
	{
		*(arr + i) = *(arr1 + i);//将原数组内容拷贝给临时数组
	}
	for (int i = 0; i < size; i++)
	{

		*(arr1 + i) = *(temp + *(arr2 + i) - 1);//arr1[i] = temp[arr2[i] - 1] 或 arr1[i] = arr[arr2[i] - 1]
	}
}

拆分元素顺序改变后的数组K

//将数组K拆分为两个大小相同的数组C0和D0
sz = sizeof(C0) / sizeof(C0[0]);//更新此时sz的值,
Split(K, C0, D0, sz);//(数组K,子数组C0,子数组D0,子数组C0大小),子数组C0和D0大小相同
printf("数组C0:\n");
printfArray(C0, sz);
printf("数组D0:\n");
printfArray(D0, sz);

        也很简单,无非就是将两个已经半初始化的空数组以及元素顺序改变后的数组K传入Split函数中,然后利用for循环将对K数组根据下标进行分割(由于是S-DES算法的数组都是偶数个就使得这一步骤不需要考虑奇数的问题可以更容易实现) 

//分离数组
void Split(int* arr1, int* arr2, int* arr3, int size)//(原数组名,子数组名,子数组名,子数组大小),默认子数组大小相同
{
	int temp = size;//用temp获取size的值,如果不用temp可能会导致i的范围由于size++而发生变化,影响arr2
	for (int i = 0; i < size; i++)
	{
		*(arr2 + i) = *(arr1 + i);//arr2[i] = arr1[i]
		*(arr3 + i) = *(arr1 + temp);//arr3[i] = arr1[temp]
		temp++;
	}
}

拆分后数组元素向左循环位移

        需要注意的是,我们这里要的是循环左移(比如10000循环左移一位的结果是00001,而不是00000那样子的覆盖左移),在循环左移时,每次移动开始前令临时变量temp存储当前数组首元素,然后再将数组的元素向前覆盖移动(下标大的元素赋值给它前面下标比它小一个的元素)最后将temp中存放的原数组起始的元素赋值给数组尾元素即可

//将C0和D0数组均左移一位
sz = sizeof(C0) / sizeof(C0[0]);//更新此时sz的值
int num = 1;//左移次数
ShiftArray(C0, num, sz);//(子数组C0,左移次数,数组C0大小)
ShiftArray(D0, num, sz);//(子数组D0,左移次数,数组C0大小),,子数组C0和D0大小相同
printf("左移一位后的数组C0:\n");
printfArray(C0, sz);
printf("左移一位后的数组D0:\n");
printfArray(D0, sz);
//左移数组
void ShiftArray(int* arr,int num,int size)  //(数组名,左移次数,数组大小)
{
	for (int i = 0; i < num; i++)
	{
		int temp = arr[0];//temp存放每次循环前的数组首元素
		//开始移位,将数组后一个元素的值赋值给前一个元素
		for (int j = 0; j < size - 1; j++)
		{ 
			*(arr + j) = *(arr + j + 1);//arr[j] = arr[]
		}
		arr[size - 1] = temp;  //将存放的原来arr[0]的值赋值给数组尾元素
	}
}

将左移后的数组合并

        将准备好的半初始化的空数组以及两个被分割的数组传入Combine函数中,向分割它们时候一样,根据下标索引将两个分割数组放入空数组中(注意,放入的顺序,左值子数组C0要先放入空数组中)

//将左移一次的子数组C0和D0合并成数组C1D1
sz = sizeof(C1D1) / sizeof(C1D1[0]);//更新此时sz的值
Combine(C0, D0, C1D1, sz);//(子数组C0,子数组D0,数组C1D1,数组C1D1大小)
printf("合并后的数组C1D1:\n");
printfArray(C1D1, sz);
//合并数组
void Combine(int* arr1, int* arr2,int* arr3,int size)//(合并子数组名,合并子数组名,合并数组名,合并后数组大小)
{
	for (int i = 0; i < size/2; i++)//这里可以直接size/2的原因是数组都是偶数
	{
		*(arr3 + i) = *(arr1 + i);  //arr3[i] = arr1[i] 第一个子数组拷贝至合并数组(如何对应下标自己思考不予解释)
	}

	for (int j = 0; j < size/2; j++)
	{
		*(arr3 + size/2 + j) = *(arr2 + j);//arr3[size / 2 + j] = arr2[j] 第二个子数组拷贝至合并数组
	}
}

获取PC-2

        与获取PC-1基本一致,但是GetPC2函数中的scanf只有8个%c(因为规定的PC-2只有八个比特位):

//获取PC-2
sz = sizeof(TempPC2) / sizeof(TempPC2[0]);//更新此时sz的值
GetPC2(TempPC2, sz);
getchar();
sz = sizeof(PC2) / sizeof(PC2[0]);//更新此时sz的值
TransformArray(TempPC2, PC2, sz);
printf("输入的PC-2:\n");
printfArray(PC2, sz);
//获取包含字符的PC2数组
void GetPC2(char* arr, int size)//(字符数组,字符数组大小)
{
	printf("向PC数组中写入%d个数据:\n", size);
	scanf("%c %c %c %c %c %c %c %c", &arr[0], &arr[1], &arr[2], &arr[3], &arr[4], &arr[5], &arr[6], &arr[7]);
}

//转换字符数组至整型数组
void TransformArray(char* arr1, int* arr2, int size)//(字符数组,整型数组,整型数组大小)
{
	for (int i = 0; i < size; i++)
	{

		if (arr1[i]>='0' && arr1[i] <= '9')//遍历input数组的每一个元素,如果该元素为整数就利用atoi函数将该字符转换为对应的整数,比如“123” -> 123
		{
			arr2[i] = arr1[i] - '0';
		}
		else
		{
			int num = arr1[i];
			switch (num)
			{
			case 65:
				arr2[i] = 10;
				break;
			case 66:
				arr2[i] = 11;
				break;
			case 67:
				arr2[i] = 12;
				break;
			case 68:
				arr2[i] = 13;
				break;
			case 69:
				arr2[i] = 14;
				break;
			case 70:
				arr2[i] = 15;
				break;
			}
		}
	}
}

获取子密钥K1 

//获取子密钥K1
sz = sizeof(K1) / sizeof(K1[0]);//更新此时sz的值
SecondMapping(C1D1, PC2, K1, sz);//(合并数组C1D1,PC2数组,子密钥数组K1,子密钥数组K1大小)
printf("子密钥数组K1:\n");
printfArray(K1, sz);

        相比于Mapping,SecondMapping适用于处理映射后会形成新数组的问题,Mapping是针对映射后不形成新数组只在原本数组上进行更改的情况(题目要求将十进制位缩小为八进制位,忘了重新回去看流程图,对于获取子密钥K2也是这样的):

//获取子密钥(处理映射后会形成新数组的情况)
void SecondMapping(int* arr1, int* arr2, int* arr3, int size)//(原数组名,映射数组名,新数组名,新数组大小)
{
	for (int i = 0; i < size; i++)
	{
		*(arr3 + i) = *(arr1 + *(arr2 + i) - 1); //arr3[i] = arr1[arr2[i]-1]; 
	}
}

 将之前拆分后的数组元素再次向左循环位移

        这次是在原先基础上继续向左位移两次,因为原先拆分后的数组我们并未对其进行更改,只是使用了它们合并后的数组,所以这里可以继续使用:

//将C0和D0数组在原有基础上继续左移两位
sz = sizeof(C0) / sizeof(C0[0]);//更新此时sz的值
num = 2;//左移次数
ShiftArray(C0, num, sz);//(子数组C0,左移次数,数组C0大小)
ShiftArray(D0, num, sz);//(子数组C0,左移次数,数组D0大小)
printf("左移两位后的数组C0:\n");//其实,总的来说到这里就已经左移了三次了
printfArray(C0, sz);
printf("左移两位后的数组D0:\n");
printfArray(D0, sz);
//左移数组
void ShiftArray(int* arr,int num,int size)  //(数组名,左移次数,数组大小)
{
	for (int i = 0; i < num; i++)
	{
		int temp = arr[0];//temp存放每次循环前的数组首元素
		//开始移位,将数组后一个元素的值赋值给前一个元素
		for (int j = 0; j < size - 1; j++)
		{ 
			*(arr + j) = *(arr + j + 1);//arr[j] = arr[]
		}
		arr[size - 1] = temp;  //将存放的原来arr[0]的值赋值给数组尾元素
	}
}

将二次左移后的数组继续合并成新数组

仍然利用Combine合并数组,从这里就可以体会到封装的妙处了😍


//将左移两次(三)的子数组C0和D0合并成数组C2D2
sz = sizeof(C2D2) / sizeof(C2D2[0]);//更新此时sz的值
Combine(C0, D0, C2D2, sz);//(子数组C0,子数组D0,数组C2D2,数组C2D2大小)
printf("合并后的数组C2D2:\n");
printfArray(C2D2, sz);
//合并数组
void Combine(int* arr1, int* arr2,int* arr3,int size)//(合并子数组名,合并子数组名,合并数组名,合并后数组大小)
{
	for (int i = 0; i < size/2; i++)//这里可以直接size/2的原因是数组都是偶数
	{
		*(arr3 + i) = *(arr1 + i);  //arr3[i] = arr1[i] 第一个子数组拷贝至合并数组(如何对应下标自己思考不予解释)
	}

	for (int j = 0; j < size/2; j++)
	{
		*(arr3 + size/2 + j) = *(arr2 + j);//arr3[size / 2 + j] = arr2[j] 第二个子数组拷贝至合并数组
	}
}

获取子密钥K2

//获取子密钥K2
sz = sizeof(K2) / sizeof(K2[0]);//更新此时sz的值
SecondMapping(C2D2, PC2, K2, sz);//(合并数组C2D2,PC2数组,子密钥数组K2,子密钥数组K2大小)
printf("子密钥数组K2:\n");
printfArray(K2, sz);
//获取子密钥(处理映射后会形成新数组的情况)
void SecondMapping(int* arr1, int* arr2, int* arr3, int size)//(原数组名,映射数组名,新数组名,新数组大小)
{
	for (int i = 0; i < size; i++)
	{
		*(arr3 + i) = *(arr1 + *(arr2 + i) - 1); //arr3[i] = arr1[arr2[i]-1]; 
	}
}

明文加密

除非有新函数,下面重复出现的函数就不再给予展示

初始化必要数组

(有个大致印象就行,有些数组的描述可能我也没描述准确获取描述错误,懒得改了😎)

int s;          //明文数组(十进制整数)
int SGroup[8];  //存放明文数组的前八个二进制比特位的整型数组
int IP[8], ReverseIP[8];//存放初始换位IP和逆初始换位IP
int L0[4], R0[4];//存放分割后的数组元素
int EP[8];//存放EP扩展
int R0Pro[8];//存放EP扩展后的数组
int XOR[8];//存放异或运算后的数组
int S0[4][4] = { 1,0,2,3,  3,1,0,2,  2,0,3,1,  1,3,2,0 }, S1[4][4] = { 0,3,1,2,  3,2,0,1,  1,0,3,2,  2,1,3,0 };//存放S0和S1盒的数组
int OR0[2], OR1[2];//存放异或后再分割的数组元素
int ORALL[4];//存放异或后再分割再S盒缩减后再合并的数组
int P[4];//存放P盒元素
int FirstTemp[4],SecondTemp[4];//用于处理迭代运算中出现的,第一轮的右值是第二轮的左值之类的问题
int Results[8];//存放最终密文的数组

获取明文数组s 

//获取明文数组s
printf("请输入明文数组的值:");	
scanf("%d", &s);
getchar();
system("cls");

获取明文数组s的十个二进制位

//获取明文数组SGroup
sz = sizeof(SGroup) / sizeof(SGroup[0]);//更新此时sz的值
GetLimitedArray(SGroup, s, sz);//(明文数组SGroup,明文数组的十进制整数,要获得的二进制个数)	printf("明文数组SGroup:\n");
printfArray(SGroup, sz);

获取初始换位IP  

//获取初始换位IP
sz = sizeof(IP) / sizeof(IP[0]);//更新此时sz的值
GetArray(IP, sz);//(初始换位IP,初始换位IP数组大小)
printf("输入的初始换位IP数组:\n");
printfArray(IP, sz);

由于是整型数组这里我会用循环,之前的字符数组我也不知道为什么用循环就会出问题┭┮﹏┭┮ 

//获取各类数组
void GetArray(int* arr,int size)//(需要人为数组的数组名,该数组大小)
{
	printf("请输入%d比特大小的内容:\n", size);
	for (int i = 0; i < size; i++)
	{
		scanf("%d", &arr[i]);//逐个数组,注意每次输入需要换行,且只能输入整数
	}
}   

 利用IP改变数组SGroup中元素的排列顺序

  • Mapping函数处理映射后不形成新数组只在原本数组上进行更改的情况;
  • SecondMapping函数处理映射后会形成新数组的情况;
//利用IP改变数组SGroup的内容
sz = sizeof(SGroup) / sizeof(SGroup[0]);//更新此时sz的值
Mapping(SGroup, IP, sz);
printf("最新的明文数组SGroup:\n");
printfArray(SGroup, sz);

第一轮迭代运算 

拆分元素顺序改变后的数组SGroup

//分离最新的SGroup数组从而获得第一轮迭代运算的左值子数组L0和右值子数组R0
sz = sizeof(L0) / sizeof(L0[0]);//更新此时sz的值
Split(SGroup, L0, R0, sz);//(最新明文数组SGroup,左值子数组L0,右值子数组R0,子数组大小)
printf("第一轮迭代运算的左值子数组L0:\n");
printfArray(L0, sz);	
printf("第一轮迭代运算的右值子数组R0:\n");
printfArray(R0, sz);

存储第一轮迭代运算中的右值作为第二次迭代运算的左值

//在第1次迭代运算中,右值作为第二轮轮的左值(FirstTemp是第二轮的左值)
sz = sizeof(L0) / sizeof(L0[0]);//更新此时sz的值	
Update(FirstTemp, R0, sz);//将右值子数组拷贝给数组FirstTemp
printf("第二轮迭代运算的左值子数组FirstTemp:\n");
printfArray(FirstTemp, sz);

 简单的拷贝函数

//备份函数(与其说是更新函数不如说是通过创建临时数组以应对迭代运算时,左右值的互换)
void Update(int* arr1, int* arr2,int size)
{
	for (int i = 0; i < size; i++)
	{
		*(arr1 + i) = *(arr2 + i);//arr1[i] = arr2[i]
	}
}

获取EP

//EP扩展
sz = sizeof(EP) / sizeof(EP[0]);//更新此时sz的值	
GetArray(EP, sz);
printf("输入的数组EP:\n");
printfArray(EP, sz);

EP扩展右值数组

//利用EP扩展第一轮迭代运算的右值子数组R0	
sz = sizeof(R0Pro) / sizeof(R0Pro[0]);//更新此时sz的值
SecondMapping(R0, EP, R0Pro, sz);//(右值子数组,EP数组,扩展后数组R0PR0,扩展后数组大小)
printf("第一轮迭代运算中,右值子数组R0在F函数中进行EP扩展后的新数组R0Pro:\n");
printfArray(R0Pro, sz);

扩展后的右值数组与子密钥K1进行异或运算形成新数组

//扩展后的右值子数组R0Pro与子密钥数组K1进行异或运算形成新的数组XOR
sz = sizeof(XOR) / sizeof(XOR[0]);//更新此时sz的值
OR(R0Pro, K1,XOR,sz);//(扩展后的右值子数组R0Pro,子密钥K1,异或后的新数组XOR,异或后新数组XOR大小)
printf("第一轮迭代运算中,右值子数组R0在F函数中进行EP扩展后的数组R0Pro与子密钥数组K1异或运算后得到的新数组XOR:\n");
printfArray(XOR, sz);

对两个数组的同一下标的元素进行异或,并将异或结果放入同一下标的新数组中 

//异或运算
void OR(int* arr1, int* arr2, int* arr3, int size)//(数组名,数组名,新数组名,新数组大小),默认三个数组大小均相同
{
	for (int i = 0; i < size; i++)
	{
		*(arr3 + i) = (*(arr1 + i) ^ *(arr2 + i));//arr3[i] = [arr1[i] ^ arr2[i]]
	}
}

缩小并分割新数组的两个子数组 

//s盒运算(缩小XOR数组的两个子数组)
sz = sizeof(XOR) / sizeof(XOR[0]);//更新此时sz的值
BoxS(XOR,OR0,S0,OR1,S1,sz);//(异或后的新数组XOR,XOR的左值子数组缩小后的新数组OR0(原始版本),S0盒数组,XOR的右值子数组缩小后的新数组OR1(原始版本),S1盒数组)
sz = sizeof(OR0) / sizeof(OR0[0]);//更新此时sz的值
printf("XOR的左值子数组缩小后的新数组OR0(初始版本):\n");
printfArray(OR0, sz);
printf("XOR的左值子数组缩小后的新数组OR0(初始版本):\n");
printfArray(OR1, sz);

    GetLimitedArray实现S盒子缩小后的分割效果,S盒简单来讲就是对于0110,首元素和尾元素组成的00(如果是01就是1,10就是2,11就是3,就是8421码)的十进制整数值作为S盒(二维数组)的横坐标,中间的11(S-DES中这里只能有两个但是DES中这里可能就是11011或者1111了)的十进制整数值作为S盒的纵坐标,将这两个横纵坐标的值用两个临时整型变量first和second存储后,再在S盒中确定一个十进制整数,将该数(S-DES算法中该数转为的二进制表示最大为11)对应的前两个二进制位的数字放入事先准备好的空数组OR0和OR1中

//S盒置换
void BoxS(int* arr1, int* arr2, int(*arr3)[4], int* arr4, int(*arr5)[4], int size)//(异或后新数组名,置换后数组,置换表数组名,置换后数组,置换表数组名,置换前数组大小) == XOR S0 OR1 S1 sz,默认置换后数组大小相同,这里我们没有选择将异或后的结果拆开后再进行S盒置换而是直接在该数组上进行
{
	for (int i = 0; i < 1; i++) //只进行一次的for循环,为了分离两次数组置换的过程,由于变量的生命周期,这样也可以实现一段代码的重复使用
	{
		//下标0~3
		int first = 0, second = 0;//first表示横坐标,second表示纵坐标

		//获取横坐标的过程
		int num1 = arr1[0];//0
		int num2 = arr1[size / 2 - 1];//3

		if (num1 == 0 && num2 == 0)
			first = 0;
		else if (num1 == 0 && num2 == 1)
			first = 1;
		else if (num1 == 1 && num2 == 0)
			first = 2;
		else if (num1 == 1 && num2 == 1)
			first = 3;

		//获取纵坐标的过程
		int num3 = arr1[1];//1
		int num4 = arr1[size / 2 - 2];//2

		if (num3 == 0 && num4 == 0)
			second = 0;
		else if (num3 == 0 && num4 == 1)
			second = 1;
		else if (num3 == 1 && num4 == 0)
			second = 2;
		else if (num3 == 1 && num4 == 1)
			second = 3;

		int num5 = arr3[first][second];//利用横纵坐标在置换表中确定置换后的十进制整数
		GetLimitedArray(arr2, num5, 2);//将该数字转为规定的二进制位后放入置换后数组中
	}
	for (int i = 0; i < 1; i++)
	{
		//下标4~7
		int first = 0, second = 0;
		int num1 = arr1[size / 2];//4
		int num2 = arr1[size - 1];//7

		if (num1 == 0 && num2 == 0)
			first = 0;
		else if (num1 == 0 && num2 == 1)
			first = 1;
		else if (num1 == 1 && num2 == 0)
			first = 2;
		else if (num1 == 1 && num2 == 1)
			first = 3;


		int num3 = arr1[size / 2 + 1];//5
		int num4 = arr1[size - 2];//6

		if (num3 == 0 && num4 == 0)
			second = 0;
		else if (num3 == 0 && num4 == 1)
			second = 1;
		else if (num3 == 1 && num4 == 0)
			second = 2;
		else if (num3 == 1 && num4 == 1)
			second = 3;

		int num5 = arr5[first][second];
		GetLimitedArray(arr4, num5, 2);
	}
}

获取P

//获取P盒
sz = sizeof(P) / sizeof(P[0]);//更新此时sz的值
GetArray(P, sz);//(P盒数组,数组大小)
printf("输入的数组P:\n");
printfArray(P, sz);

合并分割并缩减后的数组 

//合并数组OR0和OR1
sz = sizeof(ORALL) / sizeof(ORALL[0]);//更新此时sz的值
Combine(OR0,OR1,ORALL,sz);//(XOR的左值子数组缩小后的新数组OR0,XOR的右值子数组缩小后的新数组OR1,合并后数组ORALL,合并后数组ORALL大小)
printf("第一轮迭代运算中,F函数S盒置换后的两个子数组合并成的数组ORALL(第一轮初始版本):\n");
printfArray(ORALL, sz);

利用P改变数组ORALL中元素的排列顺序 

//P盒换位
sz = sizeof(ORALL) / sizeof(ORALL[0]);//更新此时sz的值
Mapping(ORALL,P,sz);//(合并后数组ORALL,P盒数组,合并后数组ORALL大小)
printf("第一轮迭代运算中,F函数对S盒置换后的两个子数组合并成的新数组ORALL进行P盒置换后的结果(更新数组ORALL):\n");
printfArray(ORALL, sz);

获取第二轮右值 

//P盒换位后的数组ORALL与第一轮开始时的左值进行异或运算,得到第二轮的右值
sz = sizeof(R0) / sizeof(R0[0]);//更新此时sz的值
OR(ORALL,L0, R0, sz);//(第一轮迭代运算P盒置换后的数组ORALL,第一轮迭代运算开始时的左值数组L0,第一轮迭代运算开始时的右值数组R0(此函数的目的就是更改R0),右值数组R0的大小)
printf("第二轮迭代运算的右值(更新原先的R0的值):\n");
printfArray(R0, sz);

    第二轮迭代运算开始时的左值子数组为FirstTemp,右值子数组为R0

第二轮迭代运算 

存储第二轮迭代运算中的右值作为最终结果的左值

//在第2次迭代运算中,右值作为输出结果的右值(SecondTemp为最终结果的右值子数组)
sz = sizeof(L0) / sizeof(L0[0]);//更新此时sz的值
Update(SecondTemp, R0, sz);//将第一轮迭代运算的右值子数组拷贝给数组SecondTemp
printf("第二轮迭代运算后作为最终结果左值子数组的SecondTemp:\n");
printfArray(SecondTemp, sz);

EP扩展右值数组

//EP扩展右数组R0
sz = sizeof(R0Pro) / sizeof(R0Pro[0]);//更新此时sz的值
SecondMapping(R0, EP, R0Pro, sz);//(右值子数组R0,EP数组,扩展后数组R0Pro,扩展后数组大小)	printf("第二轮迭代运算中,右值子数组R0在F函数中进行EP扩展后的新数组R0Pro:\n");
printfArray(R0Pro, sz);

扩展后的右值数组与子密钥K2进行异或运算放入原XOR数组(更新XOR数组)

//扩展后的R0与子密钥K2进行异或运算(更新XOR数组的内容)
sz = sizeof(XOR) / sizeof(XOR[0]);//更新此时sz的值
OR(R0Pro, K2, XOR, sz);//(右值扩展后数组R0Pro,子密钥数组K2,异或运算后的新数组XOR,异或运算后的新数组XOR大小)
printf("第二轮迭代运算中,右值子数组R0在f函数中进行EP扩展后的数组R0Pro与子密钥数组K2异或运算后得到的新数组XOR(更新XOR数组):\n");
printfArray(XOR, sz);

缩小并分割XOR数组的两个子数组(更新OR0和OR1) 


//S盒运算(更新第一轮迭代运算中的某些数组)
sz = sizeof(XOR) / sizeof(XOR[0]);//更新此时sz的值
BoxS(XOR, OR0, S0, OR1, S1, sz);//(异或后的新数组XOR,XOR的左值子数组缩小后的新数组OR0(更新版本),S0盒数组,XOR的右值子数组缩小后的新数组OR1(更新版本),S1盒数组)
sz = sizeof(OR0) / sizeof(OR0[0]);//更新此时sz的值
printf("XOR的左值子数组缩小后的新数组OR0(更新版本):\n");
printfArray(OR0, sz);
printf("XOR的左值子数组缩小后的新数组OR1(更新版本):\n");
printfArray(OR1, sz);

合并分割并缩减后的数组 


//合并数组OR0和OR1
sz = sizeof(ORALL) / sizeof(ORALL[0]);//更新此时sz的值
Combine(OR0, OR1, ORALL, sz);//
printf("第二轮迭代运算中,f函数s盒置换后的两个子数组合并成的新数组ORALL(第二轮更新版本):\n");
printfArray(ORALL, sz);

利用P改变数组ORALL中元素的排列顺序  

//p盒换位
sz = sizeof(ORALL) / sizeof(ORALL[0]);//更新此时sz的值
Mapping(ORALL, P, sz);//(合并后数组ORALL,P盒数组,合并后数组ORALL大小)
printf("第二轮迭代运算中,F函数对S盒置换后的两个子数组合并成的新数组ORALL进行P盒置换后的结果(更新数组ORALL):\n");
printfArray(ORALL, sz);

获取最终结果的左值 

//右值通过f( )函数与子密钥结合后,再与第二轮初始时的左值子数组first进行异或运算,得到最终输出结果的左值(虽然还是用R0来承接,但是这时的R0代表的是最终输出结果的左值)
sz = sizeof(R0) / sizeof(R0[0]);//更新此时sz的值
OR(ORALL, FirstTemp, R0, sz);//(P盒子置换后的右值子数组,第二轮迭代运算初始时的左值子数组FirstTemp,最终输出的左值子数组R0(虽然叫R0但这里表示已经是左值了),最终输出的左值子数组R0大小)
printf("第二轮迭代运算中,最后输出的左值:\n");
printfArray(R0, sz);

合并最终结果的左值和右值

//合并数组
sz = sizeof(Results) / sizeof(Results[0]);//更新此时sz的值
Combine(R0,SecondTemp,Results, sz);//(第二轮迭代运算输出左值子数组R0,第二轮迭代运算输出右值子数组SecondTemp,合并数组results,合并数组results的大小)
printf("第二轮迭代运算后,两个输出结果合并后的数组Results:\n");
printfArray(Results, sz);

获取逆置换IP

//获取ReverseIP
sz = sizeof(ReverseIP) / sizeof(ReverseIP[0]);//更新此时sz的值
GetArray(ReverseIP, sz);//(逆初始换位ReverseIP,逆初始换位ReverseIP数组大小)
printf("输入的逆初始换位ReverseIP数组:\n");
printfArray(ReverseIP, sz);

获取最终密文 

//利用ReverseIP改变数组Results的内容
sz = sizeof(Results) / sizeof(Results[0]);//更新此时sz的值
Mapping(Results, ReverseIP, sz);//(合并后数组Results,逆初始换位ReverseIP,合并后数组Results的大小)
printf("最终明文加密后的结果:\n");
printfArray(Results, sz);

 完整代码

test.h文件

#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>


//公共函数:

//获取某个整数的有限的二进制位
void GetLimitedArray(int* arr, int k, int size);

//映射改变原数组中二进制数的排列顺序
void Mapping(int* arr1, int* arr2, int size);

//分离数组函数
void Split(int* arr1, int* arr2, int* arr3, int size);

//获取各类数组函数
void GetArray(int* arr, int size);

//打印各类数组函数
void printfArray(int* arr, int size);



//获取子密钥函数:

//包含字符的PC数组
void GetPC(int* arr, int size);

//左移函数
void ShiftArray(int* arr, int num, int size);

//合并数组函数
void Combine(int* arr1, int* arr2, int* arr3, int size);

//获取子密钥
void SecondMapping(int* arr1, int* arr2, int* arr3, int size);


//加密函数:
 
//异或运算
void OR(int* arr1, int* arr2, int* arr3, int size);

//S盒置换
void BoxS(int* arr1, int* arr2, int(*arr3)[4], int* arr4, int(*arr5)[4], int size);//OR0 S0 OR1 S1 sz

//更新L0
void Update(int* arr1, int* arr2, int size);

encrypt.c文件

#include "test.h"

//异或运算
void OR(int* arr1, int* arr2, int* arr3, int size)//(数组名,数组名,新数组名,新数组大小),默认三个数组大小均相同
{
	for (int i = 0; i < size; i++)
	{
		*(arr3 + i) = (*(arr1 + i) ^ *(arr2 + i));//arr3[i] = [arr1[i] ^ arr2[i]]
	}
}

//S盒置换和缩小(XOR, OR0, S0, OR1, S1, sz)
void BoxS(int* arr1, int* arr2, int(*arr3)[4], int* arr4, int(*arr5)[4], int size)//(异或后新数组名,置换后数组,置换表数组名,置换后数组,置换表数组名,置换前数组大小) == XOR S0 OR1 S1 sz,默认置换后数组大小相同,这里我们没有选择将异或后的结果拆开后再进行S盒置换而是直接在该数组上进行
{
	for (int i = 0; i < 1; i++) //只进行一次的for循环,为了分离两次数组置换的过程,由于变量的生命周期,这样也可以实现一段代码的重复使用
	{
		//下标0~3
		int first = 0, second = 0;//first表示横坐标,second表示纵坐标

		//获取横坐标的过程
		int num1 = arr1[0];
		int num2 = arr1[1];

		if (num1 == 0 && num2 == 0)
			first = 0;
		else if (num1 == 0 && num2 == 1)
			first = 1;
		else if (num1 == 1 && num2 == 0)
			first = 2;
		else if (num1 == 1 && num2 == 1)
			first = 3;

		//获取纵坐标的过程
		int num3 = arr1[2];//1
		int num4 = arr1[3];//2

		if (num3 == 0 && num4 == 0)
			second = 0;
		else if (num3 == 0 && num4 == 1)
			second = 1;
		else if (num3 == 1 && num4 == 0)
			second = 2;
		else if (num3 == 1 && num4 == 1)
			second = 3;

		int num5 = arr3[first][second];//利用横纵坐标在置换表中确定置换后的十进制整数
		
		//缩小
		for (int i = 1; i >= 0; i--)
		{
			arr2[i] = num5 % 2;
			num5 /= 2;
		}
	}
	for (int i = 0; i < 1; i++)
	{
		//下标4~7
		int first = 0, second = 0;
		int num1 = arr1[4];//4
		int num2 = arr1[5];//7

		if (num1 == 0 && num2 == 0)
			first = 0;
		else if (num1 == 0 && num2 == 1)
			first = 1;
		else if (num1 == 1 && num2 == 0)
			first = 2;
		else if (num1 == 1 && num2 == 1)
			first = 3;


		int num3 = arr1[6];//5
		int num4 = arr1[7];//6

		if (num3 == 0 && num4 == 0)
			second = 0;
		else if (num3 == 0 && num4 == 1)
			second = 1;
		else if (num3 == 1 && num4 == 0)
			second = 2;
		else if (num3 == 1 && num4 == 1)
			second = 3;

		
		int num5 = arr5[first][second];

		printf("s2盒运算的num5 = %d\n", num5);

		//缩小
		for (int i = 1; i >= 0; i--)
		{
			arr4[i] = num5 % 2;
			printf("arr[%d] = %d", i,arr4[i]);
			num5 /= 2;
		}
	}
}

//备份函数(与其说是更新函数不如说是通过创建临时数组以应对迭代运算时,左右值的互换)
void Update(int* arr1, int* arr2, int size)
{
	for (int i = 0; i < size; i++)
	{
		*(arr1 + i) = *(arr2 + i);//arr1[i] = arr2[i]
	}
}

keys.c文件

#include "test.h"

//获取包含字符的PC数组
void GetPC(int* arr, int size)//(字符数组,字符数组大小)
{
	char str[50];//用于存放读取到的字符

	int i = 0;
	// 读取输入字符串
	if (size == 10)
	{
		printf("请输入10个数字作为PC-1数组,以空格分隔: ");
	}
	else
	{
		printf("请输入8个数字作为PC-2数组,以空格分隔: ");
	}
	fgets(str, sizeof(str), stdin);//使用fgets函数从标准输入中读取字符

	//printf("%s", str);

	// 使用strtok函数分割读取到的字符串(空格字符作为分割符)
	char* token = strtok(str, " ");
	while (token != NULL) 
	{
		arr[i++] = atoi(token);//使用atoi函数将token指向的字符转换为正数,之后再i加一
		token = strtok(NULL, " ");
	}

	system("pause");//暂停程序只有按任意键后才会继续执行:为检查结果是否正确提供时间
	printf("\n");
	system("cls");//清屏:为下一次的输入或者打印数组留出足够的空间(腾位置)


	 输出结果
	//printf("转换后的整数数组: ");
	//for (int i = 0; i < size; i++) {
	//	printf("%d ", arr[i]);
	//}
	//printf("\n");
}



转换字符数组至整型数组
//void TransformArray(char* arr1, int* arr2, int size)//(字符数组,整型数组,整型数组大小)
//{
//	//for (int i = 0; i < size; i++)
//	//{
//
//	//	if (arr1[i] >= '0' && arr1[i] <= '9')//遍历input数组的每一个元素,如果该元素为整数就利用atoi函数将该字符转换为对应的整数,比如“123” -> 123
//	//	{
//	//		arr2[i] = arr1[i] - '0';
//	//	}
//	//	else
//	//	{
//	//		int num = arr1[i];
//	//		switch (num)
//	//		{
//	//		case 65:
//	//			arr2[i] = 10;
//	//			break;
//	//		case 66:
//	//			arr2[i] = 11;
//	//			break;
//	//		case 67:
//	//			arr2[i] = 12;
//	//			break;
//	//		case 68:
//	//			arr2[i] = 13;
//	//			break;
//	//		case 69:
//	//			arr2[i] = 14;
//	//			break;
//	//		case 70:
//	//			arr2[i] = 15;
//	//			break;
//	//		}
//	//	}
//	//}
//
//	int i = 0;
//	char* s = strtok(arr1, " ");
//	while (s != NULL) 
//	{
//		arr1[++i] = atoi(s);//调用atoi函数将字符串转为正数
//		s = strtok(NULL, " ");//s指向下一个字符的位置
//	}
//
//	printf("转换后的整数数组: ");
//	for (int i = 0; i < size; i++) {
//		printf("%d ", arr2[i]);
//	}
//	printf("\n");
//
//}

//左移数组
void ShiftArray(int* arr, int num, int size)  //(数组名,左移次数,数组大小)
{
	for (int i = 0; i < num; i++)
	{
		int temp = arr[0];//temp存放每次循环前的数组首元素
		//开始移位,将数组后一个元素的值赋值给前一个元素
		for (int j = 0; j < size - 1; j++)
		{
			*(arr + j) = *(arr + j + 1);//arr[j] = arr[]
		}
		arr[size - 1] = temp;  //将存放的原来arr[0]的值赋值给数组尾元素
	}
}

//获取子密钥(处理映射后会形成新数组的情况)
void SecondMapping(int* arr1, int* arr2, int* arr3, int size)//(原数组名,映射数组名,新数组名,新数组大小)
{
	for (int i = 0; i < size; i++)
	{
		*(arr3 + i) = *(arr1 + *(arr2 + i) - 1); //arr3[i] = arr1[arr2[i]-1]; 
	}
}

public.c文件

#include "test.h"

//获取有限的二进制位组成的数组(由于整数在IDE中是以补码的形式存在的,一般为32位,而我们想要的明文数组和初始密钥对应的二进制位数均为10bit,所以需要人为截断它们的补码并将截断结果放入相应的数组中)
void GetLimitedArray(int* arr, int num, int size)//(数组名,整数值(明文数组或初始密钥未转为二进制前的十进制整数),存放阶段后结果的数组大小)
{
	for (int i = size - 1; i >= 0; i--)  //不能交换int i = szie-1; i >= 0的顺序,否则二进制就是0010010000,倒着来了明显不符合要求
	{
		*(arr + i) = num % 2;//arr[i] = num % 2,利用%获取该数的二进制位
		num = num / 10; //利用/使得该数不断减小
		//%和/的使用是基于十进制转二进制的计算办法
	}
}

//获取各类数组
void GetArray(int* arr, int size)//(需要人为数组的数组名,该数组大小)
{
	printf("请输入%d比特大小的内容:\n", size);
	for (int i = 0; i < size; i++)
	{
		scanf("%d", &arr[i]);//逐个数组,注意每次输入需要换行,且只能输入整数
	}
}

//打印各类数组
void printfArray(int* arr, int size)//(要打印的数组名,数组大小)
{
	for (int i = 0; i < size; i++)
	{
		printf("%d ", *(arr + i));//arr[i];
	}
	system("pause");//暂停程序只有按任意键后才会继续执行:为检查结果是否正确提供时间
	printf("\n");
	system("cls");//清屏:为下一次的输入或者打印数组留出足够的空间(腾位置)
}

//映射改变原数组中二进制数的排列顺序(处理映射后不形成新数组只在原本数组上进行更改的情况)
void Mapping(int* arr1, int* arr2, int size)//(原数组名,映射数组名,数组大小)
{
	int arr[100];//设定一个足够大的临时数组,如果利用临时数组就会导致PC1 + K的结果不为0100000010,而是0110000000
	int* temp = arr;//temp指向该临时数组(可要可不要)
	for (int i = 0; i < size; i++)
	{
		*(arr + i) = *(arr1 + i);//将原数组内容拷贝给临时数组
	}
	for (int i = 0; i < size; i++)
	{

		*(arr1 + i) = *(temp + *(arr2 + i) - 1);//arr1[i] = temp[arr2[i] - 1] 或 arr1[i] = arr[arr2[i] - 1]
	}
}

//分离数组
void Split(int* arr1, int* arr2, int* arr3, int size)//(原数组名,子数组名,子数组名,子数组大小),默认子数组大小相同
{
	int temp = size;//用temp获取size的值,如果不用temp可能会导致i的范围由于size++而发生变化,影响arr2
	for (int i = 0; i < size; i++)
	{
		*(arr2 + i) = *(arr1 + i);//arr2[i] = arr1[i]
		*(arr3 + i) = *(arr1 + temp);//arr3[i] = arr1[temp]
		temp++;
	}
}

//合并数组
void Combine(int* arr1, int* arr2, int* arr3, int size)//(合并子数组名,合并子数组名,合并数组名,合并后数组大小)
{
	for (int i = 0; i < size / 2; i++)//这里可以直接size/2的原因是数组都是偶数
	{
		*(arr3 + i) = *(arr1 + i);  //arr3[i] = arr1[i] 第一个子数组拷贝至合并数组(如何对应下标自己思考不予解释)
	}

	for (int j = 0; j < size / 2; j++)
	{
		*(arr3 + size / 2 + j) = *(arr2 + j);//arr3[size / 2 + j] = arr2[j] 第二个子数组拷贝至合并数组
	}
}

test.c文件

#include "test.h"

int main()
{
	int k;
	char TempPC2[8];
	int K[10];
	int K1[8], K2[8];
	int PC1[10], PC2[8];
	int C0[5], D0[5];
	int C1D1[10], C2D2[10];

	//输入一行连续的由1和0组成的数字作为初始密钥k(长度为10)
	printf("请输入初始密钥k的值:");
	scanf("%d", &k);
	getchar();
	system("cls");

	//将读取到的数字放入初始密钥数组K中
	int sz = sizeof(K) / sizeof(K[0]);//获取数组K的大小
	GetLimitedArray(K, k, sz);//(数组K,初始密钥的十进制整数,要获得的二进制个数)
	printf("数组K:\n");
	printfArray(K, sz);//打印数组K


	//获取PC-1
	sz = sizeof(PC1) / sizeof(PC1[0]);//更新此时sz的值
	GetPC(PC1,sz);
	printf("输入的PC-1:\n");
	printfArray(PC1, sz);


	//利用PC-1改变初始密钥数组K中元素的排列顺序
	sz = sizeof(K) / sizeof(K[0]);//更新此时sz的值
	Mapping(K, PC1, sz);//(数组K,数组PC1,数组K大小),K和PC1大小相同
	printf("最新的初始密钥数组K:\n");
	printfArray(K, sz);


	//将数组K拆分为两个大小相同的数组C0和D0
	sz = sizeof(C0) / sizeof(C0[0]);//更新此时sz的值,
	Split(K, C0, D0, sz);//(数组K,子数组C0,子数组D0,子数组C0大小),子数组C0和D0大小相同
	printf("数组C0:\n");
	printfArray(C0, sz);
	printf("数组D0:\n");
	printfArray(D0, sz);


	//将C0和D0数组均左移一位
	sz = sizeof(C0) / sizeof(C0[0]);//更新此时sz的值
	int num = 1;//左移次数
	ShiftArray(C0, num, sz);//(子数组C0,左移次数,数组C0大小)
	ShiftArray(D0, num, sz);//(子数组D0,左移次数,数组C0大小),,子数组C0和D0大小相同
	printf("左移一位后的数组C0:\n");
	printfArray(C0, sz);
	printf("左移一位后的数组D0:\n");
	printfArray(D0, sz);


	//将左移一次的子数组C0和D0合并成数组C1D1
	sz = sizeof(C1D1) / sizeof(C1D1[0]);//更新此时sz的值
	Combine(C0, D0, C1D1, sz);//(子数组C0,子数组D0,数组C1D1,数组C1D1大小)
	printf("合并后的数组C1D1:\n");
	printfArray(C1D1, sz);


	//获取PC-2
	sz = sizeof(PC2) / sizeof(PC2[0]);//更新此时sz的值
	GetPC(PC2, sz);
	printf("输入的PC-2:\n");
	printfArray(PC2, sz);


	//获取子密钥K1
	sz = sizeof(K1) / sizeof(K1[0]);//更新此时sz的值
	SecondMapping(C1D1, PC2, K1, sz);//(合并数组C1D1,PC2数组,子密钥数组K1,子密钥数组K1大小)
	printf("子密钥数组K1:\n");
	printfArray(K1, sz);


	//将C0和D0数组在原有基础上继续左移两位
	sz = sizeof(C0) / sizeof(C0[0]);//更新此时sz的值
	num = 2;//左移次数
	ShiftArray(C0, num, sz);//(子数组C0,左移次数,数组C0大小)
	ShiftArray(D0, num, sz);//(子数组C0,左移次数,数组D0大小)
	printf("再次左移两位后的数组C0:\n");//其实,总的来说到这里就已经左移了三次了
	printfArray(C0, sz);
	printf("再次左移两位后的数组D0:\n");
	printfArray(D0, sz);


	//将左移两次(三)的子数组C0和D0合并成数组C2D2
	sz = sizeof(C2D2) / sizeof(C2D2[0]);//更新此时sz的值
	Combine(C0, D0, C2D2, sz);//(子数组C0,子数组D0,数组C2D2,数组C2D2大小)
	printf("合并后的数组C2D2:\n");
	printfArray(C2D2, sz);


	//获取子密钥K2
	sz = sizeof(K2) / sizeof(K2[0]);//更新此时sz的值
	SecondMapping(C2D2, PC2, K2, sz);//(合并数组C2D2,PC2数组,子密钥数组K2,子密钥数组K2大小)
	printf("子密钥数组K2:\n");
	printfArray(K2, sz);

	这俩就是上面一大长串代码得到的结果(如果要测试明文加密代码又不想多次经历上面的获取K1和K2的步骤,可以注释掉上方代码然后直接写出获得的结果)
	//int K1[8] = { 1,0,1,0,0,1,0,0 };
	//int K2[8] = { 0,1,0,0,0,0,1,1 };


	//明文加密

	int s;
	int SGroup[8];
	int IP[8], ReverseIP[8];
	int L0[4], R0[4];
	int EP[8];
	int R0Pro[8];
	int XOR[8];
	int S0[4][4] = { 1,0,2,3,  3,1,0,2,  2,0,3,1,  1,3,2,0 }, S1[4][4] = { 0,3,1,2,  3,2,0,1,  1,0,3,2,  2,1,3,0 };
	int OR0[2], OR1[2];
	int ORALL[4];
	int P[4];
	int FirstTemp[4], SecondTemp[4];
	int Results[8];

	//获取明文数组s
	printf("请输入由1和0组成的8bit大小的明文数组的值:");
	scanf("%d", &s);
	getchar();
	system("cls");

	//获取明文数组SGroup
	 sz = sizeof(SGroup) / sizeof(SGroup[0]);//更新此时sz的值
	GetLimitedArray(SGroup, s, sz);//(明文数组SGroup,明文数组的十进制整数,要获得的二进制个数)
	printf("明文数组SGroup:\n");
	printfArray(SGroup, sz);


	//获取初始换位IP
	sz = sizeof(IP) / sizeof(IP[0]);//更新此时sz的值
	GetArray(IP, sz);//(初始换位IP数组,初始换位IP数组大小)
	printf("输入的初始换位IP数组:\n");
	printfArray(IP, sz);


	//利用IP改变数组SGroup的内容
	sz = sizeof(SGroup) / sizeof(SGroup[0]);//更新此时sz的值
	Mapping(SGroup, IP, sz);
	printf("最新的明文数组SGroup:\n");
	printfArray(SGroup, sz);

	//第一轮迭代运算:
	//分离最新的SGroup数组从而获得第一轮迭代运算的左值子数组L0和右值子数组R0
	sz = sizeof(L0) / sizeof(L0[0]);//更新此时sz的值
	Split(SGroup, L0, R0, sz);//(最新明文数组SGroup,左值子数组L0,右值子数组R0,子数组大小)
	printf("第一轮迭代运算的左值子数组L0:\n");
	printfArray(L0, sz);
	printf("第一轮迭代运算的右值子数组R0:\n");
	printfArray(R0, sz);


	//在第1次迭代运算中,右值作为第二轮轮的左值(FirstTemp是第二轮的左值)
	sz = sizeof(L0) / sizeof(L0[0]);//更新此时sz的值
	Update(FirstTemp, R0, sz);//将右值子数组拷贝给数组FirstTemp
	printf("第二轮迭代运算的左值子数组FirstTemp:\n");
	printfArray(FirstTemp, sz);

	//EP扩展
	sz = sizeof(EP) / sizeof(EP[0]);//更新此时sz的值
	GetArray(EP, sz);
	printf("输入的数组EP:\n");
	printfArray(EP, sz);

	//第一轮迭代运算的F函数内容:
	//利用EP扩展第一轮迭代运算的右值子数组R0
	sz = sizeof(R0Pro) / sizeof(R0Pro[0]);//更新此时sz的值
	SecondMapping(R0, EP, R0Pro, sz);//(右值子数组,EP数组,扩展后数组R0PR0,扩展后数组大小)
	printf("第一轮迭代运算中,右值子数组R0在F函数中进行EP扩展后的新数组R0Pro:\n");
	printfArray(R0Pro, sz);


	//扩展后的右值子数组R0Pro与子密钥数组K1进行异或运算形成新的数组XOR
	sz = sizeof(XOR) / sizeof(XOR[0]);//更新此时sz的值
	OR(R0Pro, K1, XOR, sz);//(扩展后的右值子数组R0Pro,子密钥K1,异或后的新数组XOR,异或后新数组XOR大小)
	printf("第一轮迭代运算中,右值子数组R0在F函数中进行EP扩展后的数组R0Pro与子密钥数组K1异或运算后得到的新数组XOR:\n");
	printfArray(XOR, sz);


	//s盒运算(缩小XOR数组的两个子数组)
	sz = sizeof(XOR) / sizeof(XOR[0]);//更新此时sz的值
	BoxS(XOR, OR0, S0, OR1, S1, sz);//(异或后的新数组XOR,XOR的左值子数组缩小后的新数组OR0(原始版本),S0盒数组,XOR的右值子数组缩小后的新数组OR1(原始版本),S1盒数组)
	sz = sizeof(OR0) / sizeof(OR0[0]);//更新此时sz的值
	printf("XOR的左值子数组缩小后的新数组OR0(第一轮F函数):\n");
	printfArray(OR0, sz);
	printf("XOR的右值子数组缩小后的新数组OR1(第一轮F函数):\n");
	printfArray(OR1, sz);


	//合并数组OR0和OR1
	sz = sizeof(ORALL) / sizeof(ORALL[0]);//更新此时sz的值
	Combine(OR0, OR1, ORALL, sz);//(XOR的左值子数组缩小后的新数组OR0,XOR的右值子数组缩小后的新数组OR1,合并后数组ORALL,合并后数组ORALL大小)
	printf("第一轮迭代运算中,F函数S盒置换后的两个子数组合并成的数组ORALL(第一轮初始版本):\n");
	printfArray(ORALL, sz);

	//获取P盒
	sz = sizeof(P) / sizeof(P[0]);//更新此时sz的值
	GetArray(P, sz);//(P盒数组,数组大小)
	printf("输入的数组P:\n");
	printfArray(P, sz);

	//P盒换位
	sz = sizeof(ORALL) / sizeof(ORALL[0]);//更新此时sz的值
	Mapping(ORALL, P, sz);//(合并后数组ORALL,P盒数组,合并后数组ORALL大小)
	printf("第一轮迭代运算中,F函数对S盒置换后的两个子数组合并成的新数组ORALL进行P盒置换后的结果(更新数组ORALL):\n");
	printfArray(ORALL, sz);


	//P盒换位后的数组ORALL与第一轮开始时的左值进行异或运算,得到第二轮的右值
	sz = sizeof(R0) / sizeof(R0[0]);//更新此时sz的值
	OR(ORALL, L0, R0, sz);//(第一轮迭代运算P盒置换后的数组ORALL,第一轮迭代运算开始时的左值数组L0,第一轮迭代运算开始时的右值数组R0(此函数的目的就是更改R0),右值数组R0的大小)
	printf("将经过P盒置换后的ORALL与第一轮迭代运算的左值做异或运算得到第二轮迭代运算的右值(更新原先的R0的值):\n");
	printfArray(R0, sz);

	//第二轮迭代运算开始时的左值子数组为FirstTemp,右值子数组为R0

	//在第2次迭代运算中,右值作为输出结果的右值(SecondTemp为最终结果的右值子数组)
	sz = sizeof(R0) / sizeof(R0[0]);//更新此时sz的值
	Update(SecondTemp, R0, sz);//将第一轮迭代运算的右值子数组拷贝给数组SecondTemp
	printf("第二轮迭代运算后作为最终结果左值子数组的SecondTemp:\n");
	printfArray(SecondTemp, sz);


	//第二轮迭代运算的f函数内容(对第一轮迭代运算的左值):
	//EP扩展右数组R0
	sz = sizeof(R0Pro) / sizeof(R0Pro[0]);//更新此时sz的值
	SecondMapping(R0, EP, R0Pro, sz);//(右值子数组R0,EP数组,扩展后数组R0Pro,扩展后数组大小)
	printf("第二轮迭代运算中,右值子数组R0在F函数中进行EP扩展后的新数组R0Pro:\n");
	printfArray(R0Pro, sz);


	//扩展后的R0与子密钥K2进行异或运算(更新XOR数组的内容)
	sz = sizeof(XOR) / sizeof(XOR[0]);//更新此时sz的值
	OR(R0Pro, K2, XOR, sz);//(右值扩展后数组R0Pro,子密钥数组K2,异或运算后的新数组XOR,异或运算后的新数组XOR大小)
	printf("第二轮迭代运算中,右值子数组R0在f函数中进行EP扩展后的数组R0Pro与子密钥数组K2异或运算后得到的新数组XOR(更新XOR数组):\n");
	printfArray(XOR, sz);


	//S盒运算(更新第一轮迭代运算中的某些数组)
	sz = sizeof(XOR) / sizeof(XOR[0]);//更新此时sz的值
	BoxS(XOR, OR0, S0, OR1, S1, sz);//(异或后的新数组XOR,XOR的左值子数组缩小后的新数组OR0(更新版本),S0盒数组,XOR的右值子数组缩小后的新数组OR1(更新版本),S1盒数组)
	sz = sizeof(OR0) / sizeof(OR0[0]);//更新此时sz的值
	printf("XOR的左值子数组缩小后的新数组OR0(第二轮F函数):\n");
	printfArray(OR0, sz);
	printf("XOR的左值子数组缩小后的新数组OR1(第二轮F函数):\n");
	printfArray(OR1, sz);


	//合并数组OR0和OR1
	sz = sizeof(ORALL) / sizeof(ORALL[0]);//更新此时sz的值
	Combine(OR0, OR1, ORALL, sz);//
	printf("第二轮迭代运算中,f函数s盒置换后的两个子数组合并成的新数组ORALL(第二轮更新版本):\n");
	printfArray(ORALL, sz);


	//p盒换位
	sz = sizeof(ORALL) / sizeof(ORALL[0]);//更新此时sz的值
	Mapping(ORALL, P, sz);//(合并后数组ORALL,P盒数组,合并后数组ORALL大小)
	printf("第二轮迭代运算中,F函数对S盒置换后的两个子数组合并成的新数组ORALL进行P盒置换后的结果(更新数组ORALL):\n");
	printfArray(ORALL, sz);


	//右值通过f( )函数与子密钥结合后,再与第二轮初始时的左值子数组first进行异或运算,得到最终输出结果的左值(虽然还是用R0来承接,但是这时的R0代表的是最终输出结果的左值)
	sz = sizeof(R0) / sizeof(R0[0]);//更新此时sz的值
	OR(ORALL, FirstTemp, R0, sz);//(P盒子置换后的右值子数组,第二轮迭代运算初始时的左值子数组FirstTemp,最终输出的左值子数组R0(虽然叫R0但这里表示已经是左值了),最终输出的左值子数组R0大小)
	printf("第二轮迭代运算中,最后输出的左值:\n");
	printfArray(R0, sz);


	//合并数组
	sz = sizeof(Results) / sizeof(Results[0]);//更新此时sz的值
	Combine(R0, SecondTemp, Results, sz);//(第二轮迭代运算输出左值子数组R0,第二轮迭代运算输出右值子数组SecondTemp,合并数组results,合并数组results的大小)
	printf("第二轮迭代运算后,两个输出结果合并后的数组Results:\n");
	printfArray(Results, sz);

	//获取ReverseIP
	sz = sizeof(ReverseIP) / sizeof(ReverseIP[0]);//更新此时sz的值
	GetArray(ReverseIP, sz);//(逆初始换位ReverseIP,逆初始换位ReverseIP数组大小)
	printf("输入的逆初始换位ReverseIP数组:\n");
	printfArray(ReverseIP, sz);


	//利用ReverseIP改变数组Results的内容
	sz = sizeof(Results) / sizeof(Results[0]);//更新此时sz的值
	Mapping(Results, ReverseIP, sz);//(合并后数组Results,逆初始换位ReverseIP,合并后数组Results的大小)
	printf("最终明文加密后的结果:\n");
	printfArray(Results, sz);

	return 0;
}

~over~

S-DES(Substitution-Permutation Network,置换-替换网络)是一种简化版本的DES(Data Encryption Standard,数据加密标准),它通常用于教学和小规模实验,而不是实际生产环境。在C语言实现S-DES,你需要了解其基本结构,包括代换(Substitution)步骤和排列(Permutation)步骤。 以下是一个简单的S-DES算法的伪代码描述: ```c typedef struct { unsigned char key[8]; // 64位密钥 unsigned char in[8]; // 输入明文块 unsigned char out[8]; // 输出密文块 } SDesContext; void init(SDesContext* context, const unsigned char key[]) { // 初始化S-DES上下文,这里仅示例,真实应用需考虑更多细节 memcpy(context->key, key, 8); } void s_des_round(SDesContext* context) { // 包含16轮替换和置换操作的具体实现 // 这部分需要你自己编写具体的代换表和循环移位操作 } void s_des_encrypt(SDesContext* context, const unsigned char plaintext[]) { for (int i = 0; i < 8; ++i) { context->in[i] = plaintext[i]; s_des_round(context); } memcpy(context->out, context->in, 8); // 将处理后的数据复制到输出 } // 使用示例 int main() { SDesContext ctx; init(&ctx, your_key); // 替换真实的密钥 s_des_encrypt(&ctx, your_plaintext); // 加密明文 return 0; } ``` 请注意,这只是一个非常基础的框架,实际实现会更复杂,并需要你编写详细的代换函数以及安排好循环移位和其他特定的S-DES变换。此外,为了完整实现,还需要包括秘钥扩展和分组过程等。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值