仿射加密加解密算法

概述:基本上和数学上的仿射变换类似
y=ax+b,通过如此达到一一对应加密。


仿射变换加密加密过程:
加密算法:c=a*m+ b(mod n)

加密过程:
1.获取a,b(密钥),n(字符个数)

2.获取明文。
3.加密成密文,明文转换成各个字符所对应的数字,将所得数字带入上面的算法公式,得到数字再转换成对应的字符

解密过程:
算法:m=a^-1(m-b)(mod n)这里a^-1不是指倒数,而是a关于字符数量模的乘法可逆元,下面介绍一下乘法可逆元

乘法可逆元定义;
群G中任意一个元素a,都在G中有唯一的逆元a‘,具有性质aa'=a'a=e,其中e为群的单位元
这个官方的定义不学数论什么肯定看不太懂。。没事我们只研究数学应用,不学理论,

举个例子好了:
4关于模7的乘法逆元为多少?

可令4X≡1mod7,即可等价于4X=7K+1,其中X,K为整数,求X和K。
由此看出可逆元的通俗定义

如果ax≡1modf,那么a为关于模f的乘法逆元。
另外也有条件,当a与f互素时,a关于模f的乘法逆元有解。如果不互素,则无解。如果f为素数,则从1到f-1的任意数都与f互素,即在1到f-1之间都恰好有一个关于模f的乘法逆元。

再来一个更具体的例子,
求5关于14的乘法逆元

用辗转相除法
14=5*2+4

5=4*1+1
反过来写
1=5-4=5-(14-5*2)=5*3-14

因此5关于模14的乘法逆元为3.
如此即可求出逆元,然后再带入公式即可实现解密。

下面给出仿射加密算法的算法实现。(直观起见采用C++)


#include<iostream>
using namespace std;
#define N 26  //这里只采用26个字母的加解密

//加密
char *encry(char *Plain, int a, int b, int n);
char *decry(char *Cipher, int a, int b, int n);
//获取可行仿射加密的a值数组
void setArr(int Canuse[], int n);
//求GCD(最大公约数)
int Gcd(int a, int b);
//求a关于模n的乘法可逆元
int Multiplicative_inverse_modulo(int Canuse[], int a, int n);
int main() {
	int a, b;
	char str[200] = "";
	cout << ("输入密钥a,b的值") << endl;
	cin >> a >> b;
	cout << "输入明文内容" << endl;
	cin >> str;
	cout << "明文为" << endl;
	cout << str << endl;
	//加密
	encry(str, a, b, N);
	//输出密文
	cout << str << endl;
	//解密
	decry(str, a, b, N);
	//输出解密内容
	cout << str << endl;
	return 0;
}
//加密函数实现
char *encry(char *Plain, int a, int b, int n)
{
	char *tmp = Plain;
	if (Plain == NULL)return NULL;
	while (*Plain) {
		if (' ' == *Plain)
		{
			++Plain;
			continue;
		}
		if ((*Plain < 'A') || (*Plain > 'Z'))
			return NULL;
		*Plain -= 'A';
		*Plain = (a*(*Plain) + b) % n;
		*Plain += 'A';
		++Plain;
	}
	return tmp;
}
//解密所需基础算法实现
void setArr(int Canuse[], int n) {
	for (int i = 1; i < n; i++) {
		if (1 == Gcd(n, i))
			*(Canuse++) = i;
	}
}
int Gcd(int a, int b) {
	int gcd = 0;
	int div = 0;
	//辗转相除法
	do {
		div = a%b;
		gcd = b;
		a = b;
		b = div;
	} while (div);
	return gcd;
}
//求乘法可逆元
int Multiplicative_inverse_modulo(int Canuse[], int a, int n) {
	for (int i = 0; Canuse[i] != 0; i++) {
		if (1 == (a*Canuse[i]) % n)
			return Canuse[i];
	}
	return 0;
}
//解密实现
char *decry(char *Cipher, int a, int b, int n) {
	char *tmp = Cipher;
	int Canuse[32] = { 0 };//符合条件的a值
	int moda = 0;//a的乘法可逆元
	int i = 0;
	if (Cipher == NULL)return NULL;
	for (; i < 32; i++)Canuse[i] = 0;
	setArr(Canuse, n);//存放符合条件的a.
	moda = Multiplicative_inverse_modulo(Canuse, a, n);
	while (*Cipher) {
		if (' ' == *Cipher) {
			++Cipher;
			continue;
		}
		if ((*Cipher < 'A') || (*Cipher > 'Z'))
			return NULL;
		*Cipher -= 'A';
		*Cipher = (moda*(*Cipher - b + n)) % n;
		*Cipher += 'A';
		++Cipher;
	}
	return tmp;
}
只恨数学学的不够多啊。

猜你喜欢

转载自blog.csdn.net/tatebrwonjava/article/details/79769425