一、算法要求:

二、代码:
#include<windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>//topper函数
// 将密钥中的字母转换成大写
void ConverstAlphabet(char key[]) {
int keyLen = strlen(key);
for (int i = 0; i < keyLen; i++)
{
key[i] = toupper(key[i]);
//toupper函数将小写字母转换为大写字母
}
}
//将密钥的字符去重
int Deduplication(char key[], int keylen1)
{
//keylen1是原始的密钥的长度
if (keylen1 <= 1)
{
return 0;
}
int i = 0;
int j = 0;
int count = 1;
for (i = 1; i < keylen1; i++)
{
for (j = 0; j < i; j++)
{
if (key[i] == key[j])
{
break;
}
}
if (i == j)
{
key[count++] = key[i];
}
}
key[count] = '\0';//末尾加一个\0
return count;//count个
}
// 生成密码表
void CreatPassWordTable(char key[], char table[5][5], int keylen2)
{
char alphabet[] = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
int alphabetLen = strlen(alphabet);
int k = 0;
//这个for循环是把密钥放到密钥表中
for (int i = 0; i < keylen2; i++) {//keylen2是去重后的密钥的长度
table[k / 5][k % 5] = key[i];
k++;
}
//把未重复的放进密码表
for (int i = 0; i < alphabetLen; i++)
{
if (alphabet[i] == 'J') {
// 将字母J转换成I
continue;
}
int flag = 0;
for (int j = 0; j < keylen2; j++)
{
if (key[j] == alphabet[i])
{//判断密钥和25个字母是否相等
flag = 1;
break;
}
}
if (!flag) {
table[k / 5][k % 5] = alphabet[i];//开始把字母存放到密钥表中去
k++;
}
}
}
/*
对明文按如下规则一次加密两个字母:
(1) 如果两个字母相同,则中间填充一个字母,如x,balloon-->balxloon-->ba lx lo on。前面的ll变lxl,后面的两个oo就不是一对了,中间无需再加x
(2) 明文去掉空格再加密,如果最终得到明文长度不是偶数的,可填充一个字母。
(2) 落在矩阵同一行中的明文字母对,由其右边的字母代替。如ar-->RM
(3) 落在矩阵同一列中的明文字母对,由其下面的字母代替。如mu-->CM
(4) 其它明文字母对:该字母所在行为密文所在行,另一字母所在列为密文所在列。如hs-->BP,ea-->IM(或JM)
*/
// 加密明文
void encrypt(char plaintext[], char table[][5]) {
int len = strlen(plaintext);
char p[100] = { 0 };
int t = 0,z;
for (int i = 0; i < len; i += 2)
{ if(plaintext[i]==plaintext[i+1])
{
for(z=len;z>=i+2;z--)
plaintext[z]=plaintext[z-1];
len++;
if(plaintext[i]!='X') plaintext[i+1]='X';
}
}
//printf("加密过程中首先对明文处理为:") ;
//for (int i = 0; i < len; i ++)
// printf("%c",plaintext[i]);
//printf("\n");
for (int i = 0; i < len; i += 2) {//因为一次找两个字符,所以这里是i+=2
int row1 = 0, col1 = 0, row2 = 0, col2 = 0;
// 查找明文字母在密码表中的位置
for (int j = 0; j < 5; j++) {
for (int k = 0; k < 5; k++) {
if (table[j][k] == plaintext[i]) {
row1 = j;
col1 = k;
}
if (table[j][k] == plaintext[i + 1]) {
row2 = j;
col2 = k;
}
}
}
// 使用Playfair密码规则加密
if (row1 == row2) {
// 如果明文字母在同一行
col1 = (col1 + 1) % 5;
col2 = (col2 + 1) % 5;
}
else if (col1 == col2) {
// 如果明文字母在同一列
row1 = (row1 + 1) % 5;
row2 = (row2 + 1) % 5;
}
else {
// 如果明文字母不在同一行也不在同一列
int temp = col1;//找对角线
col1 = col2;
col2 = temp;
}
//打印加密明文后的密文
printf("%c%c", table[row1][col1], table[row2][col2]);
}
}
// 解密密文
void decrypt(char ciphertext[], char table[][5]) {
int len = strlen(ciphertext);
char str[len];
int t = 0,q,i;
printf("解密密文之后的明文为:\n");
for (int i = 0; i < len-1; i += 2) {
int row1 = 0, col1 = 0, row2 = 0, col2 = 0;
// 查找密文字母在密码表中的位置
for (int j = 0; j < 5; j++) {
for (int k = 0; k < 5; k++) {
if (table[j][k] == ciphertext[i]) {
row1 = j;
col1 = k;
}
if (table[j][k] == ciphertext[i + 1]) {
row2 = j;
col2 = k;
}
}
}
// 使用Playfair密码规则解密
if (row1 == row2) {
// 如果密文字母在同一行
col1 = (col1 + 4) % 5;
col2 = (col2 + 4) % 5;
}
else if (col1 == col2) {
// 如果密文字母在同一列
row1 = (row1 + 4) % 5;
row2 = (row2 + 4) % 5;
}
else {
// 如果密文字母不在同一行也不在同一列
int temp = col1;
col1 = col2;
col2 = temp;
}
//打印解密的明文
str[i]=table[row1][col1];
str[i+1]=table[row2][col2];
}
for(i=0;i<len-1;i++)
{if(str[i]=='X'&&str[i-1]==str[i+1])
{
for(q=i;q<len-1;q++)
str[q]=str[q+1];
len--;
}
}
for(i=0;i<len;i++)
printf("%c",str[i]);
printf("\n");
}
// 打印密码表
void printTable(char table[][5])
{
printf("打印出Playfair密码表:\n");
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%c ", table[i][j]);
}
printf("\n");
}
printf("\n");
}
void init(char plaintext[])
{
int i,len=strlen(plaintext),p;
for(i=0;i<strlen(plaintext);i++)
if(plaintext[i]==' ')
{
for(p=i;p<len-1;p++)
plaintext[p]=plaintext[p+1];
len--;
plaintext[len]='\0';
}
//若明文为奇数需要在末尾加入一个无关字符
if(strlen(plaintext)%2!=0)
{
plaintext[len]='M';
plaintext[len]='\0';
}
ConverstAlphabet(plaintext);//把明文中的小写字母转换为大写字母
}
int main() {
SetConsoleOutputCP(65001);
char key[100] = { 0 };//密钥
char plaintext[100] = { 0 };//明文
char ciphertext[100] = { 0 };//密文
char table[5][5] = { 0 };
int input = 0;
printf("请输入密钥(不超过100个字符):");
scanf("%s", key);
ConverstAlphabet(key);//把密钥中的小写字母转换为大写字母
int keylen1 = strlen(key);//keylen1为去重前的密钥的长度
int keylen2 = Deduplication(key, keylen1);//把密钥中的字符去重,keylen2为去重后的长度
CreatPassWordTable(key, table, keylen2);
printTable(table);
printf("请你输入要加密的明文:\n(若明文有空格,去掉空格,若明文个数为奇数需要在末尾加入一个无关字符)\n");
scanf("%s", plaintext);
init(plaintext);
printf("加密明文后得到的密文为:\n");
encrypt(plaintext, table);
printf("\n");
printf("请你输入要解密的密文:\n");
scanf("%s", ciphertext);
ConverstAlphabet(ciphertext);//把密文中的小写字母转换为大写字母
printf("\n");
decrypt(ciphertext, table);
return 0;
}