数据加密--详解 RSA加密算法 原理与实现

RSA算法简介

RSA是最流行的非对称加密算法之一。也被称为公钥加密。它是由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)在1977年一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。

RSA是非对称的,也就是用来加密的密钥和用来解密的密钥不是同一个。

和DES一样的是,RSA也是分组加密算法,不同的是分组大小可以根据密钥的大小而改变。如果加密的数据不是分组大小的整数倍,则会根据具体的应用方式增加额外的填充位。

RSA作为一种非对称的加密算法,其中很重要的一特点是当数据在网络中传输时,用来加密数据的密钥并不需要也和数据一起传送。因此,这就减少了密钥泄露的可能性。RSA在不允许加密方解密数据时也很有用,加密的一方使用一个密钥,称为公钥,解密的一方使用另一个密钥,称为私钥,私钥需要保持其私有性。

RSA被认为是非常安全的,不过计算速度要比DES慢很多。同DES一样,其安全性也从未被证明过,但想攻破RSA算法涉及的大数(至少200位的大数)的因子分解是一个极其困难的问题。所以,由于缺乏解决大数的因子分解的有效方法,因此,可以推测出目前没有有效的办法可以破解RSA。

RSA算法基于的原理,基本上来说,加密和解密数据围绕着模幂运算,这是取模计算中的一种。取模计算是整数计算中的一种常见形式。x mod n的结果就是x / n的余数。比如,40 mod 13 = 1,因为40 / 13 = 3,余数为1。模幂运算就是计算ab mod n的过程。

计算公钥和私钥

RSA中的公钥和私钥需要结合在一起工作。公钥用来对数据块加密,之后 ,只有对应的私钥才能用来解密。生成密钥时,需要遵循几个步骤以确保公钥和私钥的这种关系能够正常工作。这些步骤也确保没有实际方法能够从一个密钥推出另一个。

开始前,首先要选择两个大的素数,记为p和q。根据当今求解大数因子的技术水平,这两个数应该至少有200位,这们在实践中才可以认为是安全的。

然后,开始计算n:

n = pq

接下来,选择一个小的奇数e,它将成为公钥的一部分。选择e最需要考虑的重点是它与(p-1)(q-1)不能有相同的因子。换句话说,e与(p-1)(q-1)是互为素数关系的。比如,如果p=11而q=19,那么n=11 X 19=209。这里选择e=17,因为(p-1)(q-1)=10 X 18 =180,而17和180没有相同的因子。通常选择3、17、65、537作为e的值。使用这些值不会对RSA的安全性造成影响,因为解密数据还需要用到私钥。

一旦为e选择了一个值,接下来开始计算相对应的值d,d将成为私钥的一部分。d的值就是计算e的倒数对(p-1)(q-1)的取模结果,公式如下:

d = e-1 mod (p-1)(q-1)

这里d和e是模乘法逆元的关系。

思考一下这个问题:当d为多少时可以满足ed mod (p-1)(q-1) = 1 ?比如在等式 17d mod 180 = 1中,d的一个可能值是53。其他的可能值是233、413、593等。在实践中,可以利用欧几里德算法来计算模乘法逆元。这里就不再展开。

现在有了e和d的值,将(e,n)作为公钥P将(d,n)作为私钥S并保持其不可见。表示为:

P = (e,n) , S = (d,n)

加密方使用P来加密数据,解密方使用S来解密。为了防止就算有人知道了P也无法推算出S,必须保证p和q的值绝对不能暴露

P和S结合在一起提供的安全性来自于一个事实,那就是乘法是一种很好的单向函数。

单向函数是加密技术的基础简单的说,单向函数就是在一个方向上能够很容易算出结果,但反向推导则是不切实际的。比如,在RSA算法中,计算p和q的成绩是一种单向函数,因为尽管计算p和q的成绩很容易,但将n反向因子分解为p和q则是极其耗时的。这里,选择的p和q的值要足够大才可以。

计算P和S的步骤起源于欧拉函数中的一些有趣性质。特别是,这些性质允许对模幂运算做一些有用的操作。

欧拉函数记为φ(n),定义所有小于n的正整数里和n互素的整数的个数

