下面计划:1,RSA-OAEP 2,Rabin算法 3,详解中国剩余定理
********************************
鉴于在博客中写公式略显难看,有碍观瞻,博客中的内容我都事先用latex写了一个pdf的文档,可以在下链接下载
http://download.csdn.net/detail/xue_haiyang/7637701
********************************
*******************************\\
由于我对RSA算法比较熟悉,所以决定从RSA下手。由于我的水平有限,下面所写的难免有各种错误,还请留言批评指正(欢迎任意的批评交流)。*******************************\\
随着对算法的了解,我计划分成三个大部分学习这个部分。第一大部分关于RSA基本加密的分析和实现;第二大部分Rabin函数的实现以及Rabin-OAEP的实现;
第三部分 依葫芦画瓢,写个JAVA下自己的大数包。(发现JAVA大数包结构清晰,所以希望自己能通过画瓢更加熟悉JAVA语言)
下面我就第一部分从分成几个章节写。
- RSA加密算法基础
- 基本RSA实现
- 根据中国剩余定理改进
第一部分 RSA加密算法基础
19世纪70年代,现实中,密钥分发是一个很急迫需要。私钥加密方案解决不了这个问题。Diffie 和Hellman就提出了
公钥加密方案的概念。每个人i公开一个公钥 , 同时自己保存一个私钥 . 任何一个希望给i发送信息的人
就使用 加密消息m 得到c,并发送给i . i 拿到c,可以使用 解密出消息m. 下面图示公钥加密方案的模型。
之后RSA三个人就给出了公钥加密方案的实例--RSA加密方案。我首先描述一下方案,然后在分析下方案的正确性。
- 密钥生成 首先生成长度为 的两个大素数P, Q, 令N=PQ,. 选取较小的整数e 满足e 和 是互素的。也就是。 计算.
- 加密 对于明文, 计算密文
- 解密 对于密文c, 计算
下面分析下方案的正确性。对于任意明文空间的$m$,有
我们就有 , 然后就有
- 实际上中的元素的阶是整除的。
- 为了加快加密的速度一般上选择这个素数。下面我会详细说说为什么要选择这样的$e$.
下面就看看怎样使用JAVA实现RSA加密算法。通过搜索发现在JAVA中封装好了一个BigInteger的类,至于该类的API见。
下面是对基本RSA的实现和例子。其中的PQ是使用的RSA公司分解挑战中的一个例子。
</pre><pre code_snippet_id="383363" snippet_file_name="blog_20140609_1_7560533" name="code" class="java">/**********
xuehaiyang@iie.ac.cn
***********/
import java.math.BigInteger;
public class RSATest {
<span style="white-space:pre"> </span>public static void main(String[] args)
<span style="white-space:pre"> </span>{<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//Key generation
<span style="white-space:pre"> </span>// N is the RSA modulo. e is the public key and d is the private key.
BigInteger P = new
BigInteger("398075086424064937397125500550386491199064362342526708406385189575946388957261768583317");
BigInteger Q = new
BigInteger("472772146107435302536223071973048224632914695302097116459852171130520711256363590397527");
BigInteger P1 = new
BigInteger("398075086424064937397125500550386491199064362342526708406385189575946388957261768583316");
BigInteger Q1 = new
BigInteger("472772146107435302536223071973048224632914695302097116459852171130520711256363590397526");
BigInteger N = new BigInteger("33");
BigInteger PiN = new BigInteger("33");
N = P.multiply(Q);
PiN=P1.multiply(Q1);
BigInteger e = new BigInteger("65577");
BigInteger d = e.modInverse(PiN);
System.out.println("d is " + d);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
//encryption; m is the plaintext and c is the ciphertext
BigInteger m = new BigInteger("123456789");
BigInteger c= m.modPow(e, N);
System.out.println("Ciphertext is " + c);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
//decryption; m1 is the plaintext and c is the ciphertext
BigInteger m1 =new BigInteger("987654321");
m1= c.modPow(d, N);
System.out.println("Plaintext is " + m1);
<span style="white-space:pre"> </span>
//Fast decryption with CRT; m2 is the plaintext and c is the ciphertext
BigInteger m2 =new BigInteger("987654321");
m2= ((c.modPow(d, P).multiply(Inv_P_ModQ).multiply(P))
.add(c.modPow(d, Q).multiply(Inv_Q_ModP).multiply(Q))).mod(N);
System.out.println("Plaintext is " + m2);
}
}
RSA跟对称加密算法相比的缺点是效率比较低。这里边$e$选择 的原因是在兼顾安全的前提下增加加密的效率。如果我们记$e=(e_i)$ for $i=0, 1,... ,16$
这里要计算 . 2^{16}+1 只在第一位和最后一位是1,减少乘法的次数。
第三部分: 根据中国剩余定理改进
其实这里边RSA的效率还是比较低,一个好的解决方案是增加解密的速度。使用的方法是中国剩余定理.
解密方在生成私钥的时候,直接计算$P$ mod $Q$的逆和$Q$ mod $P$的逆。如下
/**********
xuehaiyang@iie.ac.cn
***********/
import java.math.BigInteger;
public class RSACRT{
<span style="white-space:pre"> </span>public static void main(String[] args)
<span style="white-space:pre"> </span>{<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//Key generation
<span style="white-space:pre"> </span>// N is the RSA modulo. e is the public key and d,Inv_P_ModQ,Inv_Q_ModP is the private key.
BigInteger P = new
BigInteger("398075086424064937397125500550386491199064362342526708406385189575946388957261768583317");
BigInteger Q = new
BigInteger("472772146107435302536223071973048224632914695302097116459852171130520711256363590397527");
BigInteger Inv_P_ModQ = P.modInverse(Q);
BigInteger Inv_Q_ModP = Q.modInverse(P);
BigInteger P1 = new
BigInteger("398075086424064937397125500550386491199064362342526708406385189575946388957261768583316");
BigInteger Q1 = new
BigInteger("472772146107435302536223071973048224632914695302097116459852171130520711256363590397526");
BigInteger N = new BigInteger("33");
BigInteger PiN = new BigInteger("33");
N = P.multiply(Q);
PiN=P1.multiply(Q1);
BigInteger e = new BigInteger("65577");
BigInteger d = e.modInverse(PiN);
System.out.println("d is " + d);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
//encryption; m is the plaintext and c is the ciphertext
BigInteger m = new BigInteger("123456789");
BigInteger c= m.modPow(e, N);
System.out.println("Ciphertext is " + c);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
//Fast decryption with CRT; m2 is the plaintext and c is the ciphertext
BigInteger m2 =new BigInteger("987654321");
m2= ((c.modPow(d, P).multiply(Inv_P_ModQ).multiply(P))
.add(c.modPow(d, Q).multiply(Inv_Q_ModP).multiply(Q))).mod(N);
System.out.println("Plaintext is " + m2);
}
}