RSA加密算法(32bit比特级运算)(复杂版)(C++实现)

(一) 题目

在这里插入图片描述

(二)分析

关于随机选取16bit的素数
16bit的十进制数范围为[0—65535] ,[20,216-1],将这个范围内所有素数(大致6000+个)求出来放在数组中,通过随机选取数组元素的编号,实现随机选取p,q
关于数据类型
16bit的p,q产生的n的位数必然在32bit范围内,而对于过程中的一些辅助变量(比如高次方幂运算是会大于32bit的)
下面是各种数据类型的字节、位数、有无符号:

数据类型位数字节数有无符号数范围
unsigned short (int)16位2[0,216-1]
int32位4[-231,231-1]
unsigned (int)32位4[0,232-1]
unsigned long long64位8[0,264-1]

所以:全局大部分变量用的是无符号的32位 unsigned int
部分变量使用64位 unsigned long long

(三)整体代码


#include<iostream>
#include<iomanip>
using namespace std;

#define Prime_Count 6541  // [3, 65535]内的所有素数,总共有6541个素数,这6541个素数随机选取两个作为P,Q
#define BinarySize 40          // 部分数组的大小 这里只是因为40>32

//判断素数       Eratosthenes筛法:正整数n是素数,当且仅当它不能被任何一个小于sqrt(n)的素数整除
unsigned   IsPrime(unsigned n)
{
	unsigned   temp = (unsigned  )sqrt(n);
	for (unsigned  i = 2; i <= temp; i++)
	{
		if (n % i == 0) return 0;//n不是素数的话返回0
	}
	return 1;//n是素数的话返回1
}

//计算16bit的所有素数,即范围在[3, 65535]内的所有素数,总共有6541个素数,并赋值到数组Prime[]中 .        这里不考虑2,因为计算欧拉函数后相当于只是一个素数的欧拉函数(2-1)*(Q-1)
 void All_Prime_Number(unsigned  Prime[])
{
	 unsigned  j = 0;
	for (unsigned  i = 3; i < 65535; i = i + 2)//i+2跳过偶数(加快循环)         
	{		
		if (IsPrime(i) == 1)
		{
			Prime[j] = i;			
			j++;
		}
	}
}

 //在Prime[Prime_Count]中,随机挑选两个不相同的素数p,q
void RandomChoose_Prime_Number(unsigned &p, unsigned &q, unsigned Prime[])
{
	srand((unsigned)time(NULL));//确保随机性
	unsigned Choose_P =(unsigned)rand() % (Prime_Count );//在从[0,6540]共6541个数里面随机选一个  
	//cout << "Choose_P=" << Choose_P << endl;

	//Plus_Q表示在P的数组标号上的增量,为了P,Q不相等(即数组下标不相等),增量的范围是[1,6540]
	unsigned  Plus_Q = (unsigned)rand() % (Prime_Count - 1)+1;//增量的范围是[1,6540]
	//cout << "Plus_Q=" << Plus_Q << endl;

	unsigned  Choose_Q = (Choose_P + Plus_Q) % (Prime_Count );// % Prime_Count 是因为Choose_P + Plus_Q可能会超过6541
	//cout << "Choose_Q=" << Choose_Q << endl;

	p = Prime[Choose_P];
	q = Prime[Choose_Q];
	cout << "   Bob选取的两素数为:p=" << p << "," << "q=" << q << endl;
}

//计算n和n的欧拉函数值
void N(unsigned p, unsigned  q, unsigned  &n, unsigned &Euler_n)
{
	n =p *q;
	Euler_n = (p-1) * (q-1);
	cout << "   Bob计算出的公钥为:{ e=5,n=" << n << "}"<<endl;
}

