实现playfair(多字母替代密码)加密与解密程序

本文介绍了如何实现Playfair加密解密程序,包括编制密码表、整理明文及编写密文的步骤。通过示例代码展示具体实现,并对测试数据进行分析,指出差异原因在于Playfair中j通常被替换为i。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   Playfair密码(英文:Playfair cipher 或 Playfair square)是一种替换密码,1854年由查尔斯·惠斯通(Charles Wheatstone)的英国人发明。经莱昂·普莱费尔提倡在英国军地和政府使用。 
  它有一些不太明显的特征:密文的字母数一定是偶数;任意两个同组的字母都不会相同,如果出现这种字符必是乱码和虚码。 
  它使用方便而且可以让频度分析法变成瞎子,在1854到1855年的克里米亚战争和1899年的布尔战争中有广泛应用。但在1915年的一战中被破译了。 

  编写分三步:1.编制密码表 2.整理明文 3.编写密文 构成部分:1.密钥 2.明文3.密文4.注明的某个字母代替的另一个字母

 

代码实现:

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char playfair_table[5][5];
void CreateTable (char *in_key)
{
	int i = 0, j, k;
	int hash[26]={0};
	char key[26] = {0};
	int key_len;
	strcpy (key, in_key);
	key_len = strlen (key);
	//一次遍历,处理密钥
	while (1)
	{
		if (i == key_len)
			break;
		//转换成大写
		if(key[i]>='a'&&key[i]<='z')
		{
			key[i]+='A'-'a';
		}
		//去除非法字符
		if (!(key[i]<='Z'&&key[i]>='A'))
		{
			for (j = i; j < key_len - 1; ++j)
				key[j] = key[j + 1];
			key_len--;
			continue;
		}
		if(key[i]=='J')
		{
			//I和J视为相同
			key[i]='I';
		}
		if(hash[key[i]-'A']==0)
		{
			hash[key[i]-'A']=1;
		}
		else //去除重复
		{
			for (j = i; j < key_len - 1; ++j)
				key[j] = key[j + 1];
			key_len--;
			continue;
		}
		i++;
	}
	//此时,密钥长度必然小于26,长度不够需补全
	if(key_len<25)
	{
		for(i=0;i<26;i++)
		{
			if(key_len==25)
			{
				break;
			}
			if(i+'A'=='J')
				continue;
			if(hash[i]==0)
			{
				hash[i]=1;
				key[key_len]=i+'A';
				key_len++;
			}
		}
	}
	for (i = 0; i < 5;i++)
	{
		for (j = 0; j < 5; j++)
			playfair_table[i][j] = key[5 * i + j];
	}
}

void PrintTable ()
{
	int i, j;
	printf ("Playfair Table:\n");
	for (i = 0; i < 5; ++i)
	{
		printf ("\t");
		for (j = 0; j < 5; ++j)
		{
			printf ("%c ", playfair_table[i][j]);
		}
		puts("\n");
	}
	
}

void GetPosition (char c, int *x, int *y)
{
	int i, j;
	if(c>='a')
	{
		c+=-'a'+'A';
	}
	for (i = 0; i < 5; ++i)
	{
		for (j = 0; j < 5; ++j)
		{
			if (playfair_table[i][j] == c)
			{
				*x = i; *y = j;
				return;
			}
		}
	}
}

char GetKey (int x, int y,char type)
{
	if (x < 0)
		x += 5;
	if (y < 0)
		y += 5;
	if(type<'a')
	{
		return playfair_table[x % 5][y % 5];
	}
	else
	{
		return (playfair_table[x % 5][y % 5]+'a'-'A');
	}
}


int Encrypt (char *input, char *output)
{
	int length = strlen (input);
	int i = 0, j=-1,find;
	int ax, ay, bx, by;
	int pair[2]={-1,-1};
	//for(i=0;i<length;i++)
	//{
	//	if(input[i]>='A'&&input[i]<='Z')
	//	{
	//		input[i]-='A'-'a';//全部转化成小写
	//	}
	//}
	while(1)
	{
		char between[1000]={0};
		int betweenlength=-1;
		find=0;
		//找寻成对出现的第一个字符所在位置
		for(i=pair[1]+1;i<length;i++)
		{
			if((input[i]>='a'&&input[i]<='z')||(input[i]>='A'&&input[i]<='Z'))
			{
				pair[0]=i;
				pair[1]=i+1;
				find=1;
				break;
			}
			else
			{
				output[++j]=input[i];
			}
		}
		if(find==0)
		{
			break;
		}
		//找寻成对出现的第二个字符所在位置
		find=0;
		for(i=pair[1];i<length;i++)
		{
			if((input[i]>='a'&&input[i]<='z')||(input[i]>='A'&&input[i]<='Z'))
			{
				pair[1]=i;
				find=1;
				break;
			}
			else
			{
				between[++betweenlength]=input[i];
			}
		}
		if(find==0)
		{
			input[length]='Q';//代表最后一位的填充
			pair[1]=length;
			length++;
		}
		//开始加密过程
		if(input[pair[1]]==input[pair[0]])
		{
			if(input[pair[0]]!='X')//放置连续的xx影响结果
			{
				//属于相同对中的重复的明文字母将用一个填充字母进行分隔(如x)   
				for(i=length;i>=pair[1];i--)
				{
					input[i+1]=input[i];
				}
				length++;
				input[pair[1]]='X';
			}
		}
		GetPosition(input[pair[0]],&ax,&ay);
		GetPosition(input[pair[1]],&bx,&by);
		//若p1 p2在同一行,对应密文c1 c2分别是紧靠p1 p2 右端的字母。其中第一列被看做是最后一列的右方。
		if(ax==bx)
		{
			output[++j]=GetKey(ax,ay+1,input[pair[0]]);
			for(i=0;i<=betweenlength;i++)
			{
				output[++j]=between[i];
			}
			output[++j]=GetKey(bx,by+1,input[pair[1]]);
		}
		//若p1 p2在同一列,对应密文c1 c2分别是紧靠p1 p2 下方的字母。其中第一行被看做是最后一行的下方。 
		else if(ay==by)
		{
			output[++j]=GetKey(ax+1,ay,input[pair[0]]);
			for(i=0;i<=betweenlength;i++)
			{
				output[++j]=between[i];
			}
			output[++j]=GetKey(bx+1,by,input[pair[1]]);
		}
		//若p1 p2不在同一行,不在同一列,则c1 c2是由p1 p2确定的矩形的其他两角的字母,并且c1和p1, c2和p2同行。 
		else
		{
			output[++j]=GetKey(ax,by,input[pair[0]]);
			for(i=0;i<=betweenlength;i++)
			{
				output[++j]=between[i];
			}
			output[++j]=GetKey(bx,ay,input[pair[1]]);
		}
	}
	return length;
}


int Decrypt (char *input, char *output)
{
	int length = strlen (input);
	int i = 0, j=-1,find;
	int ax, ay, bx, by;
	int pair[2]={-1,-1};
	while(1)
	{
		char between[1000]={0};
		int betweenlength=-1;
		find=0;
		//找寻成对出现的第一个字符所在位置
		for(i=pair[1]+1;i<length;i++)
		{
			if((input[i]>='a'&&input[i]<='z')||(input[i]>='A'&&input[i]<='Z'))
			{
				pair[0]=i;
				pair[1]=i+1;
				find=1;
				break;
			}
			else
			{
				output[++j]=input[i];
			}
		}
		if(find==0)
		{
			break;
		}
		//找寻成对出现的第二个字符所在位置
		find=0;
		for(i
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值