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