数字签名------RSA大数分解算法之逆推法

cpp 复制代码
/*
  RSA加解密过程

  随机地选择两个大素数p和q,而且保密;
  计算n=pq,将n公开
  计算fi=(p-1)*(q-1),对fi保密
  随机选择一个正整数e,1<e<fi 且e和fi 互素
  根据 ed=1 mod fi,求出d,并对d保密
  加密运算:C=M^e mod n
  解密运算:M=C^d mod n
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <malloc/malloc.h>

#define BUFLEN 4096
#define MAX(a,b) (a>b?a:b)

char result[BUFLEN] = {'\0'};

// compare字符串比较函数
int compare(char *str1, char *str2)
{
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    if (len1 > len2)
        return 1;
    else if (len1 < len2)
        return -1;
    else
    {
        int n = strcmp(str1, str2);
        if (n > 0)
            return 1;
        else if (n == 0)
            return 0;
        else
            return -1;
    }
}
 
//  加法运算
char *add(char *str1, char *str2)
{
    //  确定较大,较小的字符串,并获取它们的长度
    int n = compare(str1, str2);
    char *max_str = n >= 0 ? str1 : str2;
    char *min_str = n >= 0 ? str2 : str1;
    int len_max = strlen(max_str);
    int len_min = strlen(min_str);
    
    //  创建 较大字符串 长度大1 的空间 存储结果
    char* str = malloc(BUFLEN + 1);
 
    str[len_max + 1] = '\0';
 
    //  进行加法运算
    int plus = 0;        // plus 为 进位
    int i = len_max - 1; // 标记 较大字符串 最低位字符的位置
    int j = len_min - 1; // 标记 较小字符串 最低位字符的位置
    for (; i >= 0; i--)
    {
        if (j >= 0)
        {
            str[i + 1] = max_str[i] + min_str[j] - '0' + plus; // 字符相加
            j--;                                               // 位置左移 1
            plus = str[i + 1] > '9' ? 1 : 0;                   // 判断是否进位
            if (plus == 1)
                str[i + 1] -= 10; // 进位 则减 10
        }
        else // 较小字符串的字符 全部加完
        {
            str[i + 1] = max_str[i] + plus;
            plus = str[i + 1] > '9' ? 1 : 0;
            if (plus == 1)
                str[i + 1] -= 10;
        }
    }
 
    //  根据 最高位 是否 进位,确定 返回指针
    if (plus == 0){
        return str + 1; // 返回 str 右移1位的位置
        //strcpy( result, str + 1 );
    }else{
        str[0] = '1'; // str首位 赋 '1'
        return str;   // 返回 str
        //strcpy( result, str );
    }
    //free(str);
    //return result;
}

//减法运算
char* sub( char *str1, char *str2 ){
    //  确定结果 正负 或 0
    int is_neg = compare(str1, str2);
    if (is_neg == 0)
        return "0"; // 若为 0, 直接返回 "0" 结束
 
    char *max_str = is_neg > 0 ? str1 : str2;
    char *min_str = is_neg > 0 ? str2 : str1;
    int len_max = strlen(max_str);
    int len_min = strlen(min_str);
    
    //  创建 较大字符串 长度大1 的空间 存储结果
    char* str = malloc(BUFLEN + 1);
    str[len_max + 1] = '\0';
 
    //  进行减法运算
    int plus = 0; // plus 为退位
    int i = len_max - 1;
    int j = len_min - 1;
    for (; i >= 0; i--)
    {
        if (j >= 0)
        {
            str[i + 1] = max_str[i] - min_str[j] + '0' + plus; // 字符相减
            j--;
            plus = str[i + 1] < '0' ? -1 : 0; // 是否 退位
            if (plus == -1)
                str[i + 1] += 10; // 退位 则加 10
        }
        else
        {
            str[i + 1] = max_str[i] + plus;
            plus = str[i + 1] < '0' ? -1 : 0;
            if (plus == -1)
                str[i + 1] += 10;
        }
    }
 
    //  确定最后一个 前位0 的位置,默认 str首位 为'0'
    int n_zero = 0;
    for (int i = 1; i <= len_max; i++)
    {
        if (str[i] != '0')
            break;
        n_zero++;
    }
 
    //  根据 正负 和 最后一个前位0的位置 确定 返回指针
    if (is_neg < 0)
    {
        str[n_zero] = '-';   // 将最后一个前置0的 赋为 '-'
        return str + n_zero; // 返回'-'的位置
        //strcpy( result, str + n_zero );
    }
    else
        return str + n_zero + 1; // 返回最后一个前置0 右移1位的位置
        //strcpy( result, str + n_zero + 1 );
    
    //free(str);
    //return result;
}


char *mul(char *str1, char *str2)
{
    // 判断 str1 和 str2 中是否为 0,若有, 返回 "0" 结束
    if (*str1 == '0' || *str2 == '0')
        return "0";
 
    // 提高效率
    int n = compare(str1, str2);
    char *max_str = n > 0 ? str1 : str2;
    char *min_str = n > 0 ? str2 : str1;
    int len_min = strlen(min_str);
 
    // 进行乘法运算
    char *str_sum = "0";
    // str2每个字符 乘 str1
    for (int i = 0; i < len_min; i++)
    {
        char *str = "0";
        int m = (int)(min_str[i] - '0'); // 把字符转成整型
        if (m == 0)
            continue;
        else
        {
            for (int j = 0; j < m; j++)
                str = add(str, max_str);
        }
        // 根据字符位数 往str后面 添 '0'
        int len = strlen(str);
        for (int j = 0; j < len_min - i - 1; j++)
        {
            str[len + j] = '0';
        }
        str[len + len_min - i - 1] = '\0';
        //printf("%s\n", str);
        // 将每次得到的结果相加
        str_sum = add(str_sum, str);
        //printf("%s\n", str_sum);
    }
    return str_sum;
}

// 除法计算
char *divi(char *str1, char *str2)
{
    // 解决一些特殊情况
    if (*str2 == '0')
        return " 0 不能作为除数!";
    if (compare(str1, str2) == -1)
        return "0";
 
    // 初始化 余数(被除数) 除数 和 结果
    char *str_mol = add(str1, "0");  // 得到 str1 副本
    char *str_divi = add(str2, "0"); // 得到 str2 副本
    char *str_sum = "0";
 
    // 进行除法运算
    // 将 str_mol 和 str_divi 右对齐
    int n = strlen(str1) - strlen(str2);
    char *str_n = "1";
    for (int i = 0; i < n; i++)
        str_n = mul(str_n, "10");    // 得到str_divi 扩大的倍数
    str_divi = mul(str_divi, str_n); // 实现右对齐
 
    for (int i = 0; i <= n; i++)
    {
        while (compare(str_mol, str_divi) >= 0)
        {
            str_mol = sub(str_mol, str_divi);
            str_sum = add(str_sum, str_n); // 将每次结果加起来
            //puts(str_mol);
            //puts(str_sum);
        }
        if (i < n)
        {
            *(str_n + strlen(str_n) - 1) = '\0';       // 去除尾位置的 '0'
            *(str_divi + strlen(str_divi) - 1) = '\0'; // 去除尾位置的 '0'
        }
    }
    return str_sum;
}
 
//取模运算
char *mol(char *str1, char *str2)
{
    if (*str2 == '0')
        return " 0 不能作为除数!";
    if (compare(str1, str2) == -1)
        return str1;
    char *str_mol = add(str1, "0");
    char *str_divi = add(str2, "0");
    char *str_sum = "0";
    int n = strlen(str1) - strlen(str2);
    char *str_n = "1";
    for (int i = 0; i < n; i++)
        str_n = mul(str_n, "10");
    str_divi = mul(str_divi, str_n);
    for (int i = 0; i <= n; i++)
    {
        while (compare(str_mol, str_divi) >= 0)
        {
            str_mol = sub(str_mol, str_divi);
            str_sum = add(str_sum, str_n);
        }
        if (i < n)
        {
            *(str_n + strlen(str_n) - 1) = '\0';
            *(str_divi + strlen(str_divi) - 1) = '\0';
        }
    }
    return str_mol;
}

//简单的大素数检测方法
int isprime(unsigned char* number){
	char* h = number;
	
	while( *h != '\0' ) h++;
	
	char* f = h-1;
	if( *f == '1' || *f == '3' || *f == '7' || *f == '9' ){
		printf( "%s is prime\n",number );
	    return 1;
	}else{
	    return 0;
	}
}
//减法找出指定范围的素数,指定个数。
void prime_n(unsigned char* p_max,long long num ){
	unsigned char s_max[BUFLEN];

	strcpy( s_max,p_max );
		
	for( long long int i = 0;i < num ; i++ ){
    	unsigned char* p = sub(s_max,"1");
    	strcpy( s_max, p );
    	
    	if( isprime(s_max) == 0 ){
    		continue;
    	}
    	//printf( "\nprime is: %s\n",s_max );	    
	}
}
//减法找出指定范围的素数,不指定个数。
void prime(unsigned char* p_max,unsigned char*p_min ){
	unsigned char s_max[BUFLEN];
	unsigned char s_min[BUFLEN];

	strcpy( s_max,p_max );
	strcpy( s_min,p_min );
	
    while( strcmp( s_max,s_min ) > 0 ){
    	unsigned char* p = sub(s_max,"1");
    	strcpy( s_max, p );
    	
    	if( isprime(s_max) == 0 ){
    		continue;
    	}
    	//printf( "\nprime is: %s\n",s_max );
    }
}

//大整数平方根二分查找法
unsigned char s_mid[BUFLEN];
unsigned char* search( unsigned char* n ){

	unsigned char s_max[BUFLEN] = {'\0'};
	unsigned char s_min[BUFLEN] = {'\0'};

	strcpy( s_max,n );
	strcpy( s_min,"0" );

    unsigned char* p = add( s_max,s_min ); 
    strcpy( s_mid, p );
    
    while(1)
    {
    	if( compare( mul( s_mid,s_mid ), n ) == 0 ){
    		return s_mid;
    	}
    	if( compare( mul( s_mid,s_mid ), n ) > 0 ){
    		strcpy( s_max, s_mid );
    	}
    	
    	if( compare( mul( s_mid,s_mid ), n ) < 0 ){
    		strcpy( s_min, s_mid );         
    	}
    		
    	p = divi( add( s_max,s_min ),"2" );                
        strcpy( s_mid, p );   
    	
    	//printf( "\nFind Middle Max: %s\n", s_max );
    	//printf( "\nFind Middle Min: %s\n", s_min );
    	
    	if(strcmp( s_mid , s_max) == 0 || strcmp( s_mid , s_min) == 0){
    		break;
    	}
    }
        
    printf( "\nFind Square Root : %s\n", s_mid );	
    
    return s_mid;
}

//费马大整数分解法
void Fermat(char* n){
	 char* p = NULL;
	 char temp[BUFLEN] = {'\0'};
	 char sqrt_buf[BUFLEN] = {'\0'};
	 
	 //求N的平方根
	 search( n );
	 strcpy( sqrt_buf, s_mid );

     if( compare( mul( sqrt_buf,sqrt_buf ), n ) < 0 ){
    		
    		p = add( sqrt_buf,"1" ); 
            strcpy( sqrt_buf, p );        
      }	
      
      while(1){
      	    //sqrt(a*a-n);
            p = sub( mul( sqrt_buf, sqrt_buf), n );
            strcpy( temp, p);
            
            search( temp);
            
            if( compare( mul( s_mid,s_mid ), temp ) == 0 ){
                break;    
             }
            p = add( sqrt_buf,"1" ); 
            strcpy( sqrt_buf, p );    
      }
      
      printf( "a = %s\n",sqrt_buf );
      
      printf( "b = %s\n",s_mid ); 

      printf( "p = %s\n",sub( sqrt_buf, s_mid ) );
      //q=a+b
      printf( "q = %s\n",add( sqrt_buf, s_mid ) ); 
      //n=a*a-b*b
      printf( "n = %s\n",sub( mul(sqrt_buf, sqrt_buf), mul( s_mid, s_mid)) );
}

//试除法1
void my_div(unsigned char* n){
	
	unsigned char* s = search( n );
	
    //执行记忆
    //unsigned char* s= "153592948117643031971517950776863466679694438097816828765125700714745511962608284908817562239895370326309718699494000789069636694784157395997281163722474666626129943585521262861562558896499277460915739845266907896591533110840273656938024570164860298294802072335878132664373128092511510210496049811213454028517"; 
	
	while(1){
		s = sub( s, "1" );

		if( isprime(s) == 0 ){
    		continue;
    	}
    	
    	if( compare( mol(n,s),"0" ) == 0){
    		printf( "\nFind p is: %s\n", s );
    		printf( "\nFind q is: %s\n", divi( n,s ) );
    		break;
    	}
	}

}
//试除法2
void mypq(unsigned char* n) {
    unsigned char p_max[BUFLEN]; //最大值
    unsigned char p_mid[BUFLEN]; //中间值
    unsigned char p_min[BUFLEN]; //最小值
    
    //寻找平方根,p值不会大于平方根,q值不会小于平方根,然后p值向下找,q值向上找。
    search( n );

    /*
    //TEST Starting
    
    //平方根
    unsigned char* p1= "153592948117643031971517950776863466679694438097816828765125700714745511962608284908817562239895370326309718699494000789069636694784157395997281163722474666626129943585521262861562558896499277460915739845266907896591533110840273656938024570164860298294802072335878132664373128092511510210496049811213458022433";  
    //执行记忆
    unsigned char* p2= "153592948117643031971517950776863466679694438097816828765125700714745511962608284908817562239895370326309718699494000789069636694784157395997281163722474666626129943585521262861562558896499277460915739845266907896591533110840273656938024570164860298294802072335878132664373128092511510210496049811213454070411"; 
    
    strcpy( p_max,p2 );
    
    //Test End*/
    
    //prime( p1,p2 ); 
    
    //试除法寻找p值
    unsigned char d[BUFLEN];
    unsigned char m[BUFLEN];
    /*
    //向上查找q
    memset( p_min,'\0',sizeof(p_min) );
    strcpy( p_min, p_mid );
    while( compare_str( p_min,p_max ) < 0 ){
    	unsigned char* p = add(p_min,"2");
    	strcpy( p_min, p );
    	
    	if( isprime(p_min) == 0 ){
    		continue;
    	}
    	
    	p = divi( n,p_min );
    	memset( d,'\0',sizeof(d) );
    	strcpy( d,p );
    	//printf( "%s\n",d );
    	
    	p = mul( d,p_min );
    	memset( m,'\0',sizeof(m) );
    	strcpy( m,p );
    	//printf( "%s\n",m );
    	
    	if( compare_str( m,n ) == 0 )
    	{
    		//printf( "%s\n",p_min );
    		break;
    	}
    }*/
    
    //向下查找p
    strcpy( p_max,s_mid );
    strcpy( p_min, "0" );
    while( strcmp( p_max,p_min ) > 0 ){
    	unsigned char* p = sub(p_max,"1");
    	strcpy( p_max, p );
    	
    	if( isprime(p_max) == 0 ){
    		continue;
    	}
    	
    	unsigned char* t = divi( n,p_max );
    	strcpy( d,t );
    	//printf( "%s\n",d );
    	
    	unsigned char* mu = mul( d,p_max );
    	strcpy( m,mu );
    	//printf( "%s\n",m );
    	
    	if( strcmp( m,n ) == 0 )
    	{
    		printf( "\nFind p is: %s\n",p_max );
    		break;
    	}
    }
    printf( "\nFind q is: %s\n", d );
    printf( "\nNew  n is: %s\n", m );
}

