如何使用C语言实现Vigenère密码加解密
如何使用C语言实现Vigenère密码加解密
在洛谷看到这题,觉得有意思,遂写。
参考文章:C语言实现Vigenere加解密算法(附带源码)
1. Vigenère密码简介与原理
Vigenère密码是一种多表密码,使用一系列凯撒密码(Caesar cipher)来实现加密。在Vigenère密码中,明文中的每个字符都被替换为密文中的对应字符,而密钥用于确定使用哪个凯撒密码表。具体来说,明文中的每个字符都会根据密钥中的字符进行位移,从而生成密文。如图:
加密例子:明文:HELLO,密钥:KEY,加密后:RIJVS
对照表中,先将密钥填充至与明文长度相同:KEYKE。然后在对照表中找到明文字符对应的密文字符,如第一个字符在对照表中的K行找到H列,对应的字符是R,于是第一个字符就被加密成R。以此类推,直到明文全部加密完成。
实际操作中,其实就是一系列的不同的凯撒密码加密,而密钥决定了使用哪个凯撒密码表,这里不赘述。我们把字母转换成数字(A = 0,B = 1,……),写成公式可以表达成:
加密:C = (P + K)% 26
其中C为密文字符数,P为明文字符数,K为密钥字符。同样可以得到解密公式:
解密:P = (C - K + 26)% 26
2.具体实现
这里仅给出函数实现,以及省略了引入string.h和ctype.h头文件。
我们可以考虑先忽略字母的大小写,解密后再对照原文判断是否转换大小写。先实现字母转数字、数字转字母的函数:
int Char_to_Number(char c)
{
return c - 'A';
}
char Number_to_Char(int num, char origin)
{
char c = 'A' + num;
//* 对照原文
if (islower(origin))
{
return tolower(c);
}
return c;
}
解码:
char *Decode(char *key, char *C, char *M)
{
for (int i = 0, j = 0; i < strlen(C); i++)
{
if (isalpha(C[i]))
{
int keyNum = Char_to_Number(key[j % strlen(key)]); // 填充密钥
int CNum = Char_to_Number(C[i]);
int MNum = (CNum - keyNum + 26) % 26;
M[i] = Number_to_Char(MNum, C[i]);
// 不能在循环体里面写j++😡,否则遇到非字母字符j也会增加
j++;
}
else
{
M[i] = C[i];
}
}
return M;
}
加密:
char *Encode(char *key, char *M, char *C)
{
for (int i = 0, j = 0; i < strlen(M); i++)
{
if (isalpha(M[i]))
{
int keyNum = Char_to_Number(key[j % strlen(key)]);
int MNum = Char_to_Number(M[i]);
int CNum = (MNum + keyNum) % 26;
C[i] = Number_to_Char(CNum, M[i]);
j++;
}
else
{
C[i] = M[i];
}
}
}
完整测试用例代码:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int Char_to_Number(char c);
char Number_to_Char(int num, char origin);
char *Decode(char *key, char *C, char *M);
char *Encode(char *key, char *M, char *C);
int main()
{
char key[101];
char C[1001];
char M[1001];
fgets(key, sizeof(key), stdin);
fgets(C, sizeof(C), stdin);
key[strcspn(key, "\n")] = '\0';
C[strcspn(C, "\n")] = '\0';
Decode(key, C, M);
printf("%s\n", M);
// Encode(key, M, C);
// printf("%s\n", C);
return 0;
}
int Char_to_Number(char c)
{
return toupper(c) - 'A';
}
char Number_to_Char(int num, char origin)
{
char c = 'A' + num;
//* 对照原文
if (islower(origin))
{
return tolower(c);
}
return c;
}
char *Decode(char *key, char *C, char *M)
{
for (int i = 0, j = 0; i < strlen(C); i++)
{
if (isalpha(C[i]))
{
int keyNum = Char_to_Number(key[j % strlen(key)]); // 填充密钥
int CNum = Char_to_Number(C[i]);
int MNum = (CNum - keyNum + 26) % 26;
M[i] = Number_to_Char(MNum, C[i]);
j++; // 不能在循环体里面写j++😡,否则遇到非字母字符j也会增加
}
else
{
M[i] = C[i];
}
}
return M;
}
char *Encode(char *key, char *M, char *C)
{
for (int i = 0, j = 0; i < strlen(M); i++)
{
if (isalpha(M[i]))
{
int keyNum = Char_to_Number(key[j % strlen(key)]);
int MNum = Char_to_Number(M[i]);
int CNum = (MNum + keyNum) % 26;
C[i] = Number_to_Char(CNum, M[i]);
j++;
}
else
{
C[i] = M[i];
}
}
}
3. 总结
知道了加解密公式,实现起来就很简单,以及注意需要对照原文判断转换字母的大小写。
介绍和图片来源于网络,侵删。

浙公网安备 33010602011771号