个人关于头歌上相关案例的一些简单记录
移位密码
移位密码体制
通俗的来讲,移位密码体制就是通过一个线性变换,即一次方程,是使得在该变换下,明文和密文是一一对应的。下面给出具体的移位的密码体制。 令P=C=K=Z26
(这里的P表示明文空间,C代表密文空间,K代表密文空间)。对0<=K<=25
,任意x,y
属于Z26
,定义:
-
ek(x)=(x+K)mod26
,这个是加密式子,具体是对每一位明文字符x
进行右移K
位得到密文。 -
dk(x)=(y−K)mod26
,这个是解密式子,具体是对每一位密文字符y
进行左移K
位得到明文。
另外当K=3
的时候,此密码体制叫做凯撒密码。
单看定义是不是很糊涂, 不要管, 记住这是凯撒密码就可以了。举例来说,如果密钥是3,则明文中的每个字母都向后移动3个位置,即A变成D,B变成E,以此类推。
代码
#include<bits/stdc++.h>
using namespace std;
char S[100];
//在下面Begin和End之间补全代码,对输入的字符串进行K位移动加密
int main()
{
int K;
scanf("%d",&K);
cin>>S;
/*********** Begin ***********/
/*********** End ***********/
}
对于这个题干,K是秘钥,S是明文。
就是把S中的每个字母依次向后移动K位即可, 得解:
#include<bits/stdc++.h>
using namespace std;
char S[100];
//在下面Begin和End之间补全代码,对输入的字符串进行K位移动加密
int main()
{
int K;
scanf("%d",&K);
cin>>S;
/*********** Begin ***********/
for (int i = 0; S[i] != '\0'; i++) {
if (isalpha(S[i])) {
char base = islower(S[i]) ? 'a' : 'A';
S[i] = ((S[i] - base + K) % 26) + base;
}
}
cout<<S<<endl;
/*********** End ***********/
}
代换密码
代换密码体制
代换密码就是明文中每一个字符被替换成密文中的另外一个字符,代换后的各字母保持原来的位置。对密文进行逆替换就可以恢复出明文。
下面给出代换密码的具体定义。 令P=C=Z26
,K
由26
个数字0,1,...,25
的所有可能代换组成。对任意的代换π属于K
,定义: 加密函数: eπ(x)=π(x) 解密函数: dπ(y)=π−1(y) 这里的π−1
代表置换π
的逆代换。 在代换密码的情形下,可简单的将加密和解密过程直接看做是一个字母表上的置换。
同样,看定义乱七八糟的,核心就是替换。
测试说明
看测试说明就很好理解了
测试输入:
mbgyalzvepsfonxqgduritwkch
vgiyzmpxgbscutkrnhoafdqwel
ggxrpnrvystmwcysyycqpevikeffmznimkkasvwsrenzkycx
预期输出:
nnkabtaxysdvqeysyyerbgxfwgccvptfvwwzsxqsagtpwyek
输入的明文 x被替换为k,r替换为a,可以看到就是输入第一行的字母按照顺序被替换为第二行的字母
至于为什么初始的g被替换成了n而不是i
可以理解为发生了二次替换
在定义代换时, g一开始是被替换未i, 但在A字符串继续索引时, 会出现第二个g的替换
此时第二个g的替换会覆盖第一个g的替换, 导致最终的明文加密时是 g -> n 而不是 g -> i
理解了这一点代码就很容易了
C++支持直接用词典MAP的方式进行转换
代码
#include<bits/stdc++.h>
using namespace std;
char A[27],B[27],M[100];
map<char,char>MAP;
//在下面Begin和End之间补全代码,对输入的字符串进行代换表置换
int main()
{
cin>>A;
cin>>B;
cin>>M;
/*********** Begin ***********/
for(int i=0;i<26;i++){
MAP[A[i]]=B[i];
}
for(int i=0;M[i]!='\0';i++){
if(MAP.find(M[i])!=MAP.end()){
M[i]=MAP[M[i]];
}
}
cout<<M<<endl;
/*********** End ***********/
}
仿射密码
仿射密码为单表加密的一种,字母系统中所有字母都利用一个简单数学方程加密,对应至数值或转回字母。
仿射密码体制
令P=C=Z26
且K=(a,b)∈Z26×Z26:gcd(a,26)=1
,对任意的K=(a,b)∈K,x,y∈Z26
,定义加密变换为: ek(x)=(ax+b)(mod 26)
相应的解密变换为: dk(y)=a−1(y−b)(mod 26) 下面给出一个例子: 设密钥K=(7,3)
,由前所得,有7−1(mod 26)=15
。加密函数为ek=7x+3(mod 26)
,因为7×15≡1(mod 26)
,相应的解密变换为: dk(y)=15(y−3)(mod 26)=15y−45(mod 26) 上面的运算均是在Z26
上完成的。下面来验证对于任意的x∈Z26
,都有dk(ek(x))=x
,下面是验证过程: dk(ek(x))=dk(7x+3)
=15(7x+3)−45
=x+45−45
=x
验证完毕。
直接看定义还是非常复杂, 关键是解密的变换甚至是写错的, 应该是下面这两个:
F(x)=(ax+b)(mod 26) 加密
D(y) = a^-1 * (y - b) mod 解密
这里的 a^-1不是幂指数, 而是表示逆元
如果存在整数x使得 (a * x) mod m = 1,那么x就是a在模数m下的逆元
测试说明
测试输入:
2 3
qwercvzzxx
预期输出:
asqqkcooii
测试输入:
5 10
qwercvzzxx
预期输出:
gmuhslppnn
输入的两个字符就是 a和b , 对应输入字符串的每个字符就是密文y
因为只要解密, 所以看F(y)=a^-1(y−b)](mod 26) 即可
代码
#include<bits/stdc++.h>
using namespace std;
char A[103];
constexpr int mod=26;
//在下面Begin和End之间补全代码,对输入的字符串进行仿射密码解密
/*********** Begin ***********/
size_t quick(size_t x,size_t y)
{
size_t ans=x;
while(y)
{
if(y&1)
ans=ans*x%mod;
x=x*x%mod;
y>>=1;
}
return ans;
}
int main()
{
int a,b;
cin>>a>>b;
cin>>A;
int x=quick(a,15);
for(int i=0; i<strlen(A); i++)
printf("%c",'a'+(x*((A[i]-'a'-b+mod)%mod)%mod));
return 0;
}
/*********** End ***********/
维吉尼亚密码
维吉尼亚密码的密码体制
维吉尼亚密码(又译维热纳尔密码)是使用一系列凯撒密码组成密码字母表的加密算法,属于多表密码的一种简单形式。下面给出具体定义。 设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的运算。
那么相应的密文为:vpxzgiaxivw
。
代码
#include<bits/stdc++.h>
using namespace std;
char A[103],B[103];
//在下面Begin和End之间补全代码,对输入的字符串进行维吉尼亚加密
int main()
{
cin>>A;
cin>>B;
/*********** Begin ***********/
// 将密钥串和明文串都转换为小写字母
for(int i=0; A[i]!='\0'; i++){
A[i] = tolower(A[i]);
}
for(int i=0; B[i]!='\0'; i++){
B[i] = tolower(B[i]);
}
int keyLen = strlen(A);
int textLen = strlen(B);
string encryptedText = "";
for(int i=0; i<textLen; i++){
char keyChar = A[i % keyLen]; // 循环使用密钥中的字符
char plainChar = B[i];
// 对明文字符进行移位加密
char encryptedChar = 'a' + (plainChar - 'a' + keyChar - 'a') % 26;
// 将加密后的字符加入到加密串中
encryptedText += encryptedChar;
}
// 输出密文串
cout << encryptedText;
/*********** End ***********/
}