G - Vigenère 密码
16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法——Vigenère 密码。Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为南军所广泛使用。
在密码学中,我们称需要加密的信息为明文,用 M 表示;称加密后的信息为密文,用 C 表示;而密钥是一种参数,是将明文转换为密文或将密文转换为明文的算法中输入的数据,记为 k。 在 Vigenère 密码中,密钥 k是一个字母串,k=k1k2…kn,当明文 M=m1m2…mn时,得到的密文C=c1c2…cn,其中ci=mi®ki,运算®的规则如下表所示:
Vigenère 加密在操作时需要注意:
1、 ® 运算忽略参与运算的字母的大小写,并保持字母在明文 M中的大小写形式;
2、当明文 M 的长度大于密钥 k 的长度时,将密钥 k 重复使用。 例如,文 M=Helloworld,密钥 k=abc 时,密文 C=Hfnlpyosnd。
明文 H e l l o w o r l d
密钥 a b c a b c a b c a
密文 H f n l p y o s n d
输入格式
第一行为一个字符串,表示密钥 k,长度不超过 100,其中仅包含大小写字母。
第二行为一个字符串,表示经加密后的密文,长度不超过 1000,其中仅包含大小写字母。
输出格式
输出共 1 行,一个字符串,表示输入密钥和密文所对应的明文。
数据范围
对于 100% 的数据,输入的密钥的长度不超过 100,输入的密文的长度不超过 1000,且都仅包含英文字母。
Sample Input
CompleteVictory
Yvqgpxaimmklongnzfwpvxmniytm
Sample Output
Wherethereisawillthereisaway
题目分析
拿到这道题一下有点懵,题目字数有点多,感觉有点东西,但是将题目看完之后,就发现实现不难,难的是逻辑运算方面,就是主要考虑怎么将运算表转化成一条可以用公式可以实现的代码语句。
然后通过观察可以发现,这个表是以对角线为界上下对称的,这样就可以更方便转换了。像第一行字母是各字母加上0所得,然后第二列就是各自字母加1所得…以此类推可得后面的也是同样的运算方式。
明文=(密文-密钥)%26 ,相当于就是将密文和密钥在字母表里的序号求出相减再加上对应的大小写ASCⅡ码数,在此基础上再根据密文和密钥的大小写情况进行小调整,就可以推断出明文的字符串。
#include <stdio.h>
int main()
{
char K[101], C[1001];//设两个数组去存放明文和密钥
char M;
int i, j;
scanf("%s", K);//先输入密钥
getchar();//吞掉回车
scanf("%s", C);//输入密文
for (i = 0, j = 0; C[j] != '\0'; j++){//对密文遍历
if (C[j] >= 'A' && C[j] <= 'Z'){//当密文是大写字母的时候
if (K[i] >= 'A' && K[i] <= 'Z')//当密钥分大小写的时候
M = (C[j] - K[i]+26) % 26 + 'A';
else
M = (C[j] - 'A' - (K[i] - 'a')+26) % 26 + 'A';
}
else{//当密文是小写的时候
if (K[i] >= 'A' && K[i] <= 'Z')
M = (C[j] - 'a' - (K[i] - 'A')+26) % 26 + 'a';
else
M = (C[j] - K[i] +26) % 26 + 'a';
}
printf("%c", M);//直接输出转化后的明文字母(逐一输出)
i++;//i递增,当密钥到最后一位时归零循环使用
if (K[i] == '\0') i = 0;
}
return 0;
}
这个代码是一个简单的循环计算输出的操作,希望这个代码抛砖引玉,希望大佬们能有更好的代码。