现代密码学概论|密码学基础--国密算法实验C语言(文末附上C语言源代码)

实验国密算法实现

一、实验目的

1)初步了解国密算法

2)掌握具体国密算法的实现

二、实验学时

  4学时

三、实验方法

根据PPT中关于国密算法的描述,任选一种国密算法,用所熟悉的编程语言实现。填写实验内容、实验操作步骤、实验结果与实验心得。

四、实验环境

计算机及语言开发环境Windows10平台下的Dev-CPP5.11。

五、实验内容

1.SM4国密算法简介

SM4 为无线局域网标准的分组加密算法,对称加密,用于替代 DES/AES 等国际算法,SM4 算法与 AES 算法具有相同的密钥长度和分组长度,均为 128 位,故对消息进行加解密时,若消息长度过长,需要进行分组,要消息长度不足,则要进行填充。加密算法与密钥扩展算法都采用 32 轮非线性迭代结构,解密算法与加密算法的结构相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。

SM4算法是用于WAPI的分组密码算法,是2006年我国国家密码管理局公布的国内第一个商用密码算法。

SM4算法是分组密码算法,其中数据分组长度为128比特,密钥分组长度也为128比特。加密算法与密钥扩展算法都采用32轮迭代结构,以字节(8位)和字(32位)为单位进行数据处理。

六、实验操作步骤

1.SM4国密算法实现

SM4密码算法的基本运算有模2加和循环移位。

  ① 模2加

  ② 循环移位

//循环左移算法

u32 loopLeft(u32 a, short length) {

short i;

for(i = 0; i < length; i++) {

a = a * 2 + a / 0x80000000;

}

return a;

}

基本密码部件

⑴ S盒

    S盒是以字节为单位的非线性替换,其密码学作用是混淆,它的输入和输出都是8位的字节。设输入字节为a,输出字节为b则S盒的运算可表示为:

 

 

S盒的替换规则如图所示。例如输入为EF,则输出为第E行与第F列交叉处的值84,

 

//s盒的数据

const u8 Sbox[256] = {

0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05,

0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99,

0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62,

0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6,

0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8,

0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35,

0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87,

0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e,

0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1,

0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3,

0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f,

0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51,

0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8,

0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0,

0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84,

0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48

};
//查询S盒的函数B

u32 functionB(u32 b) {

  u8 a[4];

  short i;

  a[0] = b / 0x1000000;

  a[1] = b / 0x10000;

  a[2] = b / 0x100;

  a[3] = b;

  b = Sbox[a[0]] * 0x1000000 + Sbox[a[1]] * 0x10000 + Sbox[a[2]] * 0x100 + Sbox[a[3]];

  return b;

}

//密钥线性变换函数L



u32 functionL1(u32 a) {

return a ^ loopLeft(a, 2) ^ loopLeft(a, 10) ^ loopLeft(a, 18) ^ loopLeft(a, 24);

}

//密钥线性变换函数L'



u32 functionL2(u32 a) {

return a ^ loopLeft(a, 13) ^ loopLeft(a, 23);

}

这里返回的是移位操作后的u 32 a

 

轮函数

 

/*

迭代32次

参数: u32 X[4]:迭代对象,保存结果    u32 RK[32]:轮密钥

  

*/

void iterate32(u32 X[], u32 RK[]) {

short i;

for(i = 0; i < 32; i++) {

X[(i+4)%4] = X[i%4] ^ functionT(X[(i+1)%4] ^ X[(i+2)%4] ^ X[(i+3)%4] ^ RK[i], 1);

}

}



/*

反转函数



*/

void reverse(u32 X[], u32 Y[]) {

 short i;

 for(i = 0; i < 4; i++){

  Y[i] = X[4 - 1 - i];

 }

}



  

加密算法

加密算法采用32轮迭代结构,每轮使用一个轮密钥。

 

/*

加密算法

参数: u32 X[4]:明文    u32 RK[32]:轮密钥    u32 Y[4]:密文,保存结果



*/

void encryptSM4(u32 X[], u32 RK[], u32 Y[]) {

iterate32(X, RK);

reverse(X, Y);

}

解密算法

解密算法与加密算法相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。

/*

解密算法

参数: u32 X[4]:密文    u32 RK[32]:轮密钥    u32 Y[4]:明文,保存结果



*/

