仿射变换的加密解密分别是:

c = Ea,b(m)  ≡ a, + b(mod 26)

m = Da,b(c) ≡ a^-1(c - b)(mod 26)

其中,a,b是密钥,为满足0≤a,b≤25和gcd(a,26)等于1的整数。

其中gcd(a,26)表示a和26的最大公因子,gcd(a,26)=1表示a和26是

互素的,a^-1表示a的逆元,即a^-1*a ≡ 1mod26。


解析:

加密过程较为容易

加密算法:c = a*m + b(mod n)
加密过程:
1,获取a,b,n;(若未知)
2,获取明文字符串;
3,
1,将每一个明文字符转换成对应的数字;
2,将明文数字带入公式c = a*m + b(mod n),获取密文对应数字;
3,将密文数字转换成对应的密文字符。

解密过程是是其中难点。

解密算法:m = a^-1(m - b) (mod n)(注:a^用_a表示)

解密过程:

1, 获取a, b,n;(若未知)
2,获取密文字符串;(若未知)
3
1,设置数组coprime为存放与n互素的元素
2,获取value1,value2的最大公约数
3,在coprime中寻找a的模n可逆元_a
4, 1,将每一个 密文字符转换成对应的数字;
2,将密文数字带入公式m = a^-1(m - b) (mod n),获取明文对应数字;
3,将明文数字转换成对应的明文字符。

下面附上源码

main函数

#include <stdio.h>
#include <assert.h>

#define N 26 //仿射变换默认模数为26
 
//加密算法
char *encode(char *c_str, int a, int b, int n);
//解密算法
char *decode(char *m_str, int a, int b, int n);

//设置数组coprime为存放与n互素的元素
void setCoprime(int coprime[], int n);
//获取value1,value2的最大公约数
int getGcd(int value1, int value2);
//在coprime中寻找a的模n可逆元_a
int get_a(int coprime[], int a, int n);

int main()
{	
	int a = 0;
	int b = 0;

	//str存储明文
	char str[128] = "";

	printf("输入a, b的值\n");
	scanf("%d %d", &a, &b);

	getchar(); //抵消换行符的干扰

	printf("输入str的内容\n");
	gets(str); //注意输入大写字母字符串

	//输出明文
	printf("明文:%s\n", str);

	//加密
	encode(str, a, b, N);

	//检验是否加密成功
	printf("密文:%s\n", str);

	//解密
	decode(str, a, b, N);

	//检验是否解密成功
	printf("明文:%s\n", str);

	return 0;
}



加密函数encode()

//加密算法
char *encode(char *c_str, int a, int b, int n)
{
	char *p_str = c_str; //减小副作用
	assert (c_str);  //判断明文字符串c_str是否为NULL
	
	while (*c_str)
	{
	if (' ' == *c_str)	//遇到空格就跳过
		{
			++c_str;
			continue;
		}

		if ((*c_str < 'A') || (*c_str > 'Z')) //不是‘A’到‘Z’之间的就中断
			assert(0);
		
		*c_str -= 'A';	//将字符转化为对应数字
		*c_str = (a*(*c_str) + b)%n;//加密核心算法
		*c_str += 'A';	//将数字转化为字符

		++c_str;
	}

	return p_str;
}


解密函数decode()

//解密算法
char *decode(char *m_str, int a, int b, int n)
{
	char *p_str = m_str; //减小副作用
	int coprime[32] = {0}; //存放小于n并且与n互素的元素
	int _a = 0; //存放a的模n可逆元
	int i = 0; //迭代因子

	assert (m_str);  //判断密文字符串m_str是否为NULL

	for (; i < 32; i++)  //将数组元素赋为0
		coprime[i] = 0;

	setCoprime(coprime, n);//设置数组coprime存放与n互素的元素

	_a = get_a(coprime, a, n);//在coprime中寻找a的逆元_a

	
	while (*m_str)
	{
		if (' ' == *m_str)  //遇到空格就跳过
		{
			++m_str;
			continue;
		}

		if ((*m_str < 'A') || (*m_str > 'Z')) //不是‘A’到‘Z’之间的就中断
			assert(0);
		*m_str -= 'A';	//将字符转化为对应数字
		*m_str = (_a*(*m_str - b + n))%n;//解密核心算法
		*m_str += 'A';	//将数字转化为字符

		++m_str;
	}

	return p_str;
}


设置数组coprime内容

//设置数组coprime存放与n互素的元素
void setCoprime(int coprime[], int n)
{
	int i = 1;

	for (; i < n; i++)
		if (1 == getGcd(n, i))//判断是否n,i是否互素
			*(coprime++) = i; //将i存入coprime中
}


获取两数最大公约数getGcd()

//获取value1和value2的最大公约数
int getGcd(int value1, int value2)
{
	int gcd = 0; //最大公约数
	int divisor = 0; //余数
	
	do	//辗转相除法
	{	
		divisor = value1 % value2;

		gcd = value2;

		value1 = value2;
		value2 = divisor;

	}while(divisor);

	return gcd;}

获取可逆元_a

//在数组coprime中寻找a的模n可逆元
int get_a(int coprime[], int a, int n)
{
	int i = 0;

	for (; coprime[i] != 0; i++)
		if (1 == (a*coprime[i])%n)
			return coprime[i];

	return 0;
}