密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)

文章目录

  • 1. 分组密码(Twine)
    • 1.1 加解密方式
      • 1.1.1 加密
      • 1.1.2 密钥生成算法
      • 1.1.3 解密
      • 1.1.4 全部代码
    • 1.2. 分组密码的模式
      • 1.2.1 ECB模式
      • 1.2.2 CBC模式
      • 1.2.3 CFB模式
      • 1.2.4 OFB模式
      • 1.2.5 CTR模式
  • 2.序列密码

如图,对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。具有算法公开、计算量小、加密速度快、加密效率高等特点。密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第1张图片

1. 分组密码(Twine)

Twine是由Tomoyasu Suzaki,Kazuhiko Minematsu, Sumio Morioka和Eita Kobayashi在2011年的ECRYPT轻量级密码会议上首次提出的,并发表在2012年的SAC会议上。它的分组长度是64比特,密钥长度有80比特和128比特两个版本,其采用广义的Feistel结构(Generalized Feistel Structure,简称GFS),并由36轮轮函数构成,这里我们重点介绍80位的算法。

1.1 加解密方式

1.1.1 加密

Twine-80的加密算法如下所示:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第2张图片
该算法采用的是广义的Feistel结构,具体结构如下图所示:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第3张图片
我们可以看出,此算法在Feistel结构的基础上改造了位置交换的方法,我们称之为π置换(π-1置换用于解密):
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第4张图片
Feistel结构中S盒如下表:S-box

void Feistel(int r,int k)
{
     
	int i;
	char a;
	if(k == 1)
	{
     
		if(r != 35)
			for(i = 0;i < 16;i += 2)
			{
     
				OutPut[PI[i]] = InPut[i];
				a = S[InPut[i] ^ R_Key[r][i / 2]];
				OutPut[PI[i + 1]] = InPut[i + 1] ^ a;
			}
		else
			for(i = 0;i < 16;i += 2)
			{
     
				OutPut[i] = InPut[i];
				a = S[InPut[i] ^ R_Key[r][i / 2]];
				OutPut[i + 1] = InPut[i + 1] ^ a;
			}
	}
	else
	{
     
		if(r != 35)
			for(i = 0;i < 16;i += 2)
			{
     
				OutPut[Pi[i]] = InPut[i];
				a = S[InPut[i] ^ R_Key[35 - r][i / 2]];
				OutPut[Pi[i + 1]] = InPut[i + 1] ^ a;
			}
		else
			for(i = 0;i < 16;i += 2)
			{
     
				OutPut[i] = InPut[i];
				a = S[InPut[i] ^ R_Key[35 - r][i / 2]];
				OutPut[i + 1] = InPut[i + 1] ^ a;
			}
	}
}

1.1.2 密钥生成算法

Twine-80的密钥生成算法如下所示:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第5张图片
方便起见,我们将算法用图画出:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第6张图片
其中轮常数Con如下:密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第7张图片

void MakeRKey()
{
     
	int i,j,k;
	int choose[8] = {
     1,3,4,6,13,14,15,16};
	char ch,ConH,ConL;
	char key[20] = {
     0};
	for(i = 0;i < 10;i++)
	{
     
		ch = fgetc(KEY);
		for(j = (2 * i) + 1;j >= 2 * i;j--)
		{
     
			key[j] = ch & 0x0F;
			ch = ch >> 4;
		}
	}
	for(i = 0;i < 36;i++)
	{
     
		for(j = 0;j < 8;j++)
			R_Key[i][j] = key[j];
		if(i < 35)
		{
     
			key[1] = key[1] ^ S[key[0]];
			key[4] = key[4] ^ S[key[16]];
			ConL = CON[i] & 0x07;
			ConH = CON[i] >> 3;
			ConH = ConH & 0x07;
			key[7] = key[7] ^ ConH;
			key[19] = key[19] ^ ConL;
			ch = key[0];
			for(j = 0;j < 19;j++)
				key[j] = key[j + 1];
			key[j] = ch;
			for(k = 0;k < 3;k++)
			{
     
				ch = key[0];
				for(j = 0;j < 18;j++)
					key[j] = key[j + 1];
				key[j] = ch;
			}
		}
	}
}

1.1.3 解密

由于轮函数的等价结构,解密算法与加密算法除π置换与轮密钥的注入顺序不同外,其余均相似。

1.1.4 全部代码

代码作用是将plaintext0.txt中的数据加密为ciphertext.txt,然后再解密为plaintext.txt:

#include
#include
#include

