实现 RSA 算法之 C 语言实现(第二章)(老物)

第二章 如何实现应用RSA算法

趁着白天在自家店里的闲暇时间来写写第二章了,假设记住了第一章的各种定理之后,我们又该如何实现RSA密码的加密解密呢?也懒得废话了,直接进入正题吧。
先回顾几个知识点:

1.模运算的性质:

结合律:(a % p * b) % p = (a * b) % p
可知当a == b时,(a % p * a) % p = (a * a) % p

2.欧拉定理

a^φ(n) ≡ 1 (mod n)

3.乘法逆元性质

e * d ≡ 1 (mod n)  => e * d ≡ 1 + k * n(k为任意整数)
注:且当a与n互质时b有解。
注:如何去除带(mod)式子,令k = 0,即忽略其他同余式。 

接着我们要证明一种现象,根据欧拉定理与乘法逆元性质外带一点模运算的结合律运算列出如下算式:
M ^ (e * d) = M ^ (1 + k * φ(n)) = M * M ^ (φ(n) * k) ≡ M * (1) ^ k ≡ M (mod n)
由此可知 M ^ (e * d) ≡ M (mod n)
注:M ^ φ(n) ≡ 1 (mod n)(欧拉定理)

基于上述请诸位看以下算式:

C ≡ M ^ e (mod n) ①
M ≡ C ^ d (mod n) ②

于是我们这样做,将①代入②可得:M ≡ M ^ (e * d) (mod n) ,是不是和上述的现象的结果一致呢?
至此我们也可以看出,其实C就是一个中间密文。
那么我们来看看RSA运作流程:
假如A和B两人各自拿着e与d。
首先A要给B解密用的密钥d时必然得满足乘法逆元性质e和n要互质,否则得不到d。
其次对于A要加密一个B可以解开的密文必然满足M < n,否则M不满足②式也就不唯一了,同样B也要满足C < n,否则A也解不对B的数据。
最后利用①与②算式分别生成中间密文交由对方来还原数据。
综上所述,RSA算法描述就到此结束了。

以下是算法实现过程:

一.算法所需参数

1.密文数据规模 n = φ(n)
2.生成两把密钥 e 与 d

二.算法实现代码

一开始想着分C++和C版本代码,后来一想,既然都写了C代码何必浪费时间去写吃力不讨好的C++呢?= -=
于是现在直接给出完整的C代码了,因为第三章想基于第二章的代码部分进行讲解,尤其是一些可以优化本质的代码(即不在语法上改进),说不定出了第二章后就不想写第三章了,所以把代码放出来是为了以后好找理由偷懒吧(“都把代码给你了你怎么还要我来讲解(说笑的= -=)”)
事不宜迟贴代码吧!建议想学习的同学复制后拿到自己的编译器里运行测试一下~

