仿射变换的加密解密分别是:
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;
}