FILE *KEY;
int flag;
int PI[16] = {
     5,0,1,4,7,12,3,8,13,6,9,2,15,10,11,14};
int Pi[16] = {
     1,2,11,6,3,0,9,4,7,10,13,14,5,8,15,12};
char S[16] = {
     0x0c,0x00,0x0f,0x0a,0x02,0x0b,0x09,0x05,
			  0x08,0x03,0x0d,0x07,0x01,0x0e,0x06,0x04};
char CON[35] = {
     0x01,0x02,0x04,0x08,0x10,0x20,0x03,
				0x06,0x0c,0x18,0x30,0x23,0x05,0x0a,
				0x14,0x28,0x13,0x26,0x0f,0x1e,0x3c,
				0x3b,0x35,0x29,0x11,0x22,0x07,0x0e,
				0x1c,0x38,0x33,0x25,0x09,0x12,0x24};
char InPut[16] = {
     0},OutPut[16] = {
     0};
char R_Key[36][8] = {
     0};
char plain[16] = {
     0},cipher[16] = {
     0};

void Read(FILE *OUT,int k)
{
     
	int i,j;
	char ch;
	for(i = 0;i < 8;i++)
	{
     
		ch = fgetc(OUT);
		if(ch == -1)
		{
     
			ch = 0;
			flag = 0;
			if(i == 0)
			{
     
				flag = -1;
				return;
			}
		}
		for(j = (2 * i) + 1;j >= 2 * i;j--)
		{
     
			if(k == 1)
				plain[j] = ch & 0x0F;
			else
				cipher[j] = ch & 0x0F;
			ch = ch >> 4;
		}
	}
}

void Write(FILE *IN,int k)
{
     
	int i,j;
	char ch;
	for(i = 0;i < 8;i++)
	{
     
		ch = 0x00;
		for(j = 2 * i;j <= (2 * i) + 1;j++)
		{
     
			ch = ch << 4;
			if(k == 1)
				ch =  ch | cipher[j];
			else
				ch =  ch | plain[j];
		}
		fputc(ch,IN);
	}
}

void MakeRKey()
{
     
	int i,j,k;
	int choose[8] = {
     1,3,4,6,13,14,15,16};
	char ch,ConH,ConL;
	char key[20] = {
     0};
	for(i = 0;i < 10;i++)
	{
     
		ch = fgetc(KEY);
		for(j = (2 * i) + 1;j >= 2 * i;j--)
		{
     
			key[j] = ch & 0x0F;
			ch = ch >> 4;
		}
	}
	for(i = 0;i < 36;i++)
	{
     
		for(j = 0;j < 8;j++)
			R_Key[i][j] = key[j];
		if(i < 35)
		{
     
			key[1] = key[1] ^ S[key[0]];
			key[4] = key[4] ^ S[key[16]];
			ConL = CON[i] & 0x07;
			ConH = CON[i] >> 3;
			ConH = ConH & 0x07;
			key[7] = key[7] ^ ConH;
			key[19] = key[19] ^ ConL;
			ch = key[0];
			for(j = 0;j < 19;j++)
				key[j] = key[j + 1];
			key[j] = ch;
			for(k = 0;k < 3;k++)
			{
     
				ch = key[0];
				for(j = 0;j < 18;j++)
					key[j] = key[j + 1];
				key[j] = ch;
			}
		}
	}
}

void Feistel(int r,int k)
{
     
	int i;
	char a;
	if(k == 1)
	{
     
		if(r != 35)
			for(i = 0;i < 16;i += 2)
			{
     
				OutPut[PI[i]] = InPut[i];
				a = S[InPut[i] ^ R_Key[r][i / 2]];
				OutPut[PI[i + 1]] = InPut[i + 1] ^ a;
			}
		else
			for(i = 0;i < 16;i += 2)
			{
     
				OutPut[i] = InPut[i];
				a = S[InPut[i] ^ R_Key[r][i / 2]];
				OutPut[i + 1] = InPut[i + 1] ^ a;
			}
	}
	else
	{
     
		if(r != 35)
			for(i = 0;i < 16;i += 2)
			{
     
				OutPut[Pi[i]] = InPut[i];
				a = S[InPut[i] ^ R_Key[35 - r][i / 2]];
				OutPut[Pi[i + 1]] = InPut[i + 1] ^ a;
			}
		else
			for(i = 0;i < 16;i += 2)
			{
     
				OutPut[i] = InPut[i];
				a = S[InPut[i] ^ R_Key[35 - r][i / 2]];
				OutPut[i + 1] = InPut[i + 1] ^ a;
			}
	}
}