//求逆元d  扩展欧几里得算法(递归版)  y是中间负责传递值的变量
void Eucild_D(unsigned e, unsigned  Euler_n, unsigned long long& d, unsigned long long& y)  // d 是 e mod Euler_n 的乘法逆元
 {
	 if (0 == Euler_n)
	 {
		 d = 1, y = 0;
		 return;
	 }
	 Eucild_D(Euler_n, e % Euler_n, d, y);
	 unsigned long long flag = d;
	 d = y;
	 y = flag - e / Euler_n * y;

 }
/*
//这是一开始的求逆元算法,一个数一个数的试,数字小还能算出来,数字大的时候时间超慢超长
void Euild_D(unsigned   e, unsigned   Euler_n, unsigned  & d)
{
	unsigned  Sign_of_Inverse_Element = 0;//判断是否求出逆元的标志:Sign_of_Inverse_Element。当Sign_of_Inverse_Element=1,则求出了逆元
	do
	{

		for (unsigned  i = Euler_n/e; i < Euler_n; i++)
		{
			unsigned long pro=((unsigned long)i * (unsigned long)e) % Euler_n;
			if (pro == 1)
			{
				Sign_of_Inverse_Element = 1; //Sign_of_Inverse_Element=1时表面求出了逆元d
				d = i;
			}
		}
	} while (Sign_of_Inverse_Element != 1);
	cout <<"d="<< d << endl;
}
*/

 //将明文串的ASCII值('abc'=(int)6382179)转为比特串,然后根据n的大小来对比特串分组,将分割后的数放入m_partition[BinarySize]中;
//Partition_count比特串分组组数            m_partition_bits比特串分组每组的位数           m_partition[]存放比特串分组的数组
void WholeASCII_to_WholeInt_to_WholeBinary_to_PartitionBinary_to_PartitionInt(unsigned  n, unsigned  &Partition_count, unsigned  & m_partition_bits ,unsigned  m_partition[])
{
	//ASCII
	 unsigned m;
	m = (unsigned )'abc';
	cout <<"   Alice想要发送的明文为"<< "abc"<<endl;
	cout <<"   明文abc的ASCII值为" << m<< endl;
	//ASCII转比特串
	unsigned   Positive_Binary[BinarySize] = { 0 };  //正序存放二进制数0和1,二进制的小端放在数组的小序号
	unsigned   Reverse_Binary[BinarySize] = { 0 };  //倒序存放二进制数0和1,二进制的大端放在数组的小序号(这个是真正的二进制表示)因为十进制整数转二进制,先逐步模二取余,然后倒序排列

	unsigned  remainder;//余数
	unsigned  index=0;//计数量
	while (m != 0)
	{
	    remainder = m % 2;  //m除以2的余数
		m= m / 2;  //m被2整除的商
		Positive_Binary[index] = remainder;  //将余数存放在数组Positive_Binary[BinarySize]中,这里是正序排放,
		index++;
	}
	cout << "   明文abc转为比特串后的比特串位数为:" << index <<"位"<< endl;

	//倒序比特串
	for (unsigned long i = 0; i < index; i++)
	{
		Reverse_Binary[i] = Positive_Binary[index-i-1];//求倒叙排列
	}

	

		cout << "   总的明文比特串为:";
		for (unsigned i = 0; i < index; i++)
		{
			cout << Reverse_Binary[i] << setw(1);
		}
		cout << endl;
	
	
	 m_partition_bits = (unsigned  )(log(n) / log(2));//对m的二进制截取的位数m_partition_bits<=[log2(n)]向下取整
	cout <<"   比特串分割后每组的位数为:"<< m_partition_bits <<"位"<< endl;

	unsigned  Sign_of_Round_up;//向上取整的标志	
	if (index % m_partition_bits != 0) 
	     {Sign_of_Round_up = 1;}
	else
	     { Sign_of_Round_up = 0; }
	//cout << "Sign_of_Round_up=" << Sign_of_Round_up << endl;

	Partition_count = (unsigned)(index / m_partition_bits) + Sign_of_Round_up;//m根据截取的位数m_partition_bits被划分成m_Partition_count个部分
	cout << "   共有" << Partition_count << "个比特串分割小组"<<endl ;
	
	//将每个比特串分组(二进制)都转成十进制  (for 循环表达)//下面注释里还有while表达(似乎while没成功)
	for (unsigned  i = 0 ; i < Partition_count; i++)
	{
		unsigned  Sign;//比特串分组的尾部元素的取值
		   if (index-1 <=(i + 1) * m_partition_bits - 1 )
		      {Sign = index - 1;}
		   else
		      {Sign = (i + 1) * m_partition_bits - 1;	}
		
		 
		 unsigned   Sum=0;
		for (unsigned  j = i* m_partition_bits; j <= Sign; j++)
		{
			//求2的( j % m_partition_bits)次方
			unsigned  pow=1;
			for (unsigned k = 0; k < j % m_partition_bits; k++)
			{
				pow = pow * 2;
			}
			Sum = Sum + Positive_Binary[j]*pow;// 这里用的是Positive_Binary[](小端对小端),所以是j(且用Positive_Binary[]明显要比 Reverse_Binary[BinarySize] 便于计算)
		}
		m_partition[i] =(unsigned )Sum;
		cout << "   第" << i +1<< "个明文分割小组的值为" << m_partition[i] << endl;
	}
	
	/*
	unsigned  ZLS=0;
	while (ZLS < Partition_count)
	{
		cout << "ZLS=" << ZLS << endl;
		
		unsigned  Sign;
		if (index - 1 <= (ZLS + 1) * m_partition_bits - 1)
		{
			Sign = index - 1;
		}
		else
		{
			Sign = (ZLS + 1) * m_partition_bits - 1;
		}
		cout << "Sign=" << Sign << endl;
		unsigned   Sum = 0;
		for (unsigned j =ZLS * m_partition_bits; j <= Sign; j++)
		{
			unsigned  pow = 1;
			for (unsigned  k = 0; k < j % m_partition_bits; k++)
			{
				pow = pow * 2;
			}
			cout << "pow = " << pow << endl;
			Sum = Sum + Positive_Binary[j] * pow;// 这里用的是Positive_Binary[](小端对小端),所以是j(且用Positive_Binary[]明显要比 Reverse_Binary[BinarySize] 便于计算)
		}
		m_partition[ZLS] = (unsigned )Sum;
		cout << "m_partition[" << ZLS << "]=" << m_partition[ZLS] << endl;
		ZLS = ZLS + 1;
	}
	*/
}

