1、基本概念
加法密码和乘法密码结合就构成仿射密码,仿射密码的加密和解密算法是:C= Ek(m)=(k1*m+k2) mod n
加密过程:c=E(p)=(a*p+b)mod26
解密过程:p=D(c)=((c-b)*(a的逆))mod26
M= Dk(c)=k3(c- k2) mod n(其中(k3 ×k1)mod26 = 1)仿射密码具有可逆性的条件是gcd(k1, n)=1。当k1=1时,仿射密码变为加法密码,当k2=0时,仿射密码变为乘法密码。仿射密码中的密钥空间的大小为nφ(n),当n为26字母,φ(n)=12,因此仿射密码的密钥空间为12×26 = 312。仿射密码是一种代换密码。密钥有两个、由0-25的整数数组成,是一种线性代换密码。和凯撒密码都是代换密码!
2、加密例子
例如我们想对字符串"test"进行加密,首先我们将字符串"test"拆分为单个字符.字符加密算法如下:
以上函数plaintext表示明文,ciphertext表示密文,a,b代表密钥对、取值范围为0-25,在仿射密码中要求a 和26的最大公约数为1 也就是a和26是互素的,如果不能保证其互素性则不能保证能够正确解密。通过以上代码对字符串“test”加密得到的结果是"gfzg”
。在此之前需要检查a和26是否互素。
以下代码判断两个数是否互素
:
int encryption(char * plaintext,char *ciphertext,int a,int b){
int strLength = strlen(plaintext);
int i=0;
for(;i<strLength;i++){
if(plaintext[i]==' '){
ciphertext[i]=plaintext[i];
}
else{
ciphertext[i] = ((plaintext[i]-'a')*a+b)%26+'a';
}
}
ciphertext[i]='\0';
return 0;
}
int Stein_GCD(int x, int y) //求最大公约数
{
if (x == 0) return y;
if (y == 0) return x;
if (x % 2 == 0 && y % 2 == 0)
return 2 * Stein_GCD(x >> 1, y >> 1);
else if (x % 2 == 0)
return Stein_GCD(x >> 1, y);
else if (y % 2 == 0)
return Stein_GCD(x, y >> 1);
else
return Stein_GCD(min(x, y), fabs((double)x-y));
}
3、解密例子
通过以上方法将字符串"test"进行加密得到的结果为"gfzg",使用以下方法对其进行解密得到明文字符串"test",以下为解密代码:
int decryption(char *ciphertext,char * plaintext,int a,int b){
int strLength = strlen(ciphertext);
int i=0;
int num=0;
for(i=0;i<strLength;i++){
if(ciphertext[i]==' '){
plaintext[i]=ciphertext[i];
}
else{
if((((ciphertext[i]-'a')-b)*IntegerInverse(a))<0){
num=26-abs((((ciphertext[i]-'a')-b)*IntegerInverse(a)))%26;
plaintext[i] = num+'a';
}else{
plaintext[i] = (((ciphertext[i]-'a')-b)*IntegerInverse(a))%26+'a';
}
}
}
plaintext[i]='\0';
return 0;
}
参数表示的含义和加密过程中表示的含义相同。在解密事用到a的逆,以下代码实现求a的模26的逆运算。
int IntegerInverse(int num){ //求一个数的模26的逆
for(int i=0;i<MAX;i++){
if((i*num)%26==1){
return i;
}
}
return -1;
}
4、加解密演示
5、完整代码
#include <iostream>
#include "math.h"
#include "string.h"
#define MAX 10000
using namespace std;
int Stein_GCD(int x, int y) //求最大公约数
{
if (x == 0) return y;
if (y == 0) return x;
if (x % 2 == 0 && y % 2 == 0)
return 2 * Stein_GCD(x >> 1, y >> 1);
else if (x % 2 == 0)
return Stein_GCD(x >> 1, y);
else if (y % 2 == 0)
return Stein_GCD(x, y >> 1);
else
return Stein_GCD(min(x, y), fabs((double)x-y));
}
int IntegerInverse(int num){ //求一个数的模26的逆
for(int i=0;i<MAX;i++){
if((i*num)%26==1){
return i;
}
}
return -1;
}
int encryption(char * plaintext,char *ciphertext,int a,int b){
int strLength = strlen(plaintext);
int i=0;
for(;i<strLength;i++){
if(plaintext[i]==' '){
ciphertext[i]=plaintext[i];
}
else{
ciphertext[i] = ((plaintext[i]-'a')*a+b)%26+'a';
}
}
ciphertext[i]='\0';
return 0;
}
int decryption(char *ciphertext,char * plaintext,int a,int b){
int strLength = strlen(ciphertext);
int i=0;
int num=0;
for(i=0;i<strLength;i++){
if(ciphertext[i]==' '){
plaintext[i]=ciphertext[i];
}
else{
if((((ciphertext[i]-'a')-b)*IntegerInverse(a))<0){
num=26-abs((((ciphertext[i]-'a')-b)*IntegerInverse(a)))%26;
plaintext[i] = num+'a';
}else{
plaintext[i] = (((ciphertext[i]-'a')-b)*IntegerInverse(a))%26+'a';
}
}
}
plaintext[i]='\0';
return 0;
}
int main()
{
int a,b;
char *plainText=new char(100);
char *ciphertext=new char(100);
cout<<"请输入密钥对:"<<endl;
cin>>a>>b;
if(Stein_GCD(a,26)==1){
cout<<"请输入明文"<<endl;
getchar();
gets(plainText); //输入了明文
encryption(plainText,ciphertext,a,b);
cout<<"加密得到的密文为:"<<ciphertext<<endl;
decryption(ciphertext,plainText,a,b);
cout<<"解密得到的明文为:"<<plainText<<endl;
}else{
cout<<"无法进行加密操作"<<endl;
}
getchar();
getchar();
return 0;
}