Skip to content

Commit 04a6b7d

Browse files
committed
RSA初步完成
1 parent 9f25af5 commit 04a6b7d

6 files changed

Lines changed: 584 additions & 0 deletions

File tree

README.md

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,4 +333,194 @@ public class AESDemo {
333333
}
334334
}
335335
336+
```
337+
338+
## 非对称加密
339+
340+
### 1. 对称加密的弊端
341+
342+
- 秘钥分发困难
343+
344+
- 可以通过非对称加密完成秘钥的分发
345+
346+
> https
347+
>
348+
> AliceBob通信, Alice给bob发送数据, 使用对称加密的方式
349+
>
350+
> 1. 生成一个非对称的秘钥对, bob生成
351+
> 2. bob将公钥发送给alice
352+
> 3. alice生成一个用于对称加密的秘钥
353+
> 4. alice使用bob的公钥就对称加密的秘钥进行加密, 并且发送给bob
354+
> 5. bob使用私钥就数据解密, 得到对称加密的秘钥
355+
> 6. 通信的双方使用写好的秘钥进行对称加密数据加密
356+
357+
### 2. 非对称加密的秘钥
358+
359+
- 不存在秘钥分发困难的问题
360+
361+
#### 2.1 场景分析
362+
363+
数据对谁更重要, 谁就拿私钥
364+
365+
- 直观上看: 私钥比公钥长
366+
- 使用第三方工具生成密钥对: 公钥文件xxx.pub xxx
367+
368+
> 1. 通信流程, 信息加密 (A写数据, 发送给B, 信息只允许B读)
369+
>
370+
> A: 公钥
371+
>
372+
> B: 私钥
373+
>
374+
> 2. 登录认证 (客户端要登录, 连接服务器, 向服务器请求个人数据)
375+
>
376+
> 客户端: 私钥
377+
>
378+
> 服务器: 公钥
379+
>
380+
> 3. 数字签名(表明信息没有受到伪造,确实是信息拥有者发出来的,附在信息原文的后面)
381+
>
382+
> - 发送信息的人: 私钥
383+
> - 收到信息的人: 公钥
384+
>
385+
> 4. 网银U盾
386+
>
387+
> - 个人: 私钥
388+
> - 银行拿公钥
389+
390+
### 3. 使用RSA非对称加密通信流程
391+
392+
> 要求: Alice 给 bob发送数据, 保证数据信息只有bob能看到
393+
394+
### 4. 生成RSA的秘钥对
395+
#### 4.1 一些概念
396+
397+
1. x509证书规范、pem、base64
398+
- pem编码规范 - 数据加密
399+
- base64 - 对数据编码, 可逆
400+
- 不管原始数据是什么, 将原始数据使用64个字符来替代
401+
- a-z A-Z 0-9 + /
402+
2. ASN.1抽象语法标记
403+
3. PKCS1标准
404+
405+
### 5. 常见算法
406+
407+
> RSA
408+
409+
> ECC(java需要借助第三方库实现加密解密,我将在另外一个项目中用go实现)
410+
411+
###6 RSA示例代码如下
412+
- 注意:经测试在后端使用Cipher.getInstance(“RSA”)加密,在移动端获取解密的Cipher类时要使用Cipher.getInstance(“RSA/ECB/PKCS1Padding”)
413+
414+
- 移动端核心代码
415+
```$java
416+
//后端用私钥加密过的数据
417+
String eText = "ETLPedgx7vR9E9JGNIj4pLhvurcOM26oo4RgJhmeF5RvDXVdl3qQ+5H6hmUx3dV2K8jPxi5aKSVs1xnjuMgSfK32fjrqzYBULFaBCmnN1HbpcwYFNMA3enWiVwT3TAWFKA9ReJ2DWh0lkCzaHruOmcWCY3f2tjuEE9X9L0DN7m5R9iy2qgEEDPgfzImYYl8wltYdudryz2fQ7UNGdIUPc75EMqdvHEUrxIi5A7cM0BDGQI2aXD+39ijQCOVBtai/9ohF7YXtGmbsocPBKarhe8qpVIcvXza6fBbOWxBC6Z68uRGcljTVkhvNjWrEmRuu5pc3C41bx4OK9FD8kPgITg==";
418+
//后端给的公钥
419+
String pkey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmpz9g5IX3ElRtXFo2+9nwD4+amqhEH4Rz1FI2cXeSiQeLPfdCoSsflLovdJ21NxvcKGw9IvmjWkLESCVU/pxDeP2UkVXFAjC2KhZvoQO4v0x4Yn3/55bAAQ9O3qoGatjPlDbzr1CEAi+ZA7NY1Oz2TtOSq8Odc7wc3Sq6U1gZBf87w5jq0GwQwgLrQjaVf5oTgKmavyf6g8Uq8U0QnktXCJpJUsSSZdeWTwAhtKk+MDkd5VRHIynLklOgeAhjG7xzEAad/Q32qLGcCwY+ySiZWLZ5q5uZAys4rj98LiwV6zLyk8CYYclUDUtBPLLXDRN8DUEe4uKAucFC4IlkrXQ0wIDAQAB";
420+
//获取公钥对象
421+
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
422+
X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(pkey, Base64.DEFAULT));
423+
PublicKey publicKey = keyFactory.generatePublic(spec);
424+
//指定解密algorithm = "RSA/ECB/PKCS1Padding"; Cipher cipher = Cipher.getInstance(algorithm);
425+
algorithm = "RSA/ECB/PKCS1Padding";
426+
String decrypt = RSADemo.RSADecrypt(algorithm, publicKey, eText, 256);
427+
System.out.println("decript###" + decrypt + "###");
428+
```
429+
430+
- 后端代码
431+
```java
432+
public class RSADemo {
433+
private static int MAX_ENCRIPT_SIZE = 200;
434+
435+
public static void main(String[] args) throws Exception {
436+
String algorithm = "RSA";
437+
String input = "frank";
438+
// generateKeys(algorithm, "test.pri", "test.pub");
439+
440+
PrivateKey privateKey = getPrivateKey("test.pri", algorithm);
441+
PublicKey publicKey = getPublicKey("test.pub", algorithm);
442+
443+
String encryptData = RSAEncrypt(algorithm, privateKey, input, MAX_ENCRIPT_SIZE);
444+
System.out.println("encryptData=" + encryptData);
445+
String decryptData = RSADecrypt(algorithm, publicKey, encryptData, 256);
446+
System.out.println("decryptData=" + decryptData);
447+
448+
}
449+
450+
public static PrivateKey getPrivateKey(String priPath, String algorithm) throws Exception {
451+
String privateKeyString = FileUtils.readFileToString(new File(priPath), Charset.defaultCharset());
452+
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
453+
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
454+
return keyFactory.generatePrivate(spec);
455+
}
456+
457+
public static PublicKey getPublicKey(String pubPath, String algorithm) throws Exception {
458+
String publicKeyString = FileUtils.readFileToString(new File(pubPath), Charset.defaultCharset());
459+
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
460+
X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
461+
return keyFactory.generatePublic(spec);
462+
}
463+
464+
public static void generateKeys(String algorithm, String priPath, String pubPath) throws Exception {
465+
// 获取密钥对生成器
466+
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
467+
// 获取密钥对
468+
KeyPair keyPair = keyPairGenerator.generateKeyPair();
469+
// 获取公私钥
470+
PrivateKey privateKey = keyPair.getPrivate();
471+
PublicKey publicKey = keyPair.getPublic();
472+
// 获取公私钥的字节数组
473+
byte[] privateKeyEncoded = privateKey.getEncoded();
474+
byte[] publicKeyEncoded = publicKey.getEncoded();
475+
// 对公私钥进行Base64的编码
476+
String privateKeyString = Base64.encode(privateKeyEncoded);
477+
String publicKeyString = Base64.encode(publicKeyEncoded);
478+
479+
FileUtils.writeStringToFile(new File(priPath), privateKeyString, Charset.defaultCharset());
480+
FileUtils.writeStringToFile(new File(pubPath), publicKeyString, Charset.defaultCharset());
481+
}
482+
483+
public static String RSAEncrypt(String algorithm, Key key, String input, int maxEncryptSize) throws Exception {
484+
Cipher cipher = Cipher.getInstance(algorithm);
485+
cipher.init(Cipher.ENCRYPT_MODE, key);
486+
byte[] data = input.getBytes();
487+
int total = data.length;
488+
int offset = 0;
489+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
490+
byte[] bytes;
491+
while (total - offset > 0) {
492+
if (total - offset >= maxEncryptSize) {
493+
bytes = cipher.doFinal(data, offset, maxEncryptSize);
494+
offset += maxEncryptSize;
495+
} else {
496+
bytes = cipher.doFinal(data, offset, total - offset);
497+
offset = total;
498+
}
499+
baos.write(bytes);
500+
}
501+
return Base64.encode(baos.toByteArray());
502+
}
503+
504+
public static String RSADecrypt(String algorithm, Key key, String input, int maxEncryptSize) throws Exception {
505+
Cipher cipher = Cipher.getInstance(algorithm);
506+
cipher.init(Cipher.DECRYPT_MODE, key);
507+
byte[] data = Base64.decode(input);
508+
int total = data.length;
509+
int offset = 0;
510+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
511+
byte[] bytes;
512+
while (total - offset > 0) {
513+
if (total - offset >= maxEncryptSize) {
514+
bytes = cipher.doFinal(data, offset, maxEncryptSize);
515+
offset += maxEncryptSize;
516+
} else {
517+
bytes = cipher.doFinal(data, offset, total - offset);
518+
offset = total;
519+
}
520+
baos.write(bytes);
521+
}
522+
return baos.toString();
523+
}
524+
525+
}
336526
```

androidcode/MainActivity.java

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package bupin.com.tmpdemo;
2+
3+
import android.support.v7.app.AppCompatActivity;
4+
import android.os.Bundle;
5+
import android.util.Base64;
6+
import android.util.Log;
7+
import android.view.View;
8+
import android.widget.Button;
9+
import android.widget.TextView;
10+
import android.widget.Toast;
11+
12+
import org.apache.commons.io.FileUtils;
13+
14+
import java.io.File;
15+
import java.nio.charset.Charset;
16+
import java.security.KeyFactory;
17+
import java.security.NoSuchAlgorithmException;
18+
import java.security.PrivateKey;
19+
import java.security.PublicKey;
20+
import java.security.spec.InvalidKeySpecException;
21+
import java.security.spec.X509EncodedKeySpec;
22+
23+
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
24+
private static final String TAG = "MainActivity";
25+
private TextView mTv;
26+
private Button mBt1;
27+
private Button mBt2;
28+
private Button mBt3;
29+
30+
@Override
31+
protected void onCreate(Bundle savedInstanceState) {
32+
super.onCreate(savedInstanceState);
33+
setContentView(R.layout.activity_main);
34+
mTv = findViewById(R.id.tv);
35+
mBt1 = findViewById(R.id.bt1);
36+
mBt2 = findViewById(R.id.bt2);
37+
mBt3 = findViewById(R.id.bt3);
38+
mBt1.setOnClickListener(this);
39+
mBt2.setOnClickListener(this);
40+
mBt3.setOnClickListener(this);
41+
}
42+
43+
@Override
44+
public void onClick(View v) {
45+
46+
String algorithm = "RSA";
47+
String input = "frank";
48+
String priPath = this.getFilesDir().getAbsolutePath() + File.separator + "a.pri";
49+
String pubPath = this.getFilesDir().getAbsolutePath() + File.separator + "a.pub";
50+
switch (v.getId()) {
51+
case R.id.bt1:
52+
Log.d(TAG, priPath);
53+
Log.d(TAG, pubPath);
54+
try {
55+
RSADemo.generateKeys(algorithm, priPath, pubPath);
56+
} catch (Exception e) {
57+
e.printStackTrace();
58+
Toast.makeText(this, "生成key出异常了", Toast.LENGTH_SHORT).show();
59+
}
60+
break;
61+
case R.id.bt2:
62+
try {
63+
PrivateKey privateKey = RSADemo.getPrivateKey(priPath, algorithm);
64+
PublicKey publicKey = RSADemo.getPublicKey(pubPath, algorithm);
65+
66+
String encryptData = RSADemo.RSAEncrypt(algorithm, privateKey, input, 245);
67+
Log.d(TAG, "encryptData=" + encryptData);
68+
String decryptData = RSADemo.RSADecrypt(algorithm, publicKey, encryptData, 256);
69+
Log.d(TAG, "decryptData=" + decryptData);
70+
} catch (Exception e) {
71+
e.printStackTrace();
72+
Toast.makeText(this, "加解密出异常了", Toast.LENGTH_SHORT).show();
73+
}
74+
break;
75+
case R.id.bt3:
76+
try {
77+
// String eText = "XURae8f0eiLfhkrFVJ+2Kn1aZ4tIDs4Mo9vVd9tLo2WkpD6e/m2UhUB7KHnMhz0Q3enwpr+hTMEntDFY0ydu0Tk0cHtQeA1PjinhF4N/Z3D73167LDrULVmxvcZYrTA6rY7yj9noK8nqDGa2qNl/IF27+KTjBXxB6Wf1OUYR8Uvk04Yu9X4MU93T/KGRu3+N/ewX8mT6M7b8CFviGG5ADpwglTK6Tl2bt+lylbMDc1wtfnKxGcLCeIxKH9gazytoFP7scrc63lrD5gK3+lhb0nRPSk4v7fCd0+5ILwquQc5IkGuphjneyRSyNPKfpKaZcLKJw9B6YXtJGOQC1V3fFw==";
78+
//后端用私钥加密过的数据
79+
String eText = "ETLPedgx7vR9E9JGNIj4pLhvurcOM26oo4RgJhmeF5RvDXVdl3qQ+5H6hmUx3dV2K8jPxi5aKSVs1xnjuMgSfK32fjrqzYBULFaBCmnN1HbpcwYFNMA3enWiVwT3TAWFKA9ReJ2DWh0lkCzaHruOmcWCY3f2tjuEE9X9L0DN7m5R9iy2qgEEDPgfzImYYl8wltYdudryz2fQ7UNGdIUPc75EMqdvHEUrxIi5A7cM0BDGQI2aXD+39ijQCOVBtai/9ohF7YXtGmbsocPBKarhe8qpVIcvXza6fBbOWxBC6Z68uRGcljTVkhvNjWrEmRuu5pc3C41bx4OK9FD8kPgITg==";
80+
//后端给的公钥
81+
String pkey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmpz9g5IX3ElRtXFo2+9nwD4+amqhEH4Rz1FI2cXeSiQeLPfdCoSsflLovdJ21NxvcKGw9IvmjWkLESCVU/pxDeP2UkVXFAjC2KhZvoQO4v0x4Yn3/55bAAQ9O3qoGatjPlDbzr1CEAi+ZA7NY1Oz2TtOSq8Odc7wc3Sq6U1gZBf87w5jq0GwQwgLrQjaVf5oTgKmavyf6g8Uq8U0QnktXCJpJUsSSZdeWTwAhtKk+MDkd5VRHIynLklOgeAhjG7xzEAad/Q32qLGcCwY+ySiZWLZ5q5uZAys4rj98LiwV6zLyk8CYYclUDUtBPLLXDRN8DUEe4uKAucFC4IlkrXQ0wIDAQAB";
82+
//获取公钥对象
83+
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
84+
X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(pkey, Base64.DEFAULT));
85+
PublicKey publicKey = keyFactory.generatePublic(spec);
86+
//指定解密algorithm = "RSA/ECB/PKCS1Padding"; Cipher cipher = Cipher.getInstance(algorithm);
87+
algorithm = "RSA/ECB/PKCS1Padding";
88+
String decrypt = RSADemo.RSADecrypt(algorithm, publicKey, eText, 256);
89+
System.out.println("decript###" + decrypt + "###");
90+
} catch (Exception e) {
91+
e.printStackTrace();
92+
Toast.makeText(this, "夸平台解密错误", Toast.LENGTH_SHORT).show();
93+
}
94+
break;
95+
}
96+
}
97+
}

0 commit comments

Comments
 (0)