//对于明文m_partition[BinarySize]的加密,得到c_partition[BinarySize]  
void E_M(unsigned  m_partition[], unsigned  Partition_count, unsigned  e, unsigned  n, unsigned  c_partition[])
{
	for (unsigned  i = 0; i < Partition_count; i++)
	{
		unsigned long long product = 1;//product表示m_partition[i]自身不断相乘的积  
		for (unsigned  j = 1; j <= e ; j++)//用e来控制m_partition[i]的指数
		{
			product = (product * m_partition[i]) % n;//注意不要忘记%n  
		}
		c_partition[i] = (unsigned  )product;
		cout << "   第" << i +1<< "个明文分割小组加密后的值为" << c_partition[i] << endl;
	}
	//cout << endl;
}

//把c_partition[BinarySize] 以二进制的形式在信道传播 

//对密文c_partition[BinarySize]的解密,得到After_m_partition[BinarySize]
void D_C(unsigned  c_partition[], unsigned  Partition_count, unsigned d, unsigned n, unsigned After_m_partition[])
{
	unsigned long long N = (unsigned long long)n;
	for (unsigned  i = 0; i < Partition_count; i++)
	{
		unsigned long long product = 1;//product表示c_partition[BinarySize]自身不断相乘的积
		for (unsigned long long  j = 1; j <= d; j++)//用d来控制c_partition[BinarySize]的指数
		{			
			product = (  product * (unsigned long long)c_partition[i])   % N;//注意不要忘记%n
		}

		After_m_partition[i] = (unsigned)product;
		cerr << "   第" << i +1<< "个密文分割小组解密后的值为" << After_m_partition[i] << endl;
	}
}

