仿射密码过程实验

本文介绍了仿射密码的历史、工作原理及其在现代密码学中的地位,重点讨论了其优点(如简单、速度快)和缺点(安全性低)。实验部分详细描述了如何使用C语言实现仿射密码加密,并探讨了如何扩展到支持更多字符和求逆元的问题。
摘要由CSDN通过智能技术生成
        仿射密码是一种古典密码,它是通过对明文中的每个字符进行数学变换来加密消息的。这种加密方法最初被使用于古罗马时期,凯撒密码就是一种简单的仿射密码。在现代密码学中,仿射密码已经不再被视为安全的加密方法,因为它容易受到各种攻击,如频率分析攻击和线性密码分析攻击。然而,仿射密码仍然具有教育意义,可以帮助初学者了解密码学的基本概念和技术。

优点:
仿射密码简单易懂,容易实现和使用。

加密速度快,因为使用的是基本的算术运算。

支持多种语言,包括中文、英文等。

提供了一定程度的安全保障,可以用于一些低级别的加密需求。

缺点:
安全性较低,容易受到暴力破解和频率分析等攻击。

密钥空间较小,只有 2626种可能的密钥。

容易受到已知明文攻击。

不支持数字和标点符号等特殊字符的加密。

总体而言,由于仿射密码的安全性相对较弱,因此在现代加密技术中很少被使用。
一、实验目的

  通过实现简单的古典密码算法,理解密码学的相关概念,如明文、密文、加 密密钥、解密密钥、加密算法、解密算法、流密码与分组密码等。

二、实验要求

(1)只有一个加密器,解密使用加密器实现;

(2)随机生成密钥;

(3)扩展欧几里得算法计算逆元;

4)文件读写明密文;

 

 

三、实验原理

        加密:在这里插入图片描述
        解密:在这里插入图片描述
        其中a, b为密钥,在这里插入图片描述,且gcd(a, 26)=1

       本程序还要求a≠0或1,当a=1时,仿射密码变为加法密码,当a=0时,仿射密码变为乘法密码。
四、实验过程:
        1.参数随机选取生成密钥:

void key(int *a, int *b) {
	srand(time(NULL));
	//随机种子生成-->time得到每次程序运行的时间,每一次运行程序的时间是不同的
	//实现一次一密
	int x, y;
	do {
		*a = rand() % N;
	} while (gcd(*a, N, &x, &y) != 1 || *a == 1 || *a == 0);
	do {
		*b = rand() % N;
	} while (*b == 0);
	printf("a=%d,b=%d\n", *a, *b);
}

        2.欧几里得算法求最大公约数——验证正确性

        若a与p互素,则满足( a × x ) m o d p = 1 (a\times x) mod p=1(a×x)modp=1的x为a的逆元。

int gcd(int a, int b, int *x, int *y) {
	if (b == 0) {
		*x = 1;
		*y = 0;
		return a;
	}
	int d = gcd(b, a % b, y, x);
	*y -= a / b * (*x);
	return d;
}

        3.文本文件相关函数——读取写入文件:

        需了解C语言文本文件读取相关函数:文本文件是指以ASCII码方式(也称文本方式)存储的文件,更确切地说,英文、数字等字符存储的是ASCII码,而汉字存储的是机内码

        引入头文件:#include<stdio.h>

        打开文件fopen函数:返回指针类型

FILE *fopen(char *filename, *type);

         常见type有:

"r"	打开一个用于读取的文件。该文件必须存在。
"w"	创建一个用于写入的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。
"a"	追加到一个文件。写操作向文件末尾追加数据。如果文件不存在,则创建文件。
"r+"打开一个用于更新的文件,可读取也可写入。该文件必须存在。
"w+"创建一个用于读写的空文件。
"a+"打开一个用于读取和追加的文件。

        读取文件 fread 函数:

fread( void *buffer, filesize, size_t count, FILE *stream );

         关闭文件fclose函数:

fclose(fp);//fp是文本地址 FILE *fp

        文件写入:最后一定要关闭文件,否则内容可能会丢失

fopen("text.txt","w");//覆盖式写入
int fputs( const char *str, FILE *stream );

        指针定位fseek 函数:

int fseek( FILE *stream, long offset, int origin );
origin
原始值含义
SEEK_CUR文件指针的当前位置
SEEK_END文件结尾
SEEK_SET文件开头

        获取当前指针位置相对于文件首地址的偏移字节数ftell()函数:用于计算文件大小

long ftell(FILE *stream);

 ……(参考C语言 文本文件读取、写入与定位(详细介绍)_c语言写入文件_Gretel Tade的博客-CSDN博客

char *readfile(const char *fname) {
	FILE *file = fopen(fname, "r");//读取文件
	if (file == NULL) {
		return NULL;
	}

	fseek(file, 0, SEEK_END);//将指针移到文件末尾
	long fsize = ftell(file);//获取当前偏移字节从而获得文件大小
	fseek(file, 0, SEEK_SET);//将指针移回文件开头

	char *s = (char *) malloc(fsize + 1);
	if (s == NULL) {
		fclose(file);
		return NULL;
	}

	if (fread(s, fsize, 1, file) != 1) {//读取文件
		free(s);
		fclose(file);
		return NULL;
	}

	s[fsize] = '\0';//加入读取终止标识符
	fclose(file);
	return s;
}

4.加密函数:

char *encrypt(int a, const char *fname, int b) {
	char *s = readfile(fname);
	printf("明文为:%s\n", s); // 打印文件内容
	char *encrypted = (char *)malloc(strlen(s) + 1);//动态分配内存空间,使用完一定要释放
	if (encrypted == NULL) {
		free(s);
		return NULL;
	}
	int len = strlen(s);
	printf("Lenth:%d\n", len);
	int i, z = 0;
	//将大小写字母分别加密
	for (i = 0; i < len; i++) {
		if (s[i] >= 'A' && s[i] <= 'Z') {
			s[z] = (a * (s[i] - 'A') + b) % 26 + 'A';
		} else if (s[i] >= 'a' && s[i] <= 'z') {
			s[z] = (a * (s[i] - 'a') + b) % 26 + 'a';
		} else {
			s[z] = s[i];//特殊字符原样输出
		}
		z++;
	}
	s[z] = '\0'; // 添加终止字符
	//输出密文
	printf("密文为:%s\n", s);
	return s;
}

5.扩展欧几里得算法——求取逆元

int epgcd(int a) {
	int x, y;
	int d = gcd(a, N, &x, &y);
	if (d != 1) {
		return -1; // a 和 m 不互质,无法求逆元
	}
	return (x % N + N) % N;
}

 (未解决)问题3:输出中文乱码。

(未解决)(1)改进将仿射密码定义在 Z29上,明密文空间除 26 个英文字母还包括空格、句号和 引号。这个方案与传统定义在 Z26上的仿射密码相比有何优点?如果要实现此方案,你的程 序应该如何进行调整?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值