只有当两个整数的唯一公因子为1时,才说这两个整数是互素的。例如,φ(8)=4,因为一共只用4个比8小的整数是互素的,它们是1,3,5,7。

欧拉方程有两个性质对RSA算法来说是特别重要的。

第一,当n是素数时,φ(n)=n-1。这是由于n的唯一因子是1和n,因此,n与之前的所有n-1个正整数都是互素的。

另一个有趣的性质是对于任意小于n且与n互素的正整数a,都有aφ(n) mod n = 1。例如,14 mod 8 = 1, 34 mod 8 = 1, 54 mod 8 = 1, 74 mod 8 = 1。对上述方程两边都乘以a,得到:

(a)(aφ(n) mod n)=a,或者aφ(n)+1 mod n = a

因此,可以得到15 mod 8 = 1, 35 mod 8 = 3, 55 mod 8 = 5, 75 mod 8 = 7。

调整之后得到的等式非常强大。因为对于某些等式c = me mod n,该等于可以让我们找出一个d的值,使得cd mod n = m。

这就是RSA算法中允许加密数据,之后再解密回原文的恒等式。可以按照如下方式表示:

cd mod n = (me)d mod n = med mod n = mφ(n)+1 mod n = m mod n

欧拉函数和指数间的关系保证了加密的任意数据都能够唯一地解密回来。为了找出d的值,解方程d = e-1 φ(n) +1。不巧的是,对于方程d = e-1φ(n)+1不一定总是有整数解。为了解决这种问题,转而计算

d mod φ(n)的值。换句话说,d = (e-1 φ(n) + 1) mod φ(n),可以简化为:

d = e-1 mod φ(n)

我们可以得到这样的简化形式,因为(φ(n)+1) mod φ(n) = (φ(n)+1) - φ(n) = 1。可以用任意的正整数替代φ(n)来证明等式成立。注意这个方程式同之前计算密钥的过程中得出d的推导式之间的相似之处。这提供了一种通过e和n来计算d的方法。当然了,e和n是公开的,对于攻击者来说是事先可知的,因此就有人问,这难道不是给了攻击者相同的机会来计算出私钥吗?讨论到这里,是时候来探讨一下RSA算法安全性保障的由来了。

RSA算法的安全性保障来自一个重要的事实,那就是欧拉函数是乘法性质的。这意味着如果p和q是互素的,那么有φ(pq)=φ(p)φ(q)。因此,如果有两个素数p和q,且n=p*q,则φ(n)=(p-1)(q-1),而且最重要的是:

d = e-1 mod (p-1)(q-1)

因此,尽管攻击者可能知道了e和n的值,为了计算出d必须知道φ(n),而这又必须同时得到p和q的值才能办到。由于p和q是不可知的,因此攻击者只能计算n的因子,只要给出的p和q的值足够大,这就是一个相当耗费时间的过程。

加密和解密数据分组

要使用RSA算法对数据进行加密和解密,首先要确定分组的大小。为了实现这一步,必须确保该分组可以保存的最大数值要小于n的位数。比如,如果p和q都是200位数字的素数,则n的结果将小于400位。因而,所选择的分组所能保存的最大值应该要以是接近于400。在实践中,通常选择的位数都是比n小的2的整数次幂。比如,如果n是209,要选择的分组大小就是7位,因为27 = 128比209小,但28 = 256又大于209。

要从缓冲区M中加密第(i)组明文Mi ,使用公钥(e,n)来获取M的数值,对其求e次幂,然后再对n取模。这将产生一组密文Ci对n的取模操作确保了Ci将和明文的分组大小保持一致。因而,要加密明文分组有:

Ci = Mie mod n

之前提到过,欧拉函数是采用幂模运算来加密数据的基础,根据欧拉函数及其推导式,能够将密文解密回原文。

要对缓冲区中C中的第(i)组密文进行解密,使用私钥(d,n)来获取Ci的数值部分,对其求d次幂,然后再对n取模。这将产生一组明文Mi。因此,要解密密文分组有:

Mi = Cid mod n

RSA的接口定义

rsa_encipher



 void rsa_encipher(Huge plaintext, Huge *ciphertext, RsaPubKey pubkey);

