C/C++ 实现基于背包算法的加解密(带摘要算法)

密码学的期末大作业:基于一种数学难题,实现对信息的加密与解密,并采用一种摘要算法生成摘要,并对摘要进行加密

  • 采用的语言为 C/C++

  • 数学难题为 背包算法(详细原理可看:背包算法原理写的很好,容易理解)

  • 摘要算法采用的是MD5(copy的,因为大作业中并未对摘要算法有要求,于是就从简copy了一份)

  • 在对摘要进行加解密时,由于背包问题逆向为数学难题,无法直接反过来,所以采用了一些特殊条件

具体过程为:

基于背包问题,实现了加密解密过程,可对由字母,数字和空格组成的字符串进行加密解密。在此基础上进行了数字签名。采用了MD5 摘要算法,并对摘要进行加密传输,解密后认证相同即为认证成功。
背包利用超递增序列作私钥,加密时通过两个互素数M,N,构造不规则序列公钥,将明晚进行二进制转化后对应求和得到密文。解密时先求出N的逆元后,对密文进行取模,再对照私钥进行解密,最后得到明文。
签名时首先通过MD5算法对明文进行摘要,并用私钥对摘要进行加密。解密时先将解密到的明文进行摘要,再对被私钥加密的摘要进行解密,通过已知公钥,M,N,求出私钥,进行解密。将解密到的摘要与解密明文提取的摘要进行对比,相同即可证明该信息可靠。

代码部分

  1. 初始化部分

通过打表的方式将数字与英文字母进行对应转换,可将其转化为六位二进制数字

string mi[37] = {"000000","000001","000010","000011","000100",
			 	 "000101","000110","000111","001000","001001",
			   	 "001010","001011","001100","001101","001110",
				 "001111","010000","010001","010010","010011",
				 "010100","010101","010110","010111","011000",
				 "011001","011010","011011","011100","011101",
				 "011110","011111","100000","100001","100010",
				 "100011","100100"};

char mm[37] = {' ','a','b','c','d',
			   'e','f','g','h','i',
			   'j','k','l','m','n',
			   'o','p','q','r','s',
			   't','u','v','w','x',
			   'y','z','0','1','2',
			   '3','4','5','6','7',
			   '8','9'};

变量声明:

int A[12] = {1,3,5,11,21,44,87,175,349,701,1399,2798}; //私钥 
int m; //= 5598;
int n; 
int B[12];//公钥 
int sum[3000];//加密后的信息 
int sum1[3000];//加密后的摘要 
int ans[3000];//转换后的信息 
int ans1[3000];//转换后的摘要 
int kk;//加密时分组的个数 
int kkz = 0;//摘要分组的个数 
string ming; //输入的明文 
string zhai,zhai1,zhai2;//摘要 
string zu[3000];//加密分组后的信息 
string zuz[3000];//摘要分组后的信息 
string answer,answer1;//解密后的明文 
string flag[3000];//转换后的串 
string flagz[3000];//转换后的串 

Ready():初始化函数
输出默认给定的私钥

//私钥 
	int sum = 0;
	cout << "私钥为:[ ";
	for(int i=0; i<12; i++){
		sum += A[i];
		cout << A[i] << " ";
		if(i!=11) cout << ",";
	} 
	cout <<" ]"<< endl;
	cout << endl;

生成M
M的要求为:比私钥A中数字的和大

//随机选取m
	srand((int)time(0));
	while(1){
		int h = random(10);
		if(h) {
			m = sum + h;
			break;
		} 	
	}

生成N
N的要求为:与M互为素数

srand((int)time(0));
	while(1){
		int k = random(100);
		if(gcd(m,k)==1 && k != 1){
			n = k;
			break;
		}
	} 
//最大公约数函数 
int gcd(int a ,int b){
    return b==0 ? a : gcd(b, a%b);
}

生成公钥B并输出:
公钥B是由私钥A生成,b=a*n%m

	//生成公钥 
	for(int k=0; k<12; k++){
		B[k] = (A[k]*n)%m;
	}
	cout << "生成的公钥为:[ ";
	for(int i=0; i<12; i++){
		cout << B[i] << " ";
		if(i!=11) cout << ",";
	} 
	cout <<" ]"<< endl;
	cout << endl;
	cout << "随机选取的两个互素数为:" << m << " " << n << endl; 
	cout << endl;

明文的读入:
明文存储在文件1.txt中,通过freopen()读入

	ready();
	
	cout << "请输入要加密的明文:" <
  1. 明文加密部分

函数名称:jiami()