/*
  大数分解末尾倒推法
  
  末尾倒推法是一个典型的平衡二叉树结构

  素数除了2、5,都是以1、3、7、9做为最后一位。

  1 * 1 = 1;  1 * 3 = 3;  1 * 7 = 7; 1 * 9 = 9;
  3 * 3 = 9;  3 * 7 = 21; 3 * 9 = 27;
  7 * 7 = 49; 7 * 9 = 63;
  9 * 9 = 81;
  
  1、9是三叉树,3、7是二叉树。
  二叉树对应关系是 1*3=3、7*9=63 和 1*7=7、3*9=27。
  三叉树对应关系是 1*1=1、3*7=21、9*9=81 和 1*9=9、3*3=9、7*7=49。
  所以根据N值最后一位就可以判断PQ的最后一位是什么。
  
  程序设计 : 剑舞
  2021.12.21
*/
/*
  字符串最后一个字节总是'\0',所以计算位数的时候要从后往前计算。
  RSA一个2048位的平方根是308个字节,p和q一般大小一致,也有pq距离很远的情况。
*/

unsigned char* g = NULL;
unsigned int depth = 5; //需要递归的字节数包括'\0'
  
//查找指定的字符串
unsigned char* find_str( unsigned char* str1,char* str2,unsigned long long int n,unsigned long long int c ){
      unsigned char* p = str1;
      
      while( *p != '\0' ) p++;
      
      p = p - n;
      
      if( strncmp( p, str2, c ) == 0 ){
      	  return p;
      }else{
          return NULL;
      }
}

