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 );
}