int main()
{
     
	int mode,i,r;
	FILE *M,*C;
	if((KEY = fopen("key.txt","rb")) == NULL)
	{
     
		printf("\nkey.txt Fail,Close!");
		getchar();
		exit(1);
	}
	MakeRKey();
	while(1)
	{
     
		flag = 1;
		printf("Plase choose:\n1. encrypt \n2. decrypt \n3. exit \n");
		scanf("%d",&mode);
		if(mode == 1)
		{
     
			if((M = fopen("plaintext0.txt","rb")) == NULL)
			{
     
				printf("\nplaintext.txt Fail,Close!");
				getchar();
				exit(1);
			}
			if((C = fopen("ciphertext.txt","wb")) == NULL)
			{
     
				printf("\nciphertext.txt Fail,Close!");
				getchar();
				exit(1);
			}
			while(flag)
			{
     
				Read(M,1);
				if(flag == -1)
					break;
				for(i = 0;i < 16;i++)
					InPut[i] = plain[i];
				for(r = 0;r < 36;r++)
				{
     
					Feistel(r,1);
					for(i = 0;i < 16;i++)
						InPut[i] = OutPut[i];
				}
				for(i = 0;i < 16;i++)
					cipher[i] = OutPut[i];
				Write(C,1);
			}
			fclose(M);
			fclose(C); 
		}
		if(mode == 2)
		{
     
			if((C = fopen("ciphertext.txt","rb")) == NULL)
			{
     
				printf("\nciphertext.txt Fail,Close!");
				getchar();
				exit(1);
			}
			if((M = fopen("plaintext.txt","wb")) == NULL)
			{
     
				printf("\nplaintext.txt Fail,Close!");
				getchar();
				exit(1);
			}
			while(flag)
			{
     
				Read(C,2);
				if(flag == -1)
					break;
				for(i = 0;i < 16;i++)
					InPut[i] = cipher[i];
				for(r = 0;r < 36;r++)
				{
     
					Feistel(r,2);
					for(i = 0;i < 16;i++)
						InPut[i] = OutPut[i];
				}
				for(i = 0;i < 16;i++)
					plain[i] = OutPut[i];
				Write(M,2);
			}
			fclose(M);
			fclose(C); 
		}
		if(mode == 3)
		{
     
			fclose(KEY);
			exit(0);
		}
		system("pause");
		system("cls");
	}
	return 0;
}

1.2. 分组密码的模式

在数组密码中,如何将长的明文数据分成算法要求的长度也是一个问题。为此,人们提出了分组密码的分组模式:

1.2.1 ECB模式

加密:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第8张图片
解密:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第9张图片

1.2.2 CBC模式

加密:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第10张图片
解密:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第11张图片

1.2.3 CFB模式

加密:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第12张图片
解密:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第13张图片

1.2.4 OFB模式

加密:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第14张图片
解密:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第15张图片

1.2.5 CTR模式

加密:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第16张图片
解密:
密码学学习笔记(二)——对称密码算法(轻量级密码算法Twine)_第17张图片

2.序列密码

序列密码也称为流密码(Stream Cipher),它是对称密码算法的一种。序列密码具有实现简单、便于硬件实施、加解密处理速度快、没有或只有有限的错误传播等特点,因此在实际应用中,特别是专用或机密机构中保持着优势,典型的应用领域包括无线通信、外交通信。
1949年Shannon证明了只有一次一密的密码体制是绝对安全的,这给序列密码技术的研究以强大的支持,序列密码方案的发展是模仿一次一密系统的尝试,或者说“一次一密”的密码方案是序列密码的雏形。如果序列密码所使用的是真正随机方式的、与消息流长度相同的密钥流,则此时的序列密码就是一次一密的密码体制。若能以一种方式产生一随机序列(密钥流),这一序列由密钥所确定,则利用这样的序列就可以进行加密,即将密钥、明文表示成连续的符号或二进制,对应地进行加密,加解密时一次处理明文中的一个或几个比特。
在序列密码中,密钥流由密钥流发生器f产生:zi=f(k,si),这里的si是加密器中存储器(记忆元件)在i时刻的状态。根据加密器中的记忆元件si的存贮状态是否依赖于明文字符,序列密码可进一步分成同步和自同步两种。如果si独立于明文字符则称为同步流密码,否则称为自同步流密码。
序列密码算法主要依靠(线性)反馈移位寄存器,这里就不过多说明了。

你可能感兴趣的:(密码学,密码学)