密码学--仿射密码

发布于:2025-05-13 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、实验目的

  1、通过实现简单的古典密码算法,理解密码学的相关概念

  2、理解明文、密文、加密密钥、解密密钥、加密算法、解密算法、流密码与分组密码等。

二、实验内容

1、题目内容描述

随机生成加密密钥并验证密钥的可行性

plain文件读入待加密明文

进行仿射密码加密

④将加密后得到的密文放入cipher文件

根据加密密钥计算解密密钥

进行解密运算

⑦将解密后的文本放入plain_decrypted文件,与明文进行对比

2、关键代码的设计、实现与执行

设计思路:

先以时间产生随机数作为加密密钥a,b,但是这里要通过求最大公因数的方式来验证加密密钥a的可行性,即密钥a和N的最大公因数为1,即a,N互质(其中N为定义在Zn上的N):

下面代码是运用Euclid算法计算最大公因数的关键代码:

while(b!=0)//此处的b是N,也就是此实验的26,

{

temp=a%b;//得到的余数部分

a=b;//b做被模数

b=temp;//得到的余数做模数

}

return a;//求得的最大公因数

下面代码是随机生成密钥a,并通过调用最大公因数的函数验证密钥a可行性的关键代码部分:
while(gcd(a,N)!=1)//循环判断密钥a的可行性

{

srand(time(NULL));//以时间随机生成种子

a=rand()%N; //a随机生成,b也以同样的方式生成,但是不用判断可行性,只需进行一次随机生成

}

得到加密密钥后,从文件读入已经准备好的加密明文也可通过记事本修改),下面代码是以读的方式打开文件,并判断是否在文件夹中存在命名的文件的关键代码部分:

 FILE *plain_file = fopen("plain.txt", "r");//以读的方式打开

    if (plain_file == NULL) {

        printf("无法打开明文文件!\n");//判断无法打开给出提示

        exit(1);//无法打开只能以异常终止结束运行

}

其中分析明文中的大小写字母,大写字母的ASCII码是从65到90,小写字母的ASCII码是从97到122,如实符号则不进行加密解密,直接返回,对字母利用放射加密y=ax+b mod q进行加密,下面代码是根据ASCII码将大小写代码转换,并进行加密的关键代码部分:

if(ch>='a'&&ch<='z')//ascii码转换,ch>=97&&ch<=122

{

ch-=97;

}

else if(ch>='A'&&ch<='Z')//ascii码转换,ch>=65&&ch<=90

{

ch-=65;

}

else

return ch;//如果是字符就直接跳过加密解密部分

return (ch*a+b)%N+97;//最后解密后的文件得到写的字母

在得到加密后的密文后放入密文cipher文件,关键代码部分如下:

while ((ch = fgetc(plain_file)) != EOF) {

     cipher_text=(char)encrypt(ch,a,b);  //加密后直接将返回的密文放入文件中        

            fputc(cipher_text, cipher_file);

运用扩展Euclid算法求逆元a1,就可以得到解密密钥a模N的逆元a1,以及密钥c=b*a1

下面代码是运用扩展Euclid算法求a的逆元a1的关键代码部分:

while(b!=0) {//此处最开始的b也是N,就是此实验的26

int r = a%b;

int q = (a-r)/b;

int x2 = x0-x1*q;

int y2 = y0-y1*q;

a=b;

b=r;

x0=x1;

y0=y1;

x1=x2;

y1=y2;

}//当b==0时,判断是否a2>b2,若是,逆元应该是y0,若不是逆元应该是x0

最后对密文进行解密,步骤基本一样,只是密钥变成了a1和c。

最后将解密得到的文本放入plain_decrypted文件中,关键代码部分如下:

while ((ch = fgetc(cipher_file)) != EOF)

{

     plain_text = (char)encrypt(ch,a1,c);

     fputc(plain_text, plain_file);

    }

实验结果截图:

  1. 实验结果分析

首先测试结果可见上图,可以看到对明文的加密结果以及对密文的解密结果,解密结果和明文是一致的,证明中间算法没有问题,然后在运行中也给了相关信息,如加密密钥和解密密钥以及文件命名等,且在明文中可以任意输入大小写字母,最后统一为小写字母,即最后return时加上97,结果如下:

当然也可以不统一为小写,或者统一为大写字母,只需要在加密encrypt函数处分类返回就行,也就是在小写字母处返回多加97,在大写字母处返回多加65,此处只是为了好看。

也可同一为大写字母如下,且有符号位:

对密文的解密也可以不统一为大写或小写,只需要各自return就行,得到结果如下:

特别的是关于符号以及空格等处理,并未对它们进行处理,而是相应的直接返回原始值,不对它们进行任何加密解密操作。

三、实验思考

1、实验过程总结

在刚开始进行编写程序的时候,由于基础理论知识不扎实,误将加密密钥直接代入解密式子中进行计算,一直出错,后来发现并及时解决了。特别是在符号及空位等的处理方式上,最开始是直接在代码中列出了常见符号的ASCII码,把它们从明文中单独提出来,然后不对它们进行加密解密操作,后来仔细看了实验视频,才发现直接用一个else就可以直接避免对所有的字符进行加密解密。

通过此次实验使我加深了对仿射密码的理解,也更清晰仿射密码加密解密每一步的原理,也加强了我自己的代码能力。

2、回答实验指导书最后提出的问题

改进将仿射密码定义在Z29上,明密文空间除26个英文字母还包括空格、句号和引号。

这个方案与传统定义在Z26上的仿射密码相比有何优点?

如果要实现此方案,你的程序应该如何进行调整?

相对引用Z(26)的仿射密码Z(29)的仿射密码覆盖的范围更广范围更广也就意味着有着更大的加密范围,意味着算法的安全性更高

②首先要将宏定义的N改为29,然后加/解密过程对多出来的三个特殊符号进行单独的加/解密。


网站公告

今日签到

点亮在社区的每一天
去签到