void decryptSM4(u32 X[], u32 RK[], u32 Y[]) {

short i;

u32 reverseRK[32];

for(i = 0; i < 32; i++) {

reverseRK[i] = RK[32-1-i];

}

iterate32(X, reverseRK);

reverse(X, Y);

}

密钥扩展算法

    SM4算法加密时输入128位的密钥,采用32轮迭代结构,每一轮使用一个32位的轮密钥,共使用32个轮密钥。使用密钥扩展算法,从加密密钥产生出32个轮密钥。

(1)常数

     在密钥扩展中使用如下的常数:

 

(2)固定参数

   共使用32个固定参数

0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,

0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,

0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,

0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,

0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,

0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,

0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,

0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279

/*

密钥扩展算法第一步

参数: MK[4]:密钥  K[4]:中间数据,保存结果 (FK[4]:常数)



*/

void extendFirst(u32 MK[], u32 K[]) {

int i;

for(i = 0; i < 4; i++) {

K[i] = MK[i] ^ FK[i];

}

}



/*

密钥扩展算法第二步

参数: RK[32]:轮密钥,保存结果    K[4]:中间数据 (CK[32]:固定参数)



*/

void extendSecond(u32 RK[], u32 K[]) {

short i;

for(i = 0; i <32; i++) {

K[(i+4)%4] = K[i%4] ^ functionT(K[(i+1)%4] ^ K[(i+2)%4] ^ K[(i+3)%4] ^ CK[i], 2);

RK[i] = K[(i+4)%4];

}

}



/*

密钥扩展算法

参数: MK[4]:密钥     K[4]:中间数据    RK[32]:轮密钥,保存结果



*/

void getRK(u32 MK[], u32 K[], u32 RK[]) {

extendFirst(MK, K);

extendSecond(RK, K);

}

七、实验结果

明文: 01234567 89abcdef fedcba98 76543210

密钥: 01234567 89abcdef fedcba98 76543210

密文: 681edf34 d206965e 86b3e94f 536e4246

 

实验源码:

#include<stdio.h>
#define u8 unsigned char
#define u32 unsigned long

// S盒
const u8 Sbox[256] = {
	0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05,
	0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99,
	0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62,
	0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6,
	0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8,
	0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35,
	0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87,
	0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e,
	0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1,
	0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3,
	0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f,
	0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51,
	0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8,
	0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0,
	0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84,
	0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48
};
	
// 密钥扩展算法的常数FK 
const u32 FK[4] = {
	0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc
};

// 密钥扩展算法的固定参数CK 
const u32 CK[32] = {
	0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
	0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
	0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
	0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
	0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
	0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
	0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
	0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
};

u32 functionB(u32 b); // 查S盒的函数B 
u32 loopLeft(u32 a, short length); // 循环左移函数 
u32 functionL1(u32 a); // 线性变换L
u32 functionL2(u32 a); // 线性变换L'
u32 functionT(u32 a, short mode); // 合成变换T
void extendFirst(u32 MK[], u32 K[]); // 密钥扩展算法第一步
void extendSecond(u32 RK[], u32 K[]); // 密钥扩展算法第二步
void getRK(u32 MK[], u32 K[], u32 RK[]); // 轮密钥获取算法
void iterate32(u32 X[], u32 RK[]); // 迭代算法
void reverse(u32 X[], u32 Y[]); // 反转函数 
void encryptSM4(u32 X[], u32 RK[], u32 Y[]); // 加密算法
void decryptSM4(u32 X[], u32 RK[], u32 Y[]); // 解密算法
 
//查S盒的函数B 

u32 functionB(u32 b) {
	u8 a[4];
	short i;
	a[0] = b / 0x1000000;
	a[1] = b / 0x10000;
	a[2] = b / 0x100;
	a[3] = b;
	b = Sbox[a[0]] * 0x1000000 + Sbox[a[1]] * 0x10000 + Sbox[a[2]] * 0x100 + Sbox[a[3]];
	return b;
}

//循环左移算法
u32 loopLeft(u32 a, short length) {
	short i;
	for(i = 0; i < length; i++) {
		a = a * 2 + a / 0x80000000;
	}
	return a;
}

//密钥线性变换函数L

u32 functionL1(u32 a) {
	return a ^ loopLeft(a, 2) ^ loopLeft(a, 10) ^ loopLeft(a, 18) ^ loopLeft(a, 24);
}

//密钥线性变换函数L'