//二叉树递归查找法
void Ten( unsigned char* aa,unsigned char* bb,unsigned char* carry,unsigned char* key,unsigned long long int pos,unsigned long long int n ){
    unsigned char p1[BUFLEN] = {'\0'},q1[BUFLEN] = {'\0'},n1[BUFLEN] = {'\0'},arry[BUFLEN] = {'\0'};
    char* p = NULL;
    
    strcpy( p1,aa );
    strcpy( q1,bb );
    strcpy( arry,carry );
    
    //递归退出条件
	  if( pos == depth){
		  return;
	  }
	  for(int i = 0;i <= 9;i++){
		  for(int j = 0; j <= 9;j++){
		    
			  p = mul( p1,q1 );
			  strcpy( n1,p );
		      
		      
			  if( strcmp( p,g ) == 0 ){
				  printf( "\n%s * %s = %s\n",p1,q1,p );
				  exit(0);
			  }

			    
			  unsigned char* d = find_str( n1,key, pos, n );
			  if( d == NULL ){  
			    p = add( q1,arry );
		        strcpy( q1,p );	
			    continue;
			  }
			  if( pos == depth-1 ){
			  	  //printf( "key = %s\n",key );
			      printf( "%s * %s = %s\n",p1,q1,n1 );
			  }
			  Ten( p1,q1,mul( arry,"10" ),key-1,pos+1,n+1 );
			  
			  p = add( q1,arry );
		      strcpy( q1,p );
		  }
		p = add( p1,arry );
		strcpy( p1,p );
        strcpy( q1,bb );
	  }  
}

