RSA原理
在RSA原理之前,我想还是有必要了解一下非对称加密算法的加密跟解密过程。下面就是一幅非称加密算法的流程图。
在此可以看到,非对称加密是通过两个**(公钥-私钥)来实现对数据的加密和解密的。公钥用于加密,私钥用于解密。对于非对称的加密和解密为什么可以使用不同的**来进行,这些都是数学上的问题了。不同的非对称加密算法也会应用到不同的数学知识。上面也对RSA中使用的数学问题做了一个小小的介绍。现在就来看看RSA算法是怎么来对数据进行加密的吧,如下是一幅RSA加密算法流程及加密过程图。
RSA应用
1. 实例模型
就以上图中的Bob和Alice来举例吧。
现在Alice通过**生成器生成了一对**(公钥-私钥)。只把公钥对外公开了。并说,你有什么要跟我说的,就用模幂运算和公钥加密后发给我吧。
此时,Bob已经获得了Alice发布的公钥。使用模幂运算对明文进行了加密,就把加密后的密文发送给了Alice。
Alice获得Bob发来的密文并没有使用公钥对密文进行解密,并获得了明文。因为解密过程需要使用的**是私钥。
2. RSA算法实现
下面的代码只是根据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;
- }
- }
RSA加密:非对称**,公开**算法
RSA加密利用了单向函数正向求解很简单,反向求解很复杂的特性。具体是利用了:
1.对两个质数相乘容易,而将其合数分解很难的这个特点进行的加密算法。 n=p1*p2,已知p1、p2求n简单,已知n求p1、p2困难。
2.(m^e) mod n=c,已知m、e、n求c简单,已知e、n、c求m很难。
RSA加密,实现了公开**,就是A可以给所有人发送锁,其他人把要加密的信息用这把锁加密后发送给A,A用自己的钥匙开锁就可以获得加密的信息了。反过来,A要发送加密信息给B,只要知道B的锁就可以了,而这个锁是公开的。
公开**n、e的生成:随机选取两个质数p1、p2,n=p1*p2,再随机选取一个整数e,e与φ(n)互质。
加密过程:(m^e) mod n=c,其中m为原信息,c为加密信息,n、e为公开**。
解密过程:(c^d) mod n=m,其中d为解***。
解***d的求解:
(c^d) mod n=(((m^e) mod n)^d) mod n=((m^e)^d) mod n=(m^ed) mod n=m ①
根据费马定理(m^φ(n)) mod n≡1,又1^k≡1,所以(m^k*φ(n)) mod n≡1,两边同乘以m得m*((m^k*φ(n)) mod n)≡1*m,化简(m^(k*φ(n)+1)) mod n≡m ②
由①、②得ed=(k*φ(n)+1),解得d=(k*φ(n)+1)/e。
费马定理:若p是素数,a与p互素,则a^(p-1)≡1 (mod p)
过程如下:
A:有一个公钥n、e。例如:3127、3。
B:有一个信息m。例如:89。
C:偷听者
A:
第一步:随机找两个质数p1、p2,一个奇数e。例如:53、59、3。
第二步:计算n=p1*p2得到n,计算欧拉函数φ(n)=(p1-1)*(p2-1)得到φ(n),计算钥匙d=(k*φ(n)+1)/e得到d。例如:53*59=3127、(53-1)*(59-1)=3016、(k*φ(n)+1)/e=(2*3016+1)/3=2011。
第三步:发送n、e给大家知道 //n、e就是公钥也做锁,d就是n、e的钥匙。
C:获得n、e
B:
第一步:获得n、e
第二步:加密信息m,(m^e) mod n=c,获得加密信息c。例如:(89^3) mod 3127=1394。
第三步:发送c给A
C:
第一步:截获加密信息c
第二步:**信息c,此时C只有n、e、c,只有把n分解质因数才能**,而此分解很困难特别是当n很大的时候。
A:
第一步:收到加密信息c
第二步:解密信息c,(c^d) mod n=m,获得信息m。例如:(1394^2011) mod 3127=89。
完成
2.。。。。。。。。。。。。。。
们来回顾一下RSA的加密算法。我们从公钥加密算法和签名算法的定义出发,用比较规范的语言来描述这一算法。
RSA公钥加密体制包含如下3个算法:******(**生成算法),Encrypt(加密算法)以及Decrypt(解密算法)。
-
。**生成算法以安全常数
作为输入,输出一个公钥PK,和一个私钥SK。安全常数用于确定这个加密算法的安全性有多高,一般以加密算法使用的质数p的大小有关。
越大,质数p一般越大,保证体制有更高的安全性。在RSA中,**生成算法如下:算法首先随机产生两个不同大质数p和q,计算N=pq。随后,算法计算欧拉函数
。接下来,算法随机选择一个小于
的整数e,并计算e关于
的模反元素d。最后,公钥为PK=(N, e),私钥为SK=(N, d)。
-
。加密算法以公钥PK和待加密的消息M作为输入,输出密文CT。在RSA中,加密算法如下:算法直接输出密文为
-
。解密算法以私钥SK和密文CT作为输入,输出消息M。在RSA中,解密算法如下:算法直接输出明文为
。由于e和d在
下互逆,因此我们有:
所以,从算法描述中我们也可以看出:公钥用于对数据进行加密,私钥用于对数据进行解密。当然了,这个也可以很直观的理解:公钥就是公开的**,其公开了大家才能用它来加密数据。私钥是私有的**,谁有这个**才能够解密密文。否则大家都能看到私钥,就都能解密,那不就乱套了。
=================分割线=================
我们再来回顾一下RSA签名体制。签名体制同样包含3个算法:******(**生成算法),Sign(签名算法),Verify(验证算法)。
-
。**生成算法同样以安全常数
作为输入,输出一个公钥PK和一个私钥SK。在RSA签名中,**生成算法与加密算法完全相同。
-
。签名算法以私钥SK和待签名的消息M作为输入,输出签名
。在RSA签名中,签名算法直接输出签名为
。注意,签名算法和RSA加密体制中的解密算法非常像。
-
。验证算法以公钥PK,签名
以及消息M作为输入,输出一个比特值b。b=1意味着验证通过。b=0意味着验证不通过。在RSA签名中,验证算法首先计算
,随后对比M'与M,如果相等,则输出b=1,否则输出b=0。注意:验证算法和RSA加密体制中的加密算法非常像。
所以,在签名算法中,私钥用于对数据进行签名,公钥用于对签名进行验证。这也可以直观地进行理解:对一个文件签名,当然要用私钥,因为我们希望只有自己才能完成签字。验证过程当然希望所有人都能够执行,大家看到签名都能通过验证证明确实是我自己签的。