本文旨在说明RSA加密算法的原理及实现,而其相关的数学部分的证实则不是本文内容。html
著做权归做者全部。java
商业转载请联系做者得到受权,非商业转载请注明出处。算法
做者:Coding-Naga安全
发表日期: 2016年2月29日网络
本文连接:http://blog.csdn.net/lemon_tree12138/article/details/50696926dom
来源:CSDN
函数
更多内容:分类 » 数据加密与信息安全加密
1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,能够实现非对称加密。这种算法用他们三我的的名字命名,叫作RSA算法。从那时直到如今,RSA算法一直是最广为使用的"非对称加密算法"。绝不夸张地说,只要有计算机网络的地方,就有RSA算法。spa
-- 摘自网络.net
此部分旨在补充本文的完整性。若是说你已经了解,或是不想了解此部份内容。那么能够直接跳过此部分的阅读。
虽然说只是补充说明(只能是补充的缘由是由于博主的数学也是比较差的-_-!!!),可是此部分的内容倒是至关重要的。博主仍是但愿能够从新阅读一下此部分。
从小学开始,咱们就了解了什么是质数。互质是针对多个数字而言的,若是两个正整数,除了1之外,没有其余公因子,那么就称这两个数是互质关系(注意,这里并无说这两个数必定是质数或有一个为质数。好比15跟4就是互质关系)。如下有一些关于质数与互质的性质:
欧拉函数是求小于x而且和x互质的数的个数。其通式为:φ(x) = x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn)。
其中p1, p2……pn为x的全部质因数,x是不为0的整数。看到这里是否是有一些头疼,太理论的东西的确不够具象。咱们且不去理会后面公式计算与论证,由于已经超出本文的范围了。就前一句来讲说吧,欧拉函数是求小于x而且和x互质的数的个数。这里我能够列举一个例子:
令x = 16,那么x的全部质因数为:φ(16) = 16 * (1 - 1/2) = 8
咱们也能够枚举出全部比16小,且与16互质的数:1, 3, 5, 7, 9, 11, 13, 15
如今也给出部分欧拉函数的性质:
欧拉函数更多参考请见这里的连接。
定义:若是两个正整数a和n互质,那么必定能够找到整数b,使得 ab-1 被n整除,或者说ab被n除的余数是1。
关于模反元素的求解,使用的是朴素的解法。若是读者想要更进一步了解的话,请自行搜索其余解法(好比:展转相除法、欧几里德算法)。
在RSA原理以前,我想仍是有必要了解一下非对称加密算法的加密跟解密过程。下面就是一幅非称加密算法的流程图。
在此能够看到,非对称加密是经过两个密钥(公钥-私钥)来实现对数据的加密和解密的。公钥用于加密,私钥用于解密。对于非对称的加密和解密为何可使用不一样的密钥来进行,这些都是数学上的问题了。不一样的非对称加密算法也会应用到不一样的数学知识。上面也对RSA中使用的数学问题作了一个小小的介绍。如今就来看看RSA算法是怎么来对数据进行加密的吧,以下是一幅RSA加密算法流程及加密过程图。
就以上图中的Bob和Alice来举例吧。
如今Alice经过密钥生成器生成了一对密钥(公钥-私钥)。只把公钥对外公开了。并说,你有什么要跟我说的,就用模幂运算和公钥加密后发给我吧。
此时,Bob已经得到了Alice发布的公钥。使用模幂运算对明文进行了加密,就把加密后的密文发送给了Alice。
Alice得到Bob发来的密文并无使用公钥对密文进行解密,并得到了明文。由于解密过程须要使用的密钥是私钥。
下面的代码只是根据RSA算法的定义,使用Java开发语言实现。且这里只是展现了一些关键步骤,完整过程能够参见下面的源码下载文档。
public class RSA { /** * 得到(公/私)密钥 */ public final Map<String, RSAKey> getCipherKeys() { ... int[] primes = getRandomPrimes(2); int modulus = modulus(primes[0], primes[1]); int euler = euler(primes[0], primes[1]); int e = cipherExponent(euler); int inverse = inverse(euler, e); publicKey.setExponent(e); publicKey.setModulus(modulus); privateKey.setExponent(inverse); privateKey.setModulus(modulus); ... } /** * 加密 */ public int encode(int plaintext, RSAPublicKey key) { return modularPower2(plaintext, key.getExponent(), key.getModulus()); } /** * 解密 */ public int decode(int chipertext, RSAPrivateKey key) { return modularPower2(chipertext, key.getExponent(), key.getModulus()); } // 随机生成count个素数 private final int[] getRandomPrimes(int count) { ... try { primeLabels = FileReadUtils.readLines("./data/prime_table"); } catch (IOException e) { e.printStackTrace(); } for (int i = 0; i < primes.length; i++) { primes[i] = Integer.parseInt(primeLabels.get(indexs.get(i))); } return primes; } // 计算公共模数 private final int modulus(int p, int q) { return p * q; } // 计算欧拉数 private final int euler(int p, int q) { return (p - 1) * (q - 1); } // 计算加密指数 private final int cipherExponent(int euler) { Random random = new Random(); int e = 7; do { e = random.nextInt(euler - 1); } while (!isCoprime(e, euler) || e <= 1); return e; } // 判断两个数互素 private final boolean isCoprime(int number1, int number2) { int sqrt = (int) Math.sqrt(Math.max(number1, number2)); for (int i = 2; i <= sqrt; i++) { if (number1 % i == 0 && number2 % 2 == 0) { return false; } } return true; } // 计算“模的逆元” // (d * e) ≡ 1 mod euler private final int inverse(int euler, int e) { ... while (flag) { q = m[2] / n[2]; for (int i = 0; i < 3; i++) { temp[i] = m[i] - q * n[i]; m[i] = n[i]; n[i] = temp[i]; } if (n[2] == 1) { if (n[1] < 0) { n[1] = n[1] + euler; } return n[1]; } if (n[2] == 0) { flag = false; } } return 0; } // 模幂运算 private final int modularPower(int base, int e, int modular) { int result = 1; do { if (isOdd(e)) { result = (result * (base % modular)) % modular; e -= 1; } else { base = (base * base) % modular; e /= 2; } } while (e > 0); result %= modular; return result; } }