#ifndef RSA
#define RSA
// 欧拉函数:φ(x) = x ∏ (1-1/p)(P是数N的质因数)
int Eular(int n)
{
    int ret = 1, i;
    for(i = 2; i*i <= n; i++)
    {
        if(0 == n%i)
        {
            n /= i, ret *= i-1;
            while(0 == n%i)
                n /= i, ret *= i;
        }
    }
    if(n > 1)
        ret *= n-1;
    return ret;
}
// 欧几里何函数:Gcd(a, b)= Gcd(b, a%b)
int Gcd(int a, int b)
{
    return 0 == b ? a : Gcd(b, a%b);
}
// 拓展欧几里何函数:a*x + b*y = gcd(a, b)
//      gcd(a, b) = gcd(b, a%b)
//    a%b = a-(a/b)*b
//    a*x + b*y = gcd(a, b) = gcd(b, a%b) = b*x1 + (a-(a/b)*b)*y1
//        = b*x1 + a*y1–(a/b)*b*y1
//        = a*y1 + b*(x1–a/b*y1)
int Egcd(int a, int b, int *x, int *y)
{
    int result, t;
    // 递归终止条件
    if (0 == b)
    {
        *x = 1, *y = 0;
        return a;
    }
    result = Egcd(b, a%b, x, y);
    t = *x, *x = *y, *y = t-a/b*(*y);
    return result;
}
// 求解乘法逆元函数 b * (return value) ≡ 1 (mod a)
int Inverse(int a, int b)
{
    int x = 0, y = 0;
    if (Egcd(a, b, &x, &y) != 1)
        return -1;
    // 确保余数与被除数符号一致
    if (b < 0)
        a = -a;
    if ((y %= a) <= 0)
        y += a;
    return y;
}
// 幂模运算a^b%k
// 通常思维暴力求解版本
unsigned PowMod(unsigned a, unsigned b, unsigned c)
{
    unsigned ans = a;
    while(b--)
        ans *= a;
    return ans % c;
}
// 幂模运算a^b%k
// 递归版本 a ^ b (mod c)
// 模运算结合律:(a * a) mod c =( (a mod c) * a ) mod c
// C 语言表达:((a * b) % p = (a % p * b) % p)
unsigned RecursionPowMod(unsigned a, unsigned b, unsigned c)
{
    return b ? a * RecursionPowMod(a, b - 1, c) % c : 1;
}
// 幂模运算a^b%k
// Montgomery 版本
unsigned FastPowMod(unsigned a, unsigned b, unsigned c)
{
    unsigned ans;
    for (ans = 1; b; a = a*a%c, b >>= 1)
        if (b & 1)
            ans = ans*a%c;// LSB位为 1
    return ans;
}
#endif // RSA

#include "stdio.h"
#include "stdlib.h"
int main()
{
    // N 数据规模, En = φ(N)(欧拉函数结果), Encrypt 与 Decrypt 分别为两把密钥
    int N = 0x1F, En = Eular(N), Encrypt = 2, Decrypt;
    // 生成RSA参数
    do
    {
        // 选取 Encrypt 与 En 互质的数
        while(1 != Gcd(En, Encrypt))
            Encrypt++;
        // 求解其乘法逆元,若 Decrypt == -1 则表示 En 与 Encrypt 不互质
        Decrypt = Inverse(En, Encrypt);
    }while(-1 == Decrypt);
    // 预览 RSA 参数
    printf("En:%4d\tE:%4d\tD:%4d\n", En, Encrypt, Decrypt);
    // 功能测试, 若陷入死循环必然是因为没能还原回原数据导致无法进入下一索引(++),可自行测试大于N的数据规模
    puts("Test Encrypt Key");
    for(int src = 0, goal; src < N; src++)
    {
        printf("src: %4d\t", src);
        goal = RecursionPowMod(src, Encrypt, N);
        printf("goal: %4d\t", goal);
        src = RecursionPowMod(goal, Decrypt, N);
        printf("src: %4d\n", src);
    }
    puts("Test Decrypt Key");
    for(int src = 0, goal; src < N; src++)
    {
        printf("src: %4d\t", src);
        goal = RecursionPowMod(src, Decrypt, N);
        printf("goal: %4d\t", goal);
        src = RecursionPowMod(goal, Encrypt, N);
        printf("src: %4d\n", src);
    }
    return 0;
}

顺便也贴一下运行结果= -=~标题就是我的IDE路径,采用32位mingw编译器

最后的最后,这章也没什么好谈的了,代码说明了一切,看一句代码比废话十句更有效吧我认为~
如果有疑问或想要进一步学习的同学可以私聊我=- = 反正我晚上一直都很有空(偶尔会跑去打魔兽吧~)

现在代码放在我的 Github 了,我翻翻 CryptFunction ,包含 ECC 算法的实现(好像)。

原文地址:https://www.cnblogs.com/juwan/p/11449042.html

时间: 2024-10-01 22:57:59

实现 RSA 算法之 C 语言实现(第二章)(老物)的相关文章

算法竞赛入门经典_第二章:循环结构程序设计_上机练习_MyAnswer

习题2-1 位数 输入一个不超过109的正整数,输出它的位数.例如12735的位数是5.请不要使用任何数学函数,只用四则运算和循环语句实现. #include<stdio.h> int main(void) { int n; int digit = 0; scanf("%d",&n); while(n) { n = n / 10; digit++; } printf("%d\n", digit); return 0; } 习题2-2 水仙花数 输

