RSA算法Java的简单实现

RSA简介

RSA算法据说是目前地球上最重要的加密算法。维基百科是这么介绍的:“对极大整数做因数分解的难度决定了RSA算法的可靠性。换言之,对一极大整数做因数分解愈困难,RSA算法愈可靠。假如有人找到一种快速因数分解的算法,那么RSA的可靠性就会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA密钥才可能被暴力破解。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。只要密钥长度足够长,用RSA加密的信息实际上是不能被解破的。”

  看上去很神奇是吧,其实在学习网络安全和密码学这门课的时候,都接触过。毕业近一年了,数论方面的知识忘的差不多了。如果大家对RSA算法原理很感兴趣,推荐下面这两篇文章:

http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html

http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html

本文描述下,我自己实现的一个简单的RSA算法。


RSA密钥生成和加密解密过程

   



RSA的具体实现

RSA具体实现的难点在于质数的生成。好在Java提供了一个强大的工具类BigInteger。具体的实现如下

(不过百行):

public class RSA {
	private BigInteger p = null;
	private BigInteger q = null;
	private BigInteger n = null;
	private BigInteger totient = null;
	private BigInteger e = null;
	private BigInteger d = null;
	public RSA(BigInteger p, BigInteger q) {
		this.p = p;
		this.q = q;
		n = p.multiply(q); // n = p * q;//totient =(p-1)*(q-1)即 (n)
		totient = (p.subtract(BigInteger.valueOf(1)).multiply((q
				.subtract(BigInteger.valueOf(1)))));
                e = getE();//选择公钥
		BigInteger y = egcd(totient, e)[1];
                d = y.mod(totient); //产生私钥
	}
	public BigInteger getE() {
		// 这里以totient/4为种子,选取一个素数作为公钥
		return totient.divide(BigInteger.valueOf(4)).nextProbablePrime();
	}
        // 扩展的Euclid算法,目的:算出e-1 mod n
	public static BigInteger[] egcd(BigInteger d1, BigInteger d2) {
		BigInteger[] ret = new BigInteger[3];
		BigInteger u = BigInteger.valueOf(1), u1 = BigInteger.valueOf(0);
		BigInteger v = BigInteger.valueOf(0), v1 = BigInteger.valueOf(1);
		if (d2.compareTo(d1) > 0) {
			BigInteger tem = d1;
			d1 = d2;
			d2 = tem;
		}
		while (d2.compareTo(BigInteger.valueOf(0)) != 0) {
			BigInteger tq = d1.divide(d2); // tq = d1 / d2
			BigInteger tu = u;
			u = u1;
			u1 = tu.subtract(tq.multiply(u1)); // u1 =tu - tq * u1
			BigInteger tv = v;
			v = v1;
			v1 = tv.subtract(tq.multiply(v1)); // v1 = tv - tq * v1
			BigInteger td1 = d1;
			d1 = d2;
			d2 = td1.subtract(tq.multiply(d2)); // d2 = td1 - tq * d2
			ret[0] = u;
			ret[1] = v;
			ret[2] = d1;
		}
		return ret;
	}
        // 加密
	public BigInteger encode(BigInteger d) {
		return d.modPow(this.e, this.n);
	}
        // 解密
	public BigInteger decode(BigInteger c) {
		return c.modPow(this.d, this.n);
	}
}

RSA的缺点

RSA算法使用乘方运算,明文以分组为单位进行加密,每个分组的二进制值均小于n也就是说分组的大

小必须小于等于log2(n)+1位。如果明文分组大于此长度,则需要进一步细分,或者借助另外一种对

称的加密算法来进行加密。此外,RSA加密解密效率不高,特别是密钥长度很长的时候,不适合对大

量信息进行加密。所以一般RSA会和其他对称的加密算法配合使用。

下面是我本科毕设中设计的一个简单的加密方案,以及前几天根据这个方案写的一个demo。


假设客户端要向服务发送数据,首先客户端需要通过用户名和密码生成自己的RSA密钥(用于解密的私

钥cPR),然后通过一个随机数生成这次数据传输的DES密钥deskey_c,除此之外我们还知道服务端的

RSA公钥sPU(服务端的RSA密钥是固定的)。有了这次数据传输的密钥信息之后,客户端就可以将数

据M1通过DES算法用deskey_c加密得到密文C1,然后将客户端生成的DES密钥deskey_c通过RSA算法

用服务端的公钥sPU加密得到加密后的DES密钥c_deskey_c。最后将加密后的信息(密文C1和加密后的

DES密钥c_deskey_c)通过http协议发送到服务端。服务端接收后,先通过自己的私钥sPR将DES密钥

解密出来,得到之前客户端生成的deskey_c,然后通过DES算法用deskey_c解密C1,得到原来的数据

M1。至此,客户端加密服务端解密的过程结束。在加密解密过程中,DES密钥为50位10进制数,RSA

算法中的p和q的范围是0到150位十进制整数。而当服务端向客户端发送数据的时候,同样需要生成密钥

信息。首先服务端通过客户端的用户名和密码得到客户端的RSA公钥cPU,然后通过一个随机数得到这

次数据传输的DES密钥deskey_s,然后通过DES算法用deskey_s将数据M2加密为密文C2,然后通过

RSA算法用客户端的公钥cPU将deskey_s加密为c_deskey_s。最后服务端将密文C2和加密后的DES

密钥c_deskey_s发送给客户端。客户端接收后,先通过RSA算法用自己的私钥cPR解密c_deskey_s,

得到原来服务端生成的DES密钥deskey_s,然后通过DES算法用该密钥解密出原来的数据M2。这样

就完成了服务端加密,客户端解密的过程。


Demo:



附上工程源码(最近加班紧,代码写的不是很好-_-||):

http://download.csdn.net/detail/he_qiao_2010/8548675


猜你喜欢

转载自blog.csdn.net/he_qiao_2010/article/details/44758711
今日推荐