返回值:无

描述采用RSA算法来加密由plaintext所指定的明文分组

pubkey是所指定的公钥(e,n),其类型为结构体RsaPubKey。

ciphertext是返回的同plaintext同样大小的密文分组。由调用者负责管理ciphertext所关联的存储空间。要加密大段的数据,可以按照前面介绍的分组加密模式来调用rsa_encipher。

复杂度:O(1)

rsa_decipher



 void rsa_decipher(Huge ciphertext, Huge *plaintext, RsaPriKey prikey)

返回值:无

描述:采用RSA算法来解密由ciphertext所指定的密文分组。

prikey是所指定的私钥(d,n),其类型为结构体RsaPriKey。

plaintext是返回的同ciphertext同样大小的明文分组。由调用者负责管理plaintext所关联的存储空间。要解密大段的数据,可以按照前面介绍的分组加密模式来调用rsa_decipher。

复杂度:O(1)

RSA算法的实现与分析

因为RSA加密算法需要的只不过是计算ab mod n,所以基本的实现是比较简单的。关键的是计算幂模的函数。

但是,要使RSA的安全性得到保障,必须使用很大的整数,这就使得事情变得复杂了。特别是,所有的计算中使用到的整数位数必须是密钥位数的2倍(稍后将在幂模计算中看到)。因此,如果密钥是一个200位的整数,就需要一个抽象数据类型来支持至少400位的整数。

关于大数运算已经有一些可用的函数库。这里不再提供具体的实现。在数据加密头文件的示例中,定义了数据类型Huge,在安全的实现中,可以为Huge类型指定typedef别名以支持所选择的大整数抽象数据类型。其他的需求就只剩下替换整数计算中的运算符为Huge类型所支持的操作。为了达到说明的目的,在这里的实现中Huge类型用typedef定义为unsigned long,这种C语言内置的类型通常只能提供10位十进制数的支持。这意味着稍后的实现示例给出的实现只能支持最多5位整数的密钥。因此,虽然示例中的实现是可用的,但如果不把Huge重定义为大数类型,这个实现就不是安全的。

rsa_encipher

rsa_encipher函数采用RSA算法将明文分组加密。

通过调用函数modexp来计算ab mod n的值,这里a代表明文分组,b和n代表公钥的e和n成员。为了提高执行效率,modexp使用称为二进制平方-乘的算法来计算模幂。

二进制平方-乘算法避免了当a和b都很大时计算ab时会出现的超大中间值。比如,假设当a、b和n都是包含200位数字的超大整数,计算ab mod n,其结果是一个40 000位的整数对200位的整数取模!因为最终得到的结果就是一个200位的整数,那么这里的目的就是要避免出现40 000位的整数的中间值。

用二进制平方-乘算法计算ab mod n,主要是多个开平方运算的结果(如下图)。首先,将b表示为二进制形式,然后从右边的位开始处理对于b中的每一位,求出a的平方对n取模的结果,并将这个结果赋给a每当遇到b中为1的位时,就将当前的a值乘上另一个寄存器y(初始值为1),并将结果再赋给y一旦迭代至b的最高有效位,y的值就是ab mod n的结果。在整个计算过程中,产生的最大值是a2。因此,如果a是一个包含200位数字的整数,就不用处理大于400位的数字了。这相对于前面提到过的包含40 000位数字的整数来说已经是很大的优化了。下图中的阴影部分展示了计算511 mod 53 = 48 828 125 mod 53 = 20的过程。在这个计算过程中,相比511 = 48 828 125,所处理的最大数值只有422 =  1764。

图示:采用二进制平方-乘算法来计算模幂

rsa_encipher的时间复杂度为O(1),因为加密一个明文分组的所有步骤都能在恒定的时间内完成。由于分组的大小是固定的,因此modexp中的循环执行时间也是恒定的。

rsa_decipher

rsa_decipher函数采用RSA算法将密文分组进行解密

该操作通过调用modexp来解密。modexp计算ab mod n的结果,这里a是密文分组,b和n代表私钥成员d和n。处理过程同rsa_decipher中描述的一样。