go语言总结第二章

var和const :变量和常量的声明 var varName type 或者 varName : = value package and import: 导入 func: 用于定义函数和方法 return :用于从函数返回 defer someCode :在函数退出之前执行 go : 用于并行 select 用于选择不同类型的通讯 interface 用于定义接口 struct 用于定义抽象数据类型 break.case.continue.for.fallthrough.else.if.swi

《算法导论》读书笔记--第二章

2.1插入排序 伪代码与真代码的区别在于,伪代码我们使用最简洁.最清晰的表示方法来说明给定的算法.这样的原则下,在伪代码中就会出现英语. 插入排序的特点:1.少量元素时,是一种有效的算法:2.直观想象:按顺序排扑克牌:3.是一种原址排序算法,即在同一个数组中完成排序工作.下面是伪代码: //INSERTION-SORT for j = 2 to A.length key = A[j] i = j - 1 while i > 0 and A[i] > key A[i+1] = A[i] i =

《算法导论》读书笔记--第二章 2.2 分析算法

2.2分析算法 分析算法的结果意味着预测算法需要的资源.虽然有时候关心内存.通讯或者计算机硬件,但是通常我们想度量的是时间. 在分析算法之前,要有一个实现技术的模型,包括描述所用资源及其代价的模型.我们假定一种通用的单处理器计算模型—随机访问机(random-access machine,RAM)来作为我们的实现技术,算法可以用计算机程序来实现.在RAM模型中,指令一条接一条执行,并没有并发操作.RAM模型包含真是计算机中常见的指令:算术指令(如加法.减法.乘法.取余.向上取整.向下取整).数据

《算法导论》读书笔记--第二章 2.3 设计算法

我们可以使用的算法设计技术有很多.插入排序用的是增量方法,即在已经排好的数组中不断加入新的元素.下面考虑一种被称为"分治法"的设计方法. 2.3.1分治法 分治法的思想:将原问题分解为几个规模较小但是类似于原问题的子问题,递归地求解这些子问题,然后合并这些子问题的解来建立原问题的解.分治模式在每层递归时有三个步骤: 分解原问题为若干子问题: 解决这些子问题,递归地求解各子问题,若子问题规模足够小,则直接求解: 合并这些子问题的解成原问题的解. 归并排序算法完全遵循分治模式,操作如下:

python语言入门--第二章 类型与操作符

2.1 Python程序结构 Python 可分为模块.语句和对象,程序是由模块组成,模块包含语句,语句生成.处理对象. 2.2 为什么使用内置对象 往往比自己定制的数据结构更有效. 2.3 数字 Python的长整数型(后面跟L或l)可以任意长,可以扩展到内存不允许为止. 普通的整数的精度与C的长整数型一样(至少32位). 八进制和十六进制和C一样,八,0:十六,0x or 0X 复数,实数+虚数J(j),如3+4J Python 特有的部分操作符 x  or y     (只有x为假时,y才

《算法竞赛入门经典》第二章 2.1

程序2-1 1 #include<stdio.h> 2 #include<math.h> 3 int main() 4 { 5 int n; 6 scanf("%d",&n); 7 for(int i=1;i<=n;i++) 8 { 9 printf("%d\n",i); 10 } 11 return 0; 12 13 } 程序2-2 1 #include<stdio.h> 2 #include<math.h&

《算法竞赛入门经典》第二章 2.2

程序2-4 1 #include<stdio.h> 2 #include<math.h> 3 int main() 4 { 5 int n, count = 0; 6 scanf("%d",&n); 7 while(n>1) 8 { 9 if(n % 2 ==1) n = 3*n +1; 10 else n/=2; 11 count++; 12 } 13 printf("%d\n",count); 14 return 0; 15

《算法竞赛入门经典》第二章 2.3

程序2-7 略去 程序2-8 1 #define LOCAL 2 #include<stdio.h> 3 #define INF 100000000 4 int main() 5 { 6 #ifdef LOCAL 7 freopen("data.in","r",stdin); 8 freopen("data.out","w",stdout); 9 #endif // LOCAL 10 int x, n = 0, m