//个位开始遍历二叉树
void Position( char* key,int byte ){
    int c = 0;
    char sp[10]={'\0'},sq[10]={'\0'};
    char pst[BUFLEN] = {'\0'};
    
    g = key;
    depth = byte;
    
	while( *key != '\0' )
		key++;
	key = key - 1;
    
	for( int i = 0; i <= 9; i++ ){
		for( int j = 0; j <= 9; j++ ){
			c = i * j;
		    //printf( "%d * %d = %d\n",i,j,c );
		    
		    sprintf( pst,"%d",c );
		    
		    unsigned char* d = find_str( pst,key, 1, 1 );
			if( d == NULL ){
			    continue;
			}
		    //printf( "%d * %d = %s\n",i,j,str );
			
			sprintf( sp,"%d",i );
			sprintf( sq,"%d",j );
			
			Ten( sp,sq,"10",key-1,2,2 );
	    }
	}
}

void p1(char* n){
	
	g = n;
	unsigned char* p = n;
	
	printf("n = %s\n",p );
	
	while( *p != '\0' )
		p++;
	p = p - 1;
	
	if( *p == '1'){
	  	Ten( "1","1","10",p-1,2,2 ); //遍历左子树
	  	//Ten( "3","7","10",p-1,2,2 ); //遍历中子树
	  	Ten( "7","3","10",p-1,2,2 ); //遍历中子树
	  	Ten( "9","9","10",p-1,2,2 ); //遍历右子树			    
	}else if( *p == '3'){
	  	Ten( "1","3","10",p-1,2,2 ); //遍历左子树
	  	Ten( "3","1","10",p-1,2,2 ); //遍历左子树
	  	Ten( "7","9","10",p-1,2,2 ); //遍历右子树
	  	Ten( "9","7","10",p-1,2,2 ); //遍历右子树
	}else if( *p == '7'){
	  	Ten( "1","7","10",p-1,2,2 ); //遍历左子树
	  	Ten( "7","1","10",p-1,2,2 ); //遍历左子树
	  	Ten( "3","9","10",p-1,2,2 ); //遍历右子树
	  	Ten( "9","3","10",p-1,2,2 ); //遍历右子树
	}else if( *p == '9'){
	  	Ten( "1","9","10",p-1,2,2 ); //遍历左子树
	  	Ten( "9","1","10",p-1,2,2 ); //遍历左子树
	  	Ten( "3","3","10",p-1,2,2 ); //遍历中子树
	  	Ten( "7","7","10",p-1,2,2 ); //遍历右子树		  	
	}
	
}