rsa_decipher的时间复杂度为O(1),因为解密密文分组的所有步骤都可以在恒定的时间内完成。由于分组大小固定,因此,modexp中的循环执行时间也是恒定的。

示例:数据加密的头文件代码

/*encrypt.h*/
#ifndef ENCRYPT_H
#define ENCRYPT_H

/*在一个安全实现中,Huge 最少要400位10进制数字*/
typedef unsigned long Huge; 

/*为RSA公钥定义一个数据结构*/
typedef struct RsaPubKey_
{
    Huge e;
    Huge n;
}RsaPubkey;

/*为RSA私钥定义一个数据结构*/
typedef struct RsaPriKey_
{
    Huge d;
    Huge n;
}RsaPriKey;

/*函数声明*/
void des_encipher(const unsigned char *plaintext, unsigned char *ciphertext, const unsigned char *key);
void des_decipher(const unsigned char *ciphertext, unsigned char *plaintext, const unsigned char *key);
void rsa_encipher(Huge plaintext, Huge *ciphertext, RsaPubKey pubkey);
void rsa_decipher(Huge ciphertext,Huge *plaintext, RsaPriKey prikey);

#endif // ENCRYPT_H

示例:RSA算法的实现

/*rsa.c RSA算法实现*/
#include "encrypt.h"

/*modexp 二进制平方乘算法函数*/
static Huge modexp(Huge a, Huge b, Huge n)
{
    Huge y;

    /*使用二进制平方乘法计算 pow(a,b) % n*/
    y=1;

    while(b != 0)
    {
        /*对于b中的每个1,累加y*/

        if(b & 1)
            y = (y*a) % n;

        /*对于b中的每一位,计算a的平方*/
        a = (a*a) % n;

        /*准备b中的下一位*/
        b = b>>1;
    }

    return y;
}

/*rsa_encipher RSA算法加密*/
void rsa_encipher(Huge plaintext, Huge *ciphertext, RsaPubKey pubkey)
{
    *ciphertext = modexp(plaintext, pubkey.e, pubkey.n);
    return;
}

/*rsa_decipher RSA算法解密*/
void rsa_decipher(Huge ciphertext, Huge *plaintext, RsaPriKey prikey)
{
    *plaintext = modexp(ciphertext, prikey.d, prikdy.n);
    return;
}

原文地址:https://www.cnblogs.com/idreamo/p/9411265.html

时间: 2024-10-02 17:29:37

数据加密--详解 RSA加密算法 原理与实现的相关文章

密码疑云 (3)——详解RSA的加密与解密

