├── README.md
├── src
└── main
│ └── java
│ └── com
│ └── baixing
│ ├── IOUtil.java
│ ├── EncryptLicense.java
│ ├── LicenseGen.java
│ ├── AES.java
│ ├── Main.java
│ └── RSAUtil.java
└── pom.xml
/README.md:
--------------------------------------------------------------------------------
1 | ## Example
2 | Generate RSA Key first.
3 |
4 | Replace `/opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub` with your public key.
5 |
--------------------------------------------------------------------------------
/src/main/java/com/baixing/IOUtil.java:
--------------------------------------------------------------------------------
1 | package com.baixing;
2 |
3 | import java.io.Closeable;
4 | import java.io.IOException;
5 |
6 | public class IOUtil {
7 | public static void closeIgnoreError(Closeable... closeables) {
8 | for (Closeable c : closeables) {
9 | if (c != null) {
10 | try {
11 | c.close();
12 | } catch (IOException ex) {
13 | // ignore error
14 | }
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/baixing/EncryptLicense.java:
--------------------------------------------------------------------------------
1 | package com.baixing;
2 |
3 | public class EncryptLicense {
4 | String data;
5 | String key;
6 | String iv;
7 |
8 | public EncryptLicense(String data, String key, String iv) {
9 | this.data = data;
10 | this.key = key;
11 | this.iv = iv;
12 | }
13 |
14 | public String getData() {
15 | return data;
16 | }
17 |
18 | public void setData(String data) {
19 | this.data = data;
20 | }
21 |
22 | public String getKey() {
23 | return key;
24 | }
25 |
26 | public void setKey(String key) {
27 | this.key = key;
28 | }
29 |
30 | public String getIv() {
31 | return iv;
32 | }
33 |
34 | public void setIv(String iv) {
35 | this.iv = iv;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.baixing
8 | Gitlab-License
9 | 1.0-SNAPSHOT
10 |
11 |
12 | org.bouncycastle
13 | bcprov-jdk15on
14 | RELEASE
15 |
16 |
17 | com.alibaba
18 | fastjson
19 | [1.2.31,)
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/main/java/com/baixing/LicenseGen.java:
--------------------------------------------------------------------------------
1 | package com.baixing;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 |
5 | import java.util.Base64;
6 | import java.util.Random;
7 |
8 | public class LicenseGen {
9 | public static String GITLAB_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Hxv3MkkZbMrKtIs6np9\n" +
10 | "ccP4OwGBkNhIvhPjcQP48hbbascv5RqsOquQGrYSD2ZrE/kbkRdkIcoHEeTZLif+\n" +
11 | "bDKFZFI7o5x0H92o9/GSvxHJhQ8mkmvwxD7lssGShwZEm8WG+U7BZqUV/gGmCDqe\n" +
12 | "9W8H8Fq2B0ck8IXjbQ4Zz+JlyV/NHZTZcs69plFiLKh4N6GYVftOVwSomh0bbypP\n" +
13 | "OB9WnLC7RC9a2LRrhtf8sqa2rRFmtyMMfgFFzLMzS+w+1K4+QLnWP1gKQVzaFnzk\n" +
14 | "pnwKPrqbGFYbRztIVEWbs8jPYlLkGb8ME4C84YVtQgbQcbyisU/VW3wUGkhT+J0k\n" +
15 | "xwIDAQAB";
16 |
17 | private static String IVPARAMETER = "0102030405060708";
18 |
19 | static String decrypt(String license, String publicKey) throws Exception {
20 | byte[] dataBytes = Base64.getMimeDecoder().decode(license);
21 | JSONObject jsonObject = JSONObject.parseObject(dataBytes,JSONObject.class);
22 | System.out.println(jsonObject);
23 | byte[] encryptedData = Base64.getMimeDecoder().decode(jsonObject.getString("data"));
24 | byte[] encryptedKey = Base64.getMimeDecoder().decode(jsonObject.getString("key"));
25 | byte[] aesIv = Base64.getMimeDecoder().decode(jsonObject.getString("iv"));
26 |
27 | byte[] aesKey = RSAUtil.decryptByPublicKey(encryptedKey,publicKey);
28 |
29 | return AES.Decrypt(encryptedData,aesKey,aesIv);
30 | }
31 |
32 | static String encrypt(String license, String privateKey) throws Exception{
33 | byte[] key = new byte[16];
34 | new Random().nextBytes(key);
35 | byte[] bIv = IVPARAMETER.getBytes();
36 | byte[] encryptedData = AES.Encrypt(license,key, bIv);
37 | byte[] encryptedKey = RSAUtil.encryptByPrivateKey(key,Base64.getMimeDecoder().decode(privateKey));
38 | EncryptLicense encryptLicense = new EncryptLicense(Base64.getMimeEncoder().encodeToString(encryptedData), Base64.getMimeEncoder().encodeToString(encryptedKey),Base64.getMimeEncoder().encodeToString(bIv));
39 |
40 | return Base64.getMimeEncoder().encodeToString(JSONObject.toJSONBytes(encryptLicense));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/baixing/AES.java:
--------------------------------------------------------------------------------
1 | package com.baixing;
2 |
3 | import javax.crypto.Cipher;
4 | import javax.crypto.spec.IvParameterSpec;
5 | import javax.crypto.spec.SecretKeySpec;
6 | import java.util.Base64;
7 |
8 | public class AES {
9 | //偏移量
10 | private static String IVPARAMETER = "0102030405060708";
11 | // 加密
12 | public static String Encrypt(String sSrc, String sKey) throws Exception {
13 | if (sKey == null) {
14 | System.out.print("Key为空null");
15 | return null;
16 | }
17 | // 判断Key是否为16位
18 | if (sKey.length() != 16) {
19 | System.out.print("Key长度不是16位");
20 | return null;
21 | }
22 | byte[] raw = sKey.getBytes("utf-8");
23 | SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
24 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
25 | IvParameterSpec iv = new IvParameterSpec(IVPARAMETER.getBytes());
26 | cipher.init(Cipher.ENCRYPT_MODE, skeySpec,iv);
27 | byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));
28 |
29 | return Base64.getEncoder().encodeToString(encrypted);//此处使用BASE64做转码功能,同时能起到2次加密的作用。
30 | }
31 |
32 | public static byte[] Encrypt(String sSrc, byte[] bKey, byte[] bIv) throws Exception {
33 | if (bKey == null) {
34 | System.out.print("Key为空null");
35 | return null;
36 | }
37 | SecretKeySpec skeySpec = new SecretKeySpec(bKey, "AES");
38 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
39 | IvParameterSpec iv = new IvParameterSpec(bIv);
40 | cipher.init(Cipher.ENCRYPT_MODE, skeySpec,iv);
41 | byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));
42 |
43 | return encrypted;//此处使用BASE64做转码功能,同时能起到2次加密的作用。
44 | }
45 |
46 | // 解密
47 | public static String Decrypt(String sSrc, String sKey, byte[] ivBytes) throws Exception {
48 | try {
49 | // 判断Key是否正确
50 | if (sKey == null) {
51 | System.out.print("Key为空null");
52 | return null;
53 | }
54 | // 判断Key是否为16位
55 | if (sKey.length() != 16) {
56 | System.out.print("Key长度不是16位");
57 | return null;
58 | }
59 | byte[] raw = sKey.getBytes("utf-8");
60 | SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
61 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
62 | IvParameterSpec iv = new IvParameterSpec(ivBytes);
63 | cipher.init(Cipher.DECRYPT_MODE, skeySpec,iv);
64 | byte[] encrypted1 = Base64.getDecoder().decode(sSrc);//先用base64解密
65 | try {
66 | byte[] original = cipher.doFinal(encrypted1);
67 | String originalString = new String(original,"utf-8");
68 | return originalString;
69 | } catch (Exception e) {
70 | System.out.println(e.toString());
71 | return null;
72 | }
73 | } catch (Exception ex) {
74 | System.out.println(ex.toString());
75 | return null;
76 | }
77 | }
78 |
79 | // 解密
80 | public static String Decrypt(byte[] bData, byte[] bKey, byte[] bIv) throws Exception {
81 | try {
82 | // 判断Key是否正确
83 | if (bKey == null) {
84 | System.out.print("Key为空null");
85 | return null;
86 | }
87 | // // 判断Key是否为16位
88 | // if (sKey.length() != 16) {
89 | // System.out.print("Key长度不是16位");
90 | // return null;
91 | // }
92 | // byte[] raw = sKey.getBytes("utf-8");
93 | SecretKeySpec skeySpec = new SecretKeySpec(bKey, "AES");
94 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
95 | IvParameterSpec iv = new IvParameterSpec(bIv);
96 | cipher.init(Cipher.DECRYPT_MODE, skeySpec,iv);
97 | // byte[] encrypted1 = Base64.getDecoder().decode(sSrc);//先用base64解密
98 | try {
99 | byte[] original = cipher.doFinal(bData);
100 | String originalString = new String(original,"utf-8");
101 | return originalString;
102 | } catch (Exception e) {
103 | System.out.println(e.toString());
104 | return null;
105 | }
106 | } catch (Exception ex) {
107 | System.out.println(ex.toString());
108 | return null;
109 | }
110 | }
111 |
112 | public static void main(String[] args) throws Exception {
113 | /*
114 | * 此处使用AES-128-ECB加密模式,key需要为16位。
115 | */
116 | String cKey = "1234567890123456";
117 | // 需要加密的字串
118 | String cSrc = "www.gowhere.so";
119 | System.out.println(cSrc);
120 | // 加密
121 | String enString = AES.Encrypt(cSrc, cKey);
122 | System.out.println("加密后的字串是:" + enString);
123 |
124 | // 解密
125 | // String DeString = AES.Decrypt(enString, cKey);
126 | // System.out.println("解密后的字串是:" + DeString);
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/main/java/com/baixing/Main.java:
--------------------------------------------------------------------------------
1 | package com.baixing;
2 |
3 | import java.util.Map;
4 |
5 | public class Main {
6 | static String GITLAB_LICENSE = "eyJkYXRhIjoiS2s1OVNGM084VXZWVmYrOUh2M0JvbGxWc2I3TThNS0ZBUmk5\n" +
7 | "cGhjL2ZHR3VnSUtibFpiSit3RTB4Ry9iXG5GUDNXZmYvRE96dVhDRDFXc2Zt\n" +
8 | "S1gxNU5MQU1JbXQwRkZLUjAvMDg3SUp0aU11M3NhazkwUk05Rml1eU9cbnMv\n" +
9 | "Q0xjcW5mU0JEak9TMHQzcU11VHpWNHdHZW5oSkxLaVBlakxFMCt1anhpeHRF\n" +
10 | "OFI5eHFYZ3lYa2xJcVxuUEpjRFVLT3dpNHcwT0hlZVZJQjBlQ1cwd2xsWkc3\n" +
11 | "ZnYyaWJtT2hTcElPMk93WmVEdWdITXR1bzB6WlhjXG5WQXpZYXhIYUF3TnV2\n" +
12 | "ZlF4eFFKenZOdGN0T201VnRucWRsQ2VpMVFIbDhpS2RGbnJNVjh0N3ovNVIz\n" +
13 | "aEFcbjVBTEUzenQxRkJBWDYzRTRpbW5uZzdwaVpMZ2NibytzSHlzVnZVMW5G\n" +
14 | "WXpIWFFuYTM4MzFnMlNNT2wzK1xuZFhkUjhNcEdZZEQvTnJoOU00a1BkK1Ux\n" +
15 | "Zm82VXVTaDZTLzljOHZScFUweUtKbFFsOXFLejhMNU0xNXpoXG43Yyt3dnlE\n" +
16 | "bDU1NVpNVm5NZTZoZlJkVjM4NUZlaWdNVnhMb2ZkdzF0bmc5WGx5dk4zOVdI\n" +
17 | "OVNtMWE2ZHZcbnlSSjdYMTFaUFV1TTNMekNXSjFQQ1FKeVdaY1M2NWs4Y2NN\n" +
18 | "cFFtS05uWjAwTkp0RFpaVnNMQU4rM1VtWlxuYlFaejhnMzgxTStBaGt5Y3ZZ\n" +
19 | "b3ZSbGFXUHI5dmgyK1N2TUFaXG4iLCJrZXkiOiJXOXN2YW81ZFdxbExGUGhw\n" +
20 | "MnRTZ29VMGs5U0hVS3JoUm82U0FlZGxkTHI3azlEVzFnUFN5YmhzQmVlZGpc\n" +
21 | "blJaYURxMHlwWUIzREdQMDNyZjBtZGpCSXpadmVQZ2FmMlJ1bmZDZTZuaWx0\n" +
22 | "OGNXblpLZE81N2d1MEhycVxuOCtTa3NGM2Nwd2t2NG1CL3lHQzhZeDZaTHhV\n" +
23 | "LzBjRW5YTzBqVlVKQ3JqTy9XOEMzTnFBSEo2c3N3dncxXG5TSkduV3VrOGVS\n" +
24 | "THNCdC9CZzNyUFRldW4zYm04YlhGZnEyWkk1REpjNy9RYnNZMWo1WHFDcmJU\n" +
25 | "NzlWZ2lcbnBGR0trWUhCclIwZXJ0endRaC9JTWlQZVp4ZGFpMjhVWDZYdWlF\n" +
26 | "OWdaWkx1bnlRcFFKV0xiaWl5KzI2VVxuSnhwZ25WcExEVjZwVmhERVNDRDlU\n" +
27 | "ZnZsTm94dEdydjIvNVg4NldxZkZnPT1cbiIsIml2IjoiQ1lKRURyblNIdjJh\n" +
28 | "NWtEODlITEZtQT09XG4ifQ==";
29 |
30 | static String MY_PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCwKf1OO2J5Ou6+QXpBRypTNbI1\n" +
31 | "OLw//bzQ4hlVV/sm1c4rwTF/SGpLeWOFhenzT8HuLmWlnPbHErlbCm4fHQJ7FpV7JOIQEe7JigK1\n" +
32 | "1l1NV7MucpWsZmqprUe3r2hs4bKvzawk9h7gZi0SLMquxyLHnvHhrjAoHnOmmirXRGcVSvwgIgV6\n" +
33 | "WZbVmXI92EfwNoDblEUOWFl8ESYshddSj5/TxriI9S2S3jeJatYw2R3DpJvRSJI57lXoExx8vJew\n" +
34 | "1eKGmNjwoAsJZAe0VzhP8QZDfLAKklnt5Mn5Ad2hG39iNXxilp0qHOFc1gwiveV54aMKPHmeD0w2\n" +
35 | "yKqAOS0ICOxlAgMBAAECggEBAI88ZPjCMkxODabmiGghXBmyNEcv7Wi+gFL7NAv/cHdgKrXK7NsI\n" +
36 | "X10kwzXi75llRVLLqNxi5whwggOzVFy58rVwZHRvRdw5KIX4UEHXnZ9waoGeq3I1CA8UlJaW6fp1\n" +
37 | "/RsSySB4ehyNF6KKhvZbdj0HULbmMcO9Ft3kxman+IUHSmU8Pmlz5a+pd/3BsaCJJYIjkJ1upGlV\n" +
38 | "SOMb+NbxC6jkEubX7eUkF1jCzdcDzm6vvk2DPfLmi1hACRjWvU/T0qqOblGwqESbUk7to8veIHVq\n" +
39 | "MbvkEMYiBBlWGHTtUDl9WSEuRtXxq7snbBj59MLa6QAfKBhiyDtgPmTyfqkjFbUCgYEA7401p2UJ\n" +
40 | "X5BTgiq08JHZP1udQHjVOgyV9gmGn7dREsx+6dsUAPb7GoH8PxYoe0XtksvDWurDYybxGFuJ0Mz/\n" +
41 | "xnJLxxrRt8l1fkV6KXRFttWwBBfh+KDhYlS9mo8U/MMwXpXVWHONy+xol/Q1diorW4mtXtMGRZ46\n" +
42 | "6ICHv2aoPIcCgYEAvEKQzTl2mITP/MVnOirxBb1HvSLphkYTU1b9Btlqa3KUBFZhyb0bq6ujTvEP\n" +
43 | "B6BMpF47S/xYo7tHkZWZdem019zut187+JbCdEPBgyGNEjxMiLa6o3tv4ck9FyGe8ikeNd75qOOB\n" +
44 | "HCbE7BZUSqRbvFlhVZHO+8udcc1DorL1FrMCgYAYepyV+3wmuM/fyE9vGehSUiFSmkZnxSt51eVc\n" +
45 | "4tW1DxKVAR8dLh/gyJGnPLNsTWwGiS3wV3cZ5bvTWl9N5/TnKXzW3sW5eyu3eJAQNmJ9WX7AHFSq\n" +
46 | "HH6Lls89QQvK/IMv1y3S+RPvV7wkcv8XkR2XIA2IWBYW/SFV6vR0OaBNdwKBgCl/SsfR+NBZxjbj\n" +
47 | "lIN/36zyMhQA1BTi8XOXYyLVXd3dXb8vA1Miuiy3IsJN5JA7x2kb1FpFf4xnxbjTjwYsw84pRv1o\n" +
48 | "oqGDKc3S+Z7cEGqKnBwumylaFilg4HRu1shuQ9iAE+wkads4uIOJ0H67h/UWhpwEDen20fe51UTR\n" +
49 | "ybB9AoGAPqvM9eJaH3c1PTmC/cDA5lh6mpK7CuobNjKUv0E5KP7h4eYDdYtEmM2HNzlpgYvRf27E\n" +
50 | "WUzlScNoa//xNEm73Mz/90dlXdpsywz2wrBxTtiEih5gk5G+L2ZPwhkUZ8sZyz8hUIO5Y3XWZiDy\n" +
51 | "u8aWLm1ivdqjn+3w7LmR1L9nAGA=";
52 |
53 | public static String GITLAB_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Hxv3MkkZbMrKtIs6np9\n" +
54 | "ccP4OwGBkNhIvhPjcQP48hbbascv5RqsOquQGrYSD2ZrE/kbkRdkIcoHEeTZLif+\n" +
55 | "bDKFZFI7o5x0H92o9/GSvxHJhQ8mkmvwxD7lssGShwZEm8WG+U7BZqUV/gGmCDqe\n" +
56 | "9W8H8Fq2B0ck8IXjbQ4Zz+JlyV/NHZTZcs69plFiLKh4N6GYVftOVwSomh0bbypP\n" +
57 | "OB9WnLC7RC9a2LRrhtf8sqa2rRFmtyMMfgFFzLMzS+w+1K4+QLnWP1gKQVzaFnzk\n" +
58 | "pnwKPrqbGFYbRztIVEWbs8jPYlLkGb8ME4C84YVtQgbQcbyisU/VW3wUGkhT+J0k\n" +
59 | "xwIDAQAB";
60 |
61 | static String MY_PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsCn9TjtieTruvkF6QUcqUzWyNTi8P/28\n" +
62 | "0OIZVVf7JtXOK8Exf0hqS3ljhYXp80/B7i5lpZz2xxK5WwpuHx0CexaVeyTiEBHuyYoCtdZdTVez\n" +
63 | "LnKVrGZqqa1Ht69obOGyr82sJPYe4GYtEizKrscix57x4a4wKB5zppoq10RnFUr8ICIFelmW1Zly\n" +
64 | "PdhH8DaA25RFDlhZfBEmLIXXUo+f08a4iPUtkt43iWrWMNkdw6Sb0UiSOe5V6BMcfLyXsNXihpjY\n" +
65 | "8KALCWQHtFc4T/EGQ3ywCpJZ7eTJ+QHdoRt/YjV8YpadKhzhXNYMIr3leeGjCjx5ng9MNsiqgDkt\n" +
66 | "CAjsZQIDAQAB";
67 |
68 | static String sLICENSE = "{\"version\":1,\"licensee\":{\"Name\":\"Baixing\",\"Email\":\"server@baixing.com\",\"Company\":\"Baixing.com\"},\"issued_at\":\"2019-05-29\",\"expires_at\":\"2030-06-28\",\"notify_admins_at\":\"2030-06-21\",\"notify_users_at\":\"2030-06-21\",\"restrictions\":{\"id\":99999,\"previous_user_count\":null,\"trueup_quantity\":null,\"trueup_from\":null,\"trueup_to\":null,\"active_user_count\":10000,\"add_ons\":{},\"subscription_id\":null,\"plan\":\"ultimate\",\"trial\":true}}";
69 |
70 | public static void main(String[] args) throws Exception {
71 | // RSAUtil rsaUtil = new RSAUtil();
72 | // Map keys = rsaUtil.initKey();
73 | // System.out.println(rsaUtil.getPublicKey(keys));
74 | // System.out.println(rsaUtil.getPrivateKey(keys));
75 |
76 | // System.out.println(LicenseGen.decrypt(GITLAB_LICENSE,GITLAB_PUBLIC_KEY));
77 | System.out.println(LicenseGen.encrypt(sLICENSE,MY_PRIVATE_KEY));
78 | System.out.println(LicenseGen.decrypt(LicenseGen.encrypt(sLICENSE,MY_PRIVATE_KEY),MY_PUBLIC_KEY));
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/com/baixing/RSAUtil.java:
--------------------------------------------------------------------------------
1 | package com.baixing;
2 |
3 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
4 |
5 | import javax.crypto.Cipher;
6 | import java.io.ByteArrayOutputStream;
7 | import java.security.*;
8 | import java.security.interfaces.RSAPrivateKey;
9 | import java.security.interfaces.RSAPublicKey;
10 | import java.security.spec.PKCS8EncodedKeySpec;
11 | import java.security.spec.X509EncodedKeySpec;
12 | import java.util.Base64;
13 | import java.util.HashMap;
14 | import java.util.Map;
15 |
16 | public class RSAUtil {
17 | public static final String KEY_ALGORITHM = "RSA";
18 | public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";//MD5withRSA
19 |
20 | private static final String PUBLIC_KEY = "RSAPublicKey";
21 | private static final String PRIVATE_KEY = "RSAPrivateKey";
22 | private static final int MAX_DECRYPT_BLOCK = 128;
23 | private static final int MAX_ENCRYPT_BLOCK = 117;
24 |
25 | private Base64.Encoder encoder = Base64.getEncoder();
26 | private static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider();
27 |
28 | private static String CIPHER_ALGORITHM = "RSA";
29 |
30 | public RSAUtil(){
31 |
32 | }
33 |
34 | public RSAUtil(String mode){
35 | CIPHER_ALGORITHM = mode;
36 | }
37 |
38 | /**
39 | * 设置RSA加密padding模式,默认RSA为Nopadding
40 | * @param mode padding模式,比如 RSA/None/PKCS1Padding
41 | */
42 | public void setPaddingMode(String mode){
43 | CIPHER_ALGORITHM = mode;
44 | }
45 |
46 | public String sign(byte[] data, String privateKey) throws Exception {
47 | // 解密由base64编码的私钥
48 | byte[] keyBytes = Base64.getDecoder().decode(privateKey);
49 |
50 | // 构造PKCS8EncodedKeySpec对象
51 | PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
52 |
53 | // KEY_ALGORITHM 指定的加密算法
54 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
55 |
56 | // 取私钥匙对象
57 | PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
58 |
59 | // 用私钥对信息生成数字签名
60 | Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
61 | signature.initSign(priKey);
62 | signature.update(data);
63 | return Base64.getEncoder().encodeToString((signature.sign()));
64 | }
65 |
66 | /**
67 | * 校验数字签名
68 | *
69 | * @param data
70 | * 加密数据
71 | * @param publicKey
72 | * 公钥
73 | * @param sign
74 | * 数字签名
75 | *
76 | * @return 校验成功返回true 失败返回false
77 | * @throws Exception
78 | *
79 | */
80 | public boolean verify(byte[] data, String publicKey, String sign)
81 | throws Exception {
82 |
83 | // 解密由base64编码的公钥
84 | byte[] keyBytes = Base64.getDecoder().decode(publicKey);
85 |
86 | // 构造X509EncodedKeySpec对象
87 | X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
88 |
89 | // KEY_ALGORITHM 指定的加密算法
90 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
91 |
92 | // 取公钥匙对象
93 | PublicKey pubKey = keyFactory.generatePublic(keySpec);
94 |
95 | Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
96 | signature.initVerify(pubKey);
97 | signature.update(data);
98 |
99 | // 验证签名是否正常
100 | return signature.verify(Base64.getDecoder().decode(sign));
101 | }
102 |
103 | /**
104 | * 用私钥解密
105 | * @param data
106 | * @param key
107 | * @return
108 | * @throws Exception
109 | */
110 | public byte[] decryptByPrivateKey(byte[] data, String key)
111 | throws Exception {
112 | // 对密钥解密
113 | byte[] keyBytes = Base64.getDecoder().decode(key);
114 |
115 | // 取得私钥
116 | PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
117 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
118 | Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
119 |
120 | // 对数据解密
121 | Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
122 | cipher.init(Cipher.DECRYPT_MODE, privateKey);
123 |
124 | return decryBySegment(cipher, data);
125 | }
126 |
127 | /**
128 | * 用公钥解密
129 | * @param data
130 | * @param key
131 | * @return
132 | * @throws Exception
133 | */
134 | public static byte[] decryptByPublicKey(byte[] data, String key)
135 | throws Exception {
136 | // 对密钥解密
137 | byte[] keyBytes = Base64.getMimeDecoder().decode(key);
138 |
139 | return decryptByPublicKey(data, keyBytes);
140 | }
141 |
142 | /**
143 | * 用公钥解密
144 | * @param data
145 | * @param keyBytes
146 | * @return
147 | * @throws Exception
148 | */
149 | public static byte[] decryptByPublicKey(byte[] data, byte[] keyBytes)
150 | throws Exception {
151 |
152 | // 取得公钥
153 | X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
154 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
155 | Key publicKey = keyFactory.generatePublic(x509KeySpec);
156 |
157 | // 对数据解密
158 | Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
159 | cipher.init(Cipher.DECRYPT_MODE, publicKey);
160 |
161 | return cipher.doFinal(data);
162 | }
163 |
164 | /**
165 | * 分段解密
166 | * @param cipher
167 | * @param data
168 | * @return
169 | * @throws Exception
170 | */
171 | private static byte[] decryBySegment(Cipher cipher, byte[] data) throws Exception{
172 | int inputLen = data.length;
173 | ByteArrayOutputStream out =new ByteArrayOutputStream();
174 | try {
175 | int offSet = 0;
176 | byte[] cache;
177 | int i = 0;
178 | // 对数据分段解密
179 | while (inputLen - offSet > 0) {
180 | Object o;
181 | if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
182 | cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
183 | } else {
184 | cache = cipher.doFinal(data, offSet, inputLen - offSet);
185 | }
186 | out.write(cache, 0, cache.length);
187 | i++;
188 | offSet = i * MAX_DECRYPT_BLOCK;
189 | }
190 | return out.toByteArray();
191 | }finally {
192 | IOUtil.closeIgnoreError(out);
193 | }
194 | }
195 |
196 | /**
197 | * 加密
198 | * 用公钥加密
199 | *
200 | * @param data
201 | * @param key
202 | * @return
203 | * @throws Exception
204 | */
205 | public byte[] encryptByPublicKey(byte[] data, String key)
206 | throws Exception {
207 | // 对公钥解密
208 | byte[] keyBytes = Base64.getDecoder().decode(key);
209 |
210 | // 取得公钥
211 | X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
212 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
213 | Key publicKey = keyFactory.generatePublic(x509KeySpec);
214 |
215 | // 对数据加密
216 | Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
217 | cipher.init(Cipher.ENCRYPT_MODE, publicKey);
218 |
219 | return encryBySegment(cipher, data);
220 | }
221 |
222 | /**
223 | * 加密
224 | * 用私钥加密
225 | *
226 | * @param data
227 | * @param key
228 | * @return
229 | * @throws Exception
230 | */
231 | public static byte[] encryptByPrivateKey(byte[] data, String key)
232 | throws Exception {
233 | // 对密钥解密
234 | byte[] keyBytes = Base64.getDecoder().decode(key);
235 |
236 | // 取得私钥
237 | PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
238 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
239 | Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
240 |
241 | // 对数据加密
242 | Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
243 | cipher.init(Cipher.ENCRYPT_MODE, privateKey);
244 |
245 | return encryBySegment(cipher, data);
246 | }
247 |
248 | public static byte[] encryptByPrivateKey(byte[] data, byte[] key)
249 | throws Exception {
250 |
251 | // 取得私钥
252 | PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
253 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
254 | Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
255 |
256 | // 对数据加密
257 | Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
258 | cipher.init(Cipher.ENCRYPT_MODE, privateKey);
259 |
260 | return cipher.doFinal(data);
261 | }
262 |
263 | private static byte[] encryBySegment(Cipher cipher, byte[] data) throws Exception{
264 | int inputLen = data.length;
265 | ByteArrayOutputStream out =new ByteArrayOutputStream();
266 | try {
267 | int offSet = 0;
268 | byte[] cache;
269 | int i = 0;
270 | // 对数据分段加密
271 | while (inputLen - offSet > 0) {
272 | int j = 0;
273 | if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
274 | cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
275 | } else {
276 | cache = cipher.doFinal(data, offSet, inputLen - offSet);
277 | }
278 | out.write(cache, 0, cache.length);
279 | i++;
280 | offSet = i * MAX_ENCRYPT_BLOCK;
281 | }
282 | return out.toByteArray();
283 | }finally {
284 | IOUtil.closeIgnoreError(out);
285 | }
286 |
287 |
288 | }
289 |
290 | /**
291 | * 取得私钥
292 | *
293 | * @param keyMap
294 | * @return
295 | * @throws Exception
296 | */
297 | public String getPrivateKey(Map keyMap)
298 | throws Exception {
299 | Key key = (Key) keyMap.get(PRIVATE_KEY);
300 |
301 | return Base64.getMimeEncoder().encodeToString(key.getEncoded());
302 | }
303 |
304 | /**
305 | * 取得公钥
306 | *
307 | * @param keyMap
308 | * @return
309 | * @throws Exception
310 | */
311 | public String getPublicKey(Map keyMap)
312 | throws Exception {
313 | Key key = (Key) keyMap.get(PUBLIC_KEY);
314 |
315 | return Base64.getMimeEncoder().encodeToString(key.getEncoded());
316 | }
317 |
318 | /**
319 | * 初始化密钥
320 | *
321 | * @return
322 | * @throws Exception
323 | */
324 | public Map initKey() throws Exception {
325 | KeyPairGenerator keyPairGen = KeyPairGenerator
326 | .getInstance(KEY_ALGORITHM);
327 | keyPairGen.initialize(2048);
328 |
329 | KeyPair keyPair = keyPairGen.generateKeyPair();
330 |
331 | // 公钥
332 | RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
333 |
334 | // 私钥
335 | RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
336 |
337 | Map keyMap = new HashMap(2);
338 |
339 | keyMap.put(PUBLIC_KEY, publicKey);
340 | keyMap.put(PRIVATE_KEY, privateKey);
341 | return keyMap;
342 | }
343 | }
344 |
--------------------------------------------------------------------------------