第一部分:将明文转化成为对应六位二进制数
当输入的明文数量为单数时,会自动补零

	int l = ming.length();
	string zu1;
	//int kk = 0;
	for(int k=0; k

第二部分:将对应的二进制数字与公钥相对应
‘1’位的数字相加得到密文,每两个字符为一组,最后生成传输的密文,打印到屏幕上

	for(int i=0; i
  1. 明文解密部分

解密部分默认已知私钥A,M,N

第一部分:求出N的逆元
利用辗转相除法求出N的逆元

int ni(int m,int n){
	int a, q, b[100], my;
	q = 0;
	a = m%n;
	my = m;
	while(a!=0){
		a = m%n;
		b[q] = m/n;
		q++;
		m = n;
		n = a;
	}
	int bb[100], j=2, bbb;
	bb[0]=1;
	bb[1] = b[q-2];
	int nn;
	nn=q-2;
	for(int i=nn; i>0; i--){	
		bb[j] = b[i-1]*bb[j-1] + bb[j-2];
		bbb = bb[j];
		j++;
	}
 	if((q-1)%2==0) return(bbb);
 	else return (my-bbb);
}

第二部分:通过逆元还原密文
将密文的每个值与逆元相乘再模M,再将得到的数字与私钥A相比,还原出六位二进制字符串

//已知私钥A,m,n
	if(sum[0]==0){
		cout << "请先进行加密!" << endl;
	}
	int niyuan = ni(m,n);
	for(int i=0; i=0; j--){
			if(ans[i]>=A[j]){
				flag1 += "1";
				ans[i] = ans[i] - A[j];
			}
			else flag1 += "0";
		}
		reverse(flag1.begin(),flag1.end());
		flag[i] = flag1;
	}

第三部分:将得到的二进制与转换表对应进行转换,得到明文
利用string的翻转函数,截取函数等,注意解密后去除末尾的空格
(由加密时补位的0造成),否则会导致后面的签名,摘要部分出现误差。

	for(int i=0; i
  1. 摘要算法部分

摘要部分采用的算法为MD5算法,详细代码见下面代码部分。

  1. 摘要加密部分

第一部分:与明文加密部分向同,将摘要进行二进制数字转换

	int l = ming.length();
	string zu1;
	
	for(int k=0; k

第二部分:与明文加密类似,但是用的是私钥

	for(int i=0; i
  1. 摘要解密部分

由于背包算法逆过程为数学难题,无法直接反推,所以采取用私钥加密,解密部分默认已知公钥B,M,N,反推回私钥A并进行解密的方法。

第一部分:私钥A进行还原

//已知公钥B,m,n
	answer1 = "";
	int BB[12];
	int niyuan = ni(m,n);
	for(int i=0; i<12; i++){
		BB[i] = B[i]*niyuan % m;
	}

第二部分:将密文与私钥A进行对比还原二进制数字串

for(int i=0; i=0; j--){
			if(sum1[i]>=BB[j]){
				flag1 += "1";
				sum1[i] = sum1[i] - BB[j];
			}
			else flag1 += "0";
		}
		reverse(flag1.begin(),flag1.end());
		flagz[i] = flag1;
	}

第三部分:将二进制数字串与转换表对应,还原出摘要

for(int i=0; i
  1. 主函数

通过调用上面的加解密,签名函数等实现整个项目,并对两个摘要进行对比验证,给出验证结果:

int main(){
	
	ready();
	
	cout << "请输入要加密的明文:" <

运行结果

C/C++ 实现基于背包算法的加解密(带摘要算法)_第1张图片

完整代码

#include 
#include 
#include 
#include 
#include 
#include 
#include
#define random(x) (rand()%x)

using namespace std;

int A[12] = {1,3,5,11,21,44,87,175,349,701,1399,2798}; //私钥 
int m; //= 5598;
int n; 
int B[12];//公钥 
int sum[3000];//加密后的信息 
int sum1[3000];//加密后的摘要 
int ans[3000];//转换后的信息 
int ans1[3000];//转换后的摘要 
int kk;//加密时分组的个数 
int kkz = 0;//摘要分组的个数 
string ming; //输入的明文 
string zhai,zhai1,zhai2;//摘要 
string zu[3000];//加密分组后的信息 
string zuz[3000];//摘要分组后的信息 
string answer,answer1;//解密后的明文 
string flag[3000];//转换后的串 
string flagz[3000];//转换后的串 

string mi[37] = {"000000","000001","000010","000011","000100",
			 	 "000101","000110","000111","001000","001001",
			   	 "001010","001011","001100","001101","001110",
				 "001111","010000","010001","010010","010011",
				 "010100","010101","010110","010111","011000",
				 "011001","011010","011011","011100","011101",
				 "011110","011111","100000","100001","100010",
				 "100011","100100"};

char mm[37] = {' ','a','b','c','d',
			   'e','f','g','h','i',
			   'j','k','l','m','n',
			   'o','p','q','r','s',
			   't','u','v','w','x',
			   'y','z','0','1','2',
			   '3','4','5','6','7',
			   '8','9'};
			  		   

//最大公约数函数 
int gcd(int a ,int b){
    return b==0 ? a : gcd(b, a%b);
}

//辗转相除法求逆元 
int ni(int m,int n){
	int a, q, b[100], my;
	q = 0;
	a = m%n;
	my = m;
	while(a!=0){
		a = m%n;
		b[q] = m/n;
		q++;
		m = n;
		n = a;
	}
	int bb[100], j=2, bbb;
	bb[0]=1;
	bb[1] = b[q-2];
	int nn;
	nn=q-2;
	for(int i=nn; i>0; i--){	
		bb[j] = b[i-1]*bb[j-1] + bb[j-2];
		bbb = bb[j];
		j++;
	}
 	if((q-1)%2==0) return(bbb);
 	else return (my-bbb);
}

void ready(){
	
	//私钥 
	int sum = 0;
	cout << "私钥为:[ ";
	for(int i=0; i<12; i++){
		sum += A[i];
		cout << A[i] << " ";
		if(i!=11) cout << ",";
	} 
	cout <<" ]"<< endl;
	cout << endl;
	
	//随机选取m
	srand((int)time(0));
	while(1){
		int h = random(10);
		if(h) {
			m = sum + h;
			break;
		} 	
	}
	srand((int)time(0));
	while(1){
		int k = random(100);
		if(gcd(m,k)==1 && k != 1){
			n = k;
			break;
		}
	} 
	
	
	//生成公钥 
	for(int k=0; k<12; k++){
		B[k] = (A[k]*n)%m;
	}
	cout << "生成的公钥为:[ ";
	for(int i=0; i<12; i++){
		cout << B[i] << " ";
		if(i!=11) cout << ",";
	} 
	cout <<" ]"<< endl;
	cout << endl;
	cout << "随机选取的两个互素数为:" << m << " " << n << endl; 
	cout << endl;
}

//加密部分 
void jiami(string ming){
	
	int l = ming.length();
	string zu1;
	//int kk = 0;
	for(int k=0; k=0; j--){
			if(ans[i]>=A[j]){
				flag1 += "1";
				ans[i] = ans[i] - A[j];
			}
			else flag1 += "0";
		}
		reverse(flag1.begin(),flag1.end());
		flag[i] = flag1;
	}
	for(int i=0; i=0; j--){
			if(sum1[i]>=BB[j]){
				flag1 += "1";
				sum1[i] = sum1[i] - BB[j];
			}
			else flag1 += "0";
		}
		reverse(flag1.begin(),flag1.end());
		flagz[i] = flag1;
	}
	for(int i=0; i> (32-(n))))//右移时高位补零
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
#define A 0x67452301
#define B 0xefcdab89
#define C 0x98badcfe
#define D 0x10325476
//strBaye的长度
unsigned int strlength;
//A,B,C,D的临时变量
unsigned int atemp;
unsigned int btemp;
unsigned int ctemp;
unsigned int dtemp;
//常量ti 
const unsigned int k[]={
        0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
        0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,
        0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,
        0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,
        0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
        0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,
        0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,
        0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,
        0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
        0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,
        0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,
        0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,
        0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391};
//向左位移数
const unsigned int s[]={7,12,17,22,7,12,17,22,7,12,17,22,7,
        12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
        4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,
        15,21,6,10,15,21,6,10,15,21,6,10,15,21};
const char str16[]="0123456789abcdef";
void mainLoop(unsigned int M[])
{
    unsigned int f,g;
    unsigned int a=atemp;
    unsigned int b=btemp;
    unsigned int c=ctemp;
    unsigned int d=dtemp;
    for (unsigned int i = 0; i < 64; i++)
    {
        if(i<16){
            f=F(b,c,d);
            g=i;
        }else if (i<32)
        {
            f=G(b,c,d);
            g=(5*i+1)%16;
        }else if(i<48){
            f=H(b,c,d);
            g=(3*i+5)%16;
        }else{
            f=I(b,c,d);
            g=(7*i)%16;
        }
        unsigned int tmp=d;
        d=c;
        c=b;
        b=b+shift((a+f+k[i]+M[g]),s[i]);
        a=tmp;
    }
    atemp=a+atemp;
    btemp=b+btemp;
    ctemp=c+ctemp;
    dtemp=d+dtemp;
}
//填充函数

unsigned int* add(string str)
{
    unsigned int num=((str.length()+8)/64)+1;//以512位,64个字节为一组
    unsigned int *strByte=new unsigned int[num*16];    
    strlength=num*16;
    for (unsigned int i = 0; i < num*16; i++)
        strByte[i]=0;
    for (unsigned int i=0; i >2]|=(str[i])<<((i%4)*8);
    }
    strByte[str.length()>>2]|=0x80<<(((str.length()%4))*8);
    strByte[num*16-2]=str.length()*8;
    return strByte;
}
string changeHex(int a)
{
    int b;
    string str1;
    string str="";
    for(int i=0;i<4;i++)
    {
        str1="";
        b=((a>>i*8)%(1<<8))&0xff;   //逆序处理每个字节
        for (int j = 0; j < 2; j++)
        {
            str1.insert(0,1,str16[b%16]);
            b=b/16;
        }
        str+=str1;
    }
    return str;
}
string getMD5(string source)
{
    atemp=A;    //初始化
    btemp=B;
    ctemp=C;
    dtemp=D;
    unsigned int *strByte=add(source);
    for(unsigned int i=0;i

你可能感兴趣的:(C/C++ 实现基于背包算法的加解密(带摘要算法))