现代密码学实验报告1——仿射密码加、解密算法实现C语⾔
实验地点:E楼III区503 实验时间:2018.11.10
⼀、实验室名称:攻防实验室
⼆、实验项⽬名称:仿射密码算法实现
三、实验学时:2 学时
四、实验原理:
仿射变换:
加密:
解密:
其中a, b为密钥,,且gcd(a, 26)=1
五、实验⽬的:
1、熟悉仿射密码算法;
2、理解明⽂(plaintext)、密⽂(ciphertext)、加密密钥(encryption key)、解密密钥(decryption key)、加密算法(encryption algorithm)、解密算法(decryption algorithm)。
六、实验内容:
1)⽤VC++\Python等语⾔实现仿射变换加/解密算法;
2)加/解密程序对任意满⾜条件的a、b都能够处理。
七、实验器材(设备、元器件):
学⽣每⼈⼀台PC,安装Windows 7操作系统及VC++\Python开发环境。
⼋、实验步骤:
1.参数选取与密钥⽣成
参数就是a与b,也就是本次实验中的密钥。密钥的选取是随机⽣成的,这⾥使⽤ srand(time(0))来重置随机数种⼦,以当前时间为参数,这样可以使每次使⽤该仿射密码加密时都可以有不同的密钥对,实现⼀次⼀密。
同时,随机⽣成的a、b需要满⾜,且gcd(a, 26)=1的条件。这⾥的26是因为有26个字母,每个字母对应⼀个数值,⼀共有26个数值。当a=1时,仿射密码变为加法密码,当a=0时,仿射密码变为乘法密码。
srand(time(0));
do{
a=rand()%26;
}while(gcd(a,26)!=1||a==0||a==1);    //随机⽣成符合条件的密钥a
do{
b=rand()%26;
}while(b==0);                    //随机⽣成符合条件的密钥b
在这⾥,涉及到gcd()这个⼦函数,这是个求最⼤公因数的⼦函数,在这⾥使⽤是为了判断a与26是否互素。
2. 加密
加密的公式是,m[]是明⽂序列。以下⼦函数是加密函数,加密算法部分。其中,m[]字符串在主函数中从⽂件中读⼊,a,b在主函数中⽣成。
int length,j=0;
FILE *fp3;
length = strlen(m);
printf("Encrypted :\n");
for(j=0;j<length-1;j++)
{
if(m[j]>64&&m[j]<91)            //区分明⽂的⼤⼩写
c[j]=(a*(m[j]-65)+b)%26 +65;      //对⼤写字母进⾏加密
else
c[j]=(a*(m[j]-97)+b)%26 +97;      //对⼩写字母进⾏加密
printf("%c",c[j]);              //输出密⽂
}
fp3=fopen("","w");    //将密⽂存储在 中,便于后续解密
int i=0;
for(i=0;i<length-1;i++)
{
fprintf(fp3,"%c",c[i]);
}
printf("\n");
}
由于输⼊的明⽂字符串可能存在⼤⼩写都有,⽽我们这⾥仅接受26个字符,所以我们需要把⼤写改成⼩写或者把⼩写改成⼤写,让⼤⼩写在数值上是保持⼀致,这是我刚开始的想法,即将所有⼤写字符转化成⼩写字母,然后再进⾏运算加密,加密后⽆论明⽂⼤⼩写,密⽂统⼀为⼩写字母。但是这样对于解密算法,需要解密的密⽂就全部为⼩写,这种情况下,解密算法解出的明⽂就⽆法将⼤⼩写区分。也就是如果我们加密前输⼊的明⽂是区分⼤⼩写的⼀串字符,在经过仿射密码的加密和解密后,就会统⼀为⼤写或⼩写。
为了解决这个问题,在加密时,我对⼤⼩写进⾏了区分,通过使⽤if语句对m[j]值的范围进⾏判断,对⼤写字母和⼩写字母分别进⾏加密,如果m[j]>64&&m[j]<91,即⼤写字母进⾏加密, c[j]=(a*(m[j]-65)+b)%26 +65,否则是对⼩写字母进⾏加密,c[j]=(a*(m[j]-
97)+b)%26 +97。⼤⼩写加密的区别在于这26个连续的字符中最⼩的是以“A”还是“a”开始。
对于加密后的密⽂,我不仅让它在命令⾏中显⽰,还将密⽂储存在另⼀个⽂本⽂件中,这样
有助于后续的解密⼯作。
明解c语言3. 解密
我在主函数中设置了⼀个switch语句,运⾏后会先问“e or d?”,此时,输⼊e,进⼊加密部分,如上⽂加密部分所述,⽽输⼊d则进⼊解密部分。我设置这样⼀个选择是考虑到这个程序的实⽤性,这个选择可以让解密独⽴使⽤。如果我们拿到的是⼀段密⽂,只要知道密钥就可以直接进⼊解密流程。选择解密后,会提⽰输⼊密钥,这也是为了让解密与加密独⽴开使⽤⽽设置的,⾃主输⼊,⽽不是直接将之前⽣成的a、b搬下来使⽤。当然,如果本次解密的密⽂就是使⽤此程序加密⽽得到的,那要记住刚刚随机⽣成的a、b密钥。
解密公式:,其中,c[]是密⽂,默认从加密程序产⽣的⽂件中读⼊,a、b 是随机密钥。
int length;
length = strlen(c);
printf("Decrypted :\n");
for(int j=0;j<length-1;j++){
if(c[j]>64&&c[j]<91) {              //对⼤写密⽂进⾏解密
m[j]=(NI(a)*((c[j]-65)-b))%26+65;  //解密算法 m[i]=a逆*(c[i]-b)mod 26
if(NI(a)*((c[j]-65)-b)<0){      //修正 NI(a)*((c[j]-65)-b)结果为负数的情况
m[j]=m[j]+26;
}
}
else{                    //对⼩写密⽂进⾏解密
m[j]=(NI(a)*((c[j]-97)-b))%26+97;  //解密算法 m[i]=a逆*(c[i]-b)mod 26
if(NI(a)*((c[j]-97)-b)<0){      //修正 NI(a)*((c[j]-97)-b)结果为负数的情况
m[j]=m[j]+26;
}
}
printf("%c",m[j]);          //输出解密后的明⽂
}
printf("\n");
}
其中涉及到⼦函数NI(),它的功能是求⼀个数mod26下的逆。解密过程,和加密类似也是对密⽂进⾏⼤⼩写区分解密。在调试过程中,我发现NI(a)((c[j]-97)-b)可能存在⼩于0的时候,这种情况是⽆法正确解密的,所以需要使⽤if函数,在NI(a)((c[j]-97)-b)<0的时,将NI(a)* ((c[j]-97)-b)+26,直到变成正数,这个过程与m[j]+26得到的结果相同,可以⽤m[j]=m[j]+26代替。同样,对于⼤写字母也有类似的操作。
九、实验数据及结果分析:
(1)实验参考代码:
完整代码请移步资源区下载
(2) 加密及解密实例结果截图:
加密:
明⽂:
选择“e”(加密),⽣成随机密钥并加密。
解密:
选择“d”(解密),输⼊密钥,解密。
⼗、实验结论:
熟悉仿射密码算法并⽤C语⾔实现了仿射密码的加密和解密过程,理解明⽂、密⽂、加密密钥、解密密钥的概念与它们之间的逻辑关系,对仿射密码的加密算法、解密算法有了较之前不⼀样的理解。完成了⼀个具有实⽤性的仿射密码加密与解密程序。
⼗⼀、总结及⼼得体会:
这次实验让我熟悉了仿射密码算法的原理,⼀点点分析算法,⼀步步去理清逻辑。通过使⽤C语⾔去将加密算法与解密算法逐步实现,去思考每⼀条公式和每⼀个循环嵌套,也让我对使⽤C语⾔处理问题增加了信⼼,同时在实践中也得到了⼀些处理问题的经验。当⼤体的框架实现后,我⼜对这个程序进⾏美化与完善,列如对加密与解密的选择,来让解密更具有实⽤性,能够应对多种情况。列如将加密后的密⽂输出到⽂本⽂件中,⽽解密时直接打开⽂件进⾏解密,让程序更加流畅。列如区分⼤⼩写的加密和解密过程,来还原最初⽂件的字符串。这些东西看似没有什么特别关键的作⽤,但是在对程序完善的过程中我也学到了很多。
⼗⼆、对本实验过程及⽅法、⼿段的改进建议:
本次实验主要是将加密算法和解密算法分别使⽤两个⼦函数实现,在主函数中,先使⽤switch语句选择加密或解密⼯作,在加密中,随机⽣成加密密钥,从⽂本⽂件中读⼊明⽂字符串,调⽤加密⼦函数进⾏加密,加密后的密⽂输出并存储在⽂本⽂件中。在解密中,⼿动输⼊解密秘钥,读⼊密⽂字符串,调⽤解密⼦函数进⾏解密并输出解密所得明⽂。
这是本次实验的基本逻辑,最终实现的代码与刚开始写成的代码已经有了很⼤的改进,但是仍然是不完美的,最明显的⼀点就是有些繁琐,尤其是⼤⼩写是否真的有必要区分,后来我⼜想解密者不会因为⼀个字母⼤⼩写不分就不认识这个字母了,区分⼤⼩写会让代码更加繁琐。
报告评分:
指导教师签字:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。