上一篇文章介绍了RSA涉及的数学知识,本章将应用这些知识详解RSA的加密与解密. RSA算法的密钥生成过程 密钥的生成是RSA算法的核心,它的密钥对生成过程如下: 1. 选择两个不相等的大素数p和q,计算出n=pq,n被称为RSA算法的公共模数: 2. 计算n的欧拉数φ(n),φ(n)=(p-1)(q-1): 3. 随机选择一个整数e作为公钥加密密钥指数,1< e < φ(n),且e与φ(n)互质: 4. 利用同余方程ed≡1 (mod φ(n))计算e对应的私钥解密指数d.由于GCD(e,

轻松学习RSA加密算法原理

以前也接触过RSA加密算法,感觉这个东西太神秘了,是数学家的事,和我无关.但是,看了很多关于RSA加密算法原理的资料之后,我发现其实原理并不是我们想象中那么复杂,弄懂之后发现原来就只是这样而已.. 学过算法的朋友都知道,计算机中的算法其实就是数学运算.所以,再讲解RSA加密算法之前,有必要了解一下一些必备的数学知识.我们就从数学知识开始讲解. 必备数学知识 RSA加密算法中,只用到素数.互质数.指数运算.模运算等几个简单的数学知识.所以,我们也需要了解这几个概念即可. 素数 素数又称质数,指在一

【java项目实践】详解Ajax工作原理以及实现异步验证用户名是否存在+源码下载(java版)

一年前,从不知道Ajax是什么,伴随着不断的积累,到现在经常使用,逐渐有了深入的认识.今天,如果想开发一个更加人性化,友好,无刷新,交互性更强的网页,那您的目标一定是Ajax. 介绍 在详细讨论Ajax是什么之前,先让我们花一分钟了解一下Ajax做什么.如图所示: 如上图展示给我们的就是使用Ajax技术实现的效果.伴随着web应用的越来越强大而出现的是等待,等待服务器响应,等待浏览器刷新,等待请求返回和生成新的页面成为了程序员们的最最头疼的难题.随着Ajax的出现使web应用程序变得更完善,更友

CDN技术详解及实现原理

CDN技术详解 一本好的入门书是带你进入陌生领域的明灯,<CDN技术详解>绝对是带你进入CDN行业的那盏最亮的明灯.因此,虽然只是纯粹的重点抄录,我也要把<CDN技术详解>的精华放上网.公诸同好. 第一章    引言    “第一公里”是指万维网流量向用户传送的第一个出口,是网站服务器接入互联网的链路所能提供的带宽.这个带宽决定了一个 网站能为用户提供的访问速度和并发访问量.如果业务繁忙,用户的访问数越多,拥塞越严重,网站会在最需要向用户提供服务时失去用户.(还有“中间一公里” 和

BadVPN详解之--组网原理剖析

这可能是第一篇关于BadVPN原理的中文介绍,所以我恪守职责,希望能将BadVPN的原理阐述清楚,而不仅仅是为了欺世盗名取天下之先. 序:格尔上市 这一段插在这里有点突兀,与BadVPN无关,只是我的一点实感,忽略即可.       明天小小要去厦门演出,今天是什么日子?是小小准备且出发的日子.但是同样在今天,也就是2017年4月21日(写完本文时估计已经到了22日...),上海格尔软件股份有限公司成功上市了.也许你不知道这个公司,确实这公司的业务是很小众,不像BAT布局那般宏大,但这并不意味着

初级游戏外挂编程详解 windows运行原理+游戏辅助编程 游戏外挂编程

详解游戏辅助编程 [目录] 1-什么是Windows API 2-Windows进程 3-Windows 的内存的运行原理 4-windows 中句柄的概念 5-Windows的变量类型 6-辅助实现的原理 7-编程实现游戏辅助 8-怎样查找内存地址 9-总结 准备软件:VC,CheatEngineer5.5 学习这部分内容,你必须要掌握C语言的基础知识,非常基础的语法就行了.这篇文章的内容适合刚开始接触编程的人,高手请飘过. [1]什么是windows API Windows API 中文翻译

纯干货详解iptables工作原理以及使用方法

简介 网络中的防火墙,是一种将内部和外部网络分开的方法,是一种隔离技术.防火墙在内网与外网通信时进行访问控制,依据所设置的规则对数据包作出判断,最大限度地阻止网络中不法分子破坏企业网络,从而加强了企业网络安全. 防火墙的分类 硬件防火墙,如思科的ASA防火墙,H3C的Secpath防火墙等软件防火墙,如iptables.firewalld等 Linux包过滤防火墙简介 1.Linux操作系统中默认内置一个软件防火墙,即iptables防火墙2.netfilter位于Linux内核中的包过滤功能体

HTTP详解1-工作原理

1. HTTP简介 HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议.它可以使浏览器更加高效,使网络传输减少.它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等. 在了解HTTP如何工作之前,我们先了解计算机之间的通信. 2. 计算机相互之间的通信 互联网的关键技术就是TCP/IP协议.两台计算机之间的通信是通过TCP/IP协议在因特网上进行的.

详解HTTPS加速原理

HTTPS是什么? http叫超文本传输协议,使用TCP端口80,默认情况下数据是明文传送的,数据可以通过抓包工具捕获到,因此在interner上,有些比较重要的站点的http服务器需要使用PKI(公钥基础结构)技术来对数据加密!这也就是HTTPS了: HTTPS叫安全的超文本传输协议,使用TCP端口443,他的数据会用PKI中的公钥进行加密,这样抓包工具捕获到的数据包也没有办法看包中的内容,安全性大大提高,要解密数据的话就要用到PKI中的私钥.所以一些安全性比较高的网站如:网上银行,电子商务网