//将分割的After_m_partition[BinarySize]合并成大整数,然后转为字符串C
void PartitionInt_to_WholeInt_to_WholeASCII(unsigned   After_m_partition[], unsigned m_partition_bits,unsigned   Partition_count,char str[])
{
	unsigned Sum_After_m_partition_bits=0;
	unsigned  C_Sum=0;
	for (unsigned  i = 0; i < Partition_count; i++)
	{
		unsigned  pow = 1;
		for (unsigned k = 0; k < Sum_After_m_partition_bits; k++)
		{
			pow = pow * 2;
		}
		//cout << "pow=" << pow << endl;
	   C_Sum = C_Sum + pow* After_m_partition[i];
	   //cout << "C_Sum=" << C_Sum << endl;
      Sum_After_m_partition_bits = Sum_After_m_partition_bits+ m_partition_bits;
	}

 //如何把str[]直接转成char C?
	
	str[0] = (char)(C_Sum & 0xff);
	str[1] = (char)((C_Sum >> 8) & 0xff);
	str[2] = (char)((C_Sum >> 16) & 0xff);
	str[3] = (char)((C_Sum >> 24) & 0xff);
	cout << "   Bob解密后得到的明文为:" << str[2] << str[1] << str[0] << endl;
	
}

int main()
{
	unsigned  Prime[Prime_Count];
	unsigned  p , q ;
	unsigned  n, Euler_n;
	unsigned   e = 5;
	unsigned  long long d,y;
	unsigned  Partition_count;
	unsigned   m_partition_bits;
	unsigned   m_partition[BinarySize];
	unsigned   c_partition[BinarySize];
	unsigned  After_m_partition[BinarySize];
	

	cout << "《Bob想要收到来自他人的信息,于是Bob开始制作公私密钥》" << endl;
	cout << "{"<<endl;
	//求所有素数,并随机选取两素数
	All_Prime_Number(Prime);
	RandomChoose_Prime_Number(p, q, Prime);
	//计算n,和n的欧拉函数
	N(p, q,n, Euler_n);
	//计算逆元d
	Eucild_D( e,  Euler_n,  d,y);
	cout << "   Bob计算出的秘密钥:{ d=" << d << ",n="<<n<<"}"<<endl;
	cout << "}" << endl;
	cout << endl<<endl;


	cout << "《Bob将计算出来的公钥广播发给所有人:"<<"“ 我是Bob,想要给我发消息,就用这个公钥:{ e=5,n=" << n << "}”》"<< endl<<endl<<endl;



	cout << "《Alice想要给Bob发送明文,于是Alice开始对明文加密》" << endl;
	cout << "{" << endl;
	//对明文分割并加密明文
	WholeASCII_to_WholeInt_to_WholeBinary_to_PartitionBinary_to_PartitionInt( n, Partition_count, m_partition_bits, m_partition);
	E_M(m_partition, Partition_count, e, n, c_partition);
	cout << "}" << endl;
	cout <<endl<<endl;


	//Alice将密文通过信道发送给Bob
	cout << "《Alice将密文通过信道发送给Bob》"<<endl<<endl<<endl;


	cout << "《Bob收到密文后开始解密》"<<endl;
	cout << "{" << endl;
	//解密密文
	D_C(c_partition, Partition_count, d, n, After_m_partition);
	char str[4];
	PartitionInt_to_WholeInt_to_WholeASCII(After_m_partition, m_partition_bits,Partition_count, str);
	cout << "}" << endl;
	cout << endl << endl<<endl;

	system("pause");
	return 0;
}

(四)运行结果

成功的
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
失败的
在这里插入图片描述

(五)不足之处

1.欧几里得求逆元的函数是从别处找的代码,还没研究具体流程和原理是什么。但是已经发现有时候d会被赋值为1,造成解码出错
2.当d大于15亿,运算时间超长,算不出来结果。

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值