第4关:维吉尼亚密码
任务描述
在前面介绍的移位密码和代换密码中,一旦密钥被选定,则每个字母对应的数字都被加密变成对应的唯一数字。这种密码体制我们一般称为单表代换密码。下面介绍的是有名的维吉尼亚密码,这是一种多表代换密码。
本关任务:用 C++ 实现维吉尼亚密码,然后对输入的明文字符串进行维吉尼亚加密后打印输出。
相关知识
为了完成本关任务,你需要掌握:维吉尼亚密码的密码体制。
维吉尼亚密码的密码体制
维吉尼亚密码(又译维热纳尔密码)是使用一系列凯撒密码组成密码字母表的加密算法,属于多表密码的一种简单形式。下面给出具体定义。 设m
是一个正整数,定义P=C=K=(Z26)m
(这里之所以会多出一个m
次方,就是因为维吉尼亚密码是一个多表代换,即对于相同的明文可以对应不同的密文)。对任意的密钥K=(k1,k2,...,km)
,定义: ek(x1,x2,...,xm)=(x1+k1,x2+k2,...,xm+km) 这个是加密函数。 dk(y1,y2,...,ym)=(y1−k1,y2−k2,...,ym−km) 这个是解密函数。 以上所有的运算都是在Z26
上进行。 相信你看到这里还是一知半解,下面我们通过一个例子来让你真正的学会维吉尼亚密码。 假设m=6
,密钥字为“CIPHER”,其对应于如下的数字串K=(2,8,15,7,4,17)
。要加密的明文为thiscryptos
。 那么我们可以把明文转化为对应的数字,使用密钥字进行模26的运算。
19 | 7 | 8 | 18 | 2 | 17 | 24 | 15 | 19 | 14 | 18 |
---|---|---|---|---|---|---|---|---|---|---|
2 | 8 | 15 | 7 | 4 | 17 | 2 | 8 | 15 | 7 | 4 |
21 | 15 | 23 | 25 | 6 | 8 | 0 | 23 | 8 | 21 | 22 |
那么相应的密文为:vpxzgiaxivw
。 从上面这个例子我们可以观察到,维吉尼亚密码体制实际上就是对密钥串的多次重复利用,最终得出每个明文字符的密文。 我们可以从这里看出,维吉尼亚密码的密钥空间大小为26m
,所以即使m
的值很小,使用穷尽密钥搜索方法也需要很长时间。比如当m=5
的时候,密钥空间大小超过1.1×107
,这样的范围超过了手算进行穷尽搜索的能力范围。 一般来说多表代换密码比单表代换密码更为安全一些。
编程要求
本关的编程任务是,补全右侧编辑器 Begin-End 区间的代码,实现给定字符串的加密功能,具体要求如下:
- 给定密钥串以及明文串,打印输出密文串(密文串全部为小写字母)。
注意:遇到大写字母要变换成小写字母来处理。
测试说明
平台会对你编写的代码进行测试:
测试输入:
ewdsa
dsadsvccvcxv
预期输出:
hodvszyfncbr
测试输入:
dderc
sacxvcxbfhjSDDAchdzcbnxz
预期输出:
vdgoxfafwjmvhucfkhqeeqbq
代码:
#include<bits/stdc++.h>
using namespace std;
// 函数来加密单个字符
char encryptChar(char plainChar, char keyChar) {
plainChar = tolower(plainChar); // 转换为小写
keyChar = tolower(keyChar); // 转换为小写
char offset = keyChar - 'a'; // 计算偏移量
return (plainChar - 'a' + offset) % 26 + 'a'; // 应用偏移并转换回字符
}
// 函数来加密整个字符串
string encryptString(string plainText, string key) {
string cipherText = "";
int keyIndex = 0;
for (char c : plainText) {
if (isalpha(c)) { // 只处理字母
cipherText += encryptChar(c, key[keyIndex]);
keyIndex = (keyIndex + 1) % key.length(); // 更新密钥索引
} else {
cipherText += c; // 非字母字符保持不变
}
}
return cipherText;
}
int main()
{
string A, B;
cin >> A; // 读取密钥
cin >> B; // 读取明文
/*********** Begin ***********/
string encrypted = encryptString(B, A); // 对明文进行加密
cout << encrypted; // 打印密文
/*********** End ***********/
return 0;
}