├── 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 | --------------------------------------------------------------------------------