欧拉函数和指数间的关系保证了加密的任意数据都能够唯一地解密回来。为了找出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位的整数。