u32 functionL2(u32 a) {
	return a ^ loopLeft(a, 13) ^ loopLeft(a, 23);
}

/*
	合成变换T
	参数:	u32 a    short mode:1表示明文的T,调用L;2表示密钥的T,调用L' 

*/
u32 functionT(u32 a, short mode) {
	return mode == 1 ? functionL1(functionB(a)) : functionL2(functionB(a));
}
 
/* 
	密钥扩展算法第一步
	参数:	MK[4]:密钥  K[4]:中间数据,保存结果	(FK[4]:常数) 

*/ 
void extendFirst(u32 MK[], u32 K[]) {
	int i;
	for(i = 0; i < 4; i++) {
		K[i] = MK[i] ^ FK[i]; 
	} 
}

/* 
	密钥扩展算法第二步
	参数:	RK[32]:轮密钥,保存结果    K[4]:中间数据 (CK[32]:固定参数) 

*/ 
void extendSecond(u32 RK[], u32 K[]) {
	short i;
	for(i = 0; i <32; i++) {
		K[(i+4)%4] = K[i%4] ^ functionT(K[(i+1)%4] ^ K[(i+2)%4] ^ K[(i+3)%4] ^ CK[i], 2);
		RK[i] = K[(i+4)%4];
	} 
}

/*
	密钥扩展算法 
	参数:	MK[4]:密钥     K[4]:中间数据    RK[32]:轮密钥,保存结果 

*/ 
void getRK(u32 MK[], u32 K[], u32 RK[]) {
	extendFirst(MK, K);
	extendSecond(RK, K);
}

/*
	迭代32次
	参数:	u32 X[4]:迭代对象,保存结果    u32 RK[32]:轮密钥
  
*/
void iterate32(u32 X[], u32 RK[]) {
	short i;
	for(i = 0; i < 32; i++) {
		X[(i+4)%4] = X[i%4] ^ functionT(X[(i+1)%4] ^ X[(i+2)%4] ^ X[(i+3)%4] ^ RK[i], 1);
	}
}

/*
	反转函数 

*/
void reverse(u32 X[], u32 Y[]) {
	 short i;
	 for(i = 0; i < 4; i++){
	 	Y[i] = X[4 - 1 - i];
	 } 
} 

/*
	加密算法
	参数:	u32 X[4]:明文    u32 RK[32]:轮密钥    u32 Y[4]:密文,保存结果 

*/
void encryptSM4(u32 X[], u32 RK[], u32 Y[]) {
	iterate32(X, RK);
	reverse(X, Y);
} 

/*
	解密算法
	参数: 	u32 X[4]:密文    u32 RK[32]:轮密钥    u32 Y[4]:明文,保存结果

*/
void decryptSM4(u32 X[], u32 RK[], u32 Y[]) {
	short i;
	u32 reverseRK[32];
	for(i = 0; i < 32; i++) {
		reverseRK[i] = RK[32-1-i];
	}
	iterate32(X, reverseRK);
	reverse(X, Y);
}
 
/*
	测试数据:
	明文:	01234567 89abcdef fedcba98 76543210
	密钥:	01234567 89abcdef fedcba98 76543210
	密文:	681edf34 d206965e 86b3e94f 536e4246 
*/
int main(void) {
	u32 X[4]; // 明文 
	u32 MK[4]; // 密钥 
	u32 RK[32]; // 轮密钥  
	u32 K[4]; // 中间数据 
	u32 Y[4]; // 密文 
	short i; // 临时变量 
	printf("明文:"); 
	scanf("%8x%8x%8x%8x", &X[0], &X[1], &X[2], &X[3]);
	printf("密钥:"); 
	scanf("%8x%8x%8x%8x", &MK[0], &MK[1], &MK[2], &MK[3]);
	printf("**************生成轮密钥*****************\n"); 
	getRK(MK, K, RK);
	for(i = 0; i < 32; i++) {
		printf("[%2d]:%08x    ", i, RK[i]);
		if(i%4 == 3)	printf("\n"); 
	}
	printf("************** 生成密文 *****************\n"); 
	encryptSM4(X, RK, Y);
	printf("%08x %08x %08x %08x\n", Y[0], Y[1], Y[2], Y[3]);
	printf("************** 生成明文 *****************\n");  
	decryptSM4(Y, RK, X);
	printf("%08x %08x %08x %08x\n", X[0], X[1], X[2], X[3]);
	return 0;	
} 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值