int main(){
	//unsigned char* p = "7793";
	//unsigned char* q = "9007";
	unsigned char* n = "70191551";
	//unsigned char* n = "122925017";
	
    //unsigned char* n="23590793711468984198167271160926294826113255441704023652048744480140209940336892276315641353543672536493784348780661558225331213198269530011559411829837338554624376114998295497162788757803894335751350071996153948532477047600902416708175757784909653660971177740378969432920357633053303422050972350922293790823060297626975425277834336688870035687518564629375343301698636583136004158303159414996507975573755129229587954973659384081829316358561985114099532078062773384475300298649781004252999251181753073183315328689206776249189899286131596273916898061715640237722643105794543640645618337729574780862850030620422257598893";
    
    printf( "n = %s\n\n", n );
    
    
    //试除法
    mypq( n );
    //my_div( n );
    
    //费马分解法
    //Fermat(n);
    
    //倒推法
    //Position( n,6 );
	
}
相关推荐
山河君3 分钟前
ubuntu使用DeepSpeech进行语音识别(包含交叉编译)
linux·ubuntu·语音识别
鹏大师运维7 分钟前
【功能介绍】信创终端系统上各WPS版本的授权差异
linux·wps·授权·麒麟·国产操作系统·1024程序员节·统信uos
筱源源9 分钟前
Elasticsearch-linux环境部署
linux·elasticsearch
van叶~10 分钟前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
简简单单做算法10 分钟前
基于Retinex算法的图像去雾matlab仿真
算法·matlab·图像去雾·retinex
萨格拉斯救世主12 分钟前
jenkins使用slave节点进行node打包报错问题处理
运维·jenkins
川石课堂软件测试23 分钟前
性能测试|docker容器下搭建JMeter+Grafana+Influxdb监控可视化平台
运维·javascript·深度学习·jmeter·docker·容器·grafana
云卓SKYDROID25 分钟前
除草机器人算法以及技术详解!
算法·机器人·科普·高科技·云卓科技·算法技术
半盏茶香1 小时前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
徐子童1 小时前
双指针算法习题解答
算法