├── .gitignore ├── src ├── main │ └── java │ │ └── com │ │ └── wustrive │ │ ├── aesrsa │ │ └── util │ │ │ ├── ConfigureEncryptAndDecrypt.java │ │ │ ├── RandomUtil.java │ │ │ ├── CheckUtils.java │ │ │ ├── EncryptionUtil.java │ │ │ ├── EncryUtil.java │ │ │ ├── AES.java │ │ │ ├── Digest.java │ │ │ ├── RSA.java │ │ │ ├── ConvertUtils.java │ │ │ └── Base64.java │ │ └── Main.java └── test │ └── java │ └── com │ └── wustrive │ └── AppTest.java ├── README.md ├── pom.xml ├── rsa测试密钥对.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | .project 3 | .classpath 4 | target/ 5 | .idea/ 6 | *.iml 7 | -------------------------------------------------------------------------------- /src/main/java/com/wustrive/aesrsa/util/ConfigureEncryptAndDecrypt.java: -------------------------------------------------------------------------------- 1 | package com.wustrive.aesrsa.util; 2 | 3 | public class ConfigureEncryptAndDecrypt { 4 | public static final String CHAR_ENCODING = "UTF-8"; 5 | public static final String AES_ALGORITHM = "AES/ECB/PKCS5Padding"; 6 | public static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding"; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aes-rsa-java AES+RSA结合应用java示例 2 | 3 | ### 介绍 4 | 随着Internet网的广泛应用,信息安全问题日益突出,以数据加密技术为核心的信息安全技术也得到了极大的发展。 5 | 目前的数据加密技术根据加密密钥类型可分私钥加密(对称加密)系统和公钥加密(非对称加密)系统。对称加密算法是较传统的加密体制, 6 | 通信双方在加/解密过程中使用他们共享的单一密钥,鉴于其算法简单和加密速度快的优点,目前仍然是主流的密码体制之一。 7 | 最常用的对称密码算法是数据加密标准(DES)算法,但是由于DES密钥长度较短,已经不适合当今分布式开放网络对数据加密安全性的要求。 8 | 最后,一种新的基于Rijndael算法对称高级数据加密标准AES取代了数据加密标准DES。 9 | 非对称加密由于加/解密钥不同(公钥加密,私钥解密),密钥管理简单,也得到广泛应用。RSA是非对称加密系统最著名的公钥密码算法。 10 | 11 | --- 12 | 13 | ### 文章详解 14 | 15 | [开放接口的安全验证方案(AES+RSA)](http://wubaoguo.com/2015/08/21/%E5%BC%80%E6%94%BE%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%AE%89%E5%85%A8%E9%AA%8C%E8%AF%81%E6%96%B9%E6%A1%88(AES+RSA)/) 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/test/java/com/wustrive/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.wustrive; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/wustrive/aesrsa/util/RandomUtil.java: -------------------------------------------------------------------------------- 1 | package com.wustrive.aesrsa.util; 2 | 3 | import java.util.Random; 4 | 5 | public class RandomUtil { 6 | 7 | public static Random random = new Random(); 8 | 9 | public static String getRandom(int length) { 10 | StringBuilder ret = new StringBuilder(); 11 | for (int i = 0; i < length; i++) { 12 | boolean isChar = (random.nextInt(2) % 2 == 0);// 输出字母还是数字 13 | if (isChar) { // 字符串 14 | int choice = random.nextInt(2) % 2 == 0 ? 65 : 97; // 取得大写字母还是小写字母 15 | ret.append((char) (choice + random.nextInt(26))); 16 | } else { // 数字 17 | ret.append(Integer.toString(random.nextInt(10))); 18 | } 19 | } 20 | return ret.toString(); 21 | } 22 | 23 | public static String getRandomNum(int length) { 24 | StringBuilder ret = new StringBuilder(); 25 | for (int i = 0; i < length; i++) { 26 | ret.append(Integer.toString(random.nextInt(10))); 27 | } 28 | return ret.toString(); 29 | } 30 | 31 | public static void main(String[] args) { 32 | System.out.println(getRandom(5)); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/wustrive/aesrsa/util/CheckUtils.java: -------------------------------------------------------------------------------- 1 | package com.wustrive.aesrsa.util; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.Collection; 5 | import java.util.Map; 6 | 7 | 8 | public class CheckUtils { 9 | 10 | public static final String COMMON_FIELD = "flowID,initiator,"; 11 | 12 | 13 | /** 14 | * 验证对象是否为NULL,空字符串,空数组,空的Collection或Map(只有空格的字符串也认为是空串) 15 | * @param obj 被验证的对象 16 | * @param message 异常信息 17 | */ 18 | @SuppressWarnings("rawtypes") 19 | public static void notEmpty(Object obj, String message) { 20 | if (obj == null){ 21 | throw new IllegalArgumentException(message + " must be specified"); 22 | } 23 | if (obj instanceof String && obj.toString().trim().length()==0){ 24 | throw new IllegalArgumentException(message + " must be specified"); 25 | } 26 | if (obj.getClass().isArray() && Array.getLength(obj)==0){ 27 | throw new IllegalArgumentException(message + " must be specified"); 28 | } 29 | if (obj instanceof Collection && ((Collection)obj).isEmpty()){ 30 | throw new IllegalArgumentException(message + " must be specified"); 31 | } 32 | if (obj instanceof Map && ((Map)obj).isEmpty()){ 33 | throw new IllegalArgumentException(message + " must be specified"); 34 | } 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.wustrive 6 | aes-rsa-java 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | aes-rsa-java 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | junit 20 | junit 21 | 3.8.1 22 | test 23 | 24 | 25 | 26 | log4j 27 | log4j 28 | 1.2.16 29 | 30 | 31 | 32 | commons-lang 33 | commons-lang 34 | 2.5 35 | 36 | 37 | 38 | com.alibaba 39 | fastjson 40 | 1.1.15 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/main/java/com/wustrive/aesrsa/util/EncryptionUtil.java: -------------------------------------------------------------------------------- 1 | package com.wustrive.aesrsa.util; 2 | 3 | import java.security.MessageDigest; 4 | 5 | public class EncryptionUtil { 6 | 7 | // 对字符串进行md5加密 8 | public static String md5(String str) { 9 | try { 10 | MessageDigest md = MessageDigest.getInstance("MD5"); 11 | md.update(str.getBytes()); 12 | 13 | byte[] b = md.digest(); 14 | StringBuffer sb = new StringBuffer(); 15 | for (int i = 0; i < b.length; i++) { 16 | int v = (int) b[i]; 17 | v = v < 0 ? 0x100 + v : v; 18 | String cc = Integer.toHexString(v); 19 | if (cc.length() == 1) 20 | sb.append('0'); 21 | sb.append(cc); 22 | } 23 | 24 | return sb.toString(); 25 | } catch (Exception e) { 26 | } 27 | return ""; 28 | } 29 | 30 | // 对字符串进行sha256加密 31 | public static String sha256(String str) { 32 | try { 33 | MessageDigest md = MessageDigest.getInstance("SHA-256"); 34 | md.update(str.getBytes()); 35 | 36 | byte[] b = md.digest(); 37 | StringBuffer sb = new StringBuffer(); 38 | for (int i = 0; i < b.length; i++) { 39 | int v = (int) b[i]; 40 | v = v < 0 ? 0x100 + v : v; 41 | String cc = Integer.toHexString(v); 42 | if (cc.length() == 1) 43 | sb.append('0'); 44 | sb.append(cc); 45 | } 46 | 47 | return sb.toString(); 48 | } catch (Exception e) { 49 | } 50 | return ""; 51 | } 52 | // 对字符串进行sha1加密 53 | public static String sha1(String str) { 54 | try { 55 | MessageDigest md = MessageDigest.getInstance("SHA-1"); 56 | md.update(str.getBytes()); 57 | 58 | byte[] b = md.digest(); 59 | StringBuffer sb = new StringBuffer(); 60 | for (int i = 0; i < b.length; i++) { 61 | int v = (int) b[i]; 62 | v = v < 0 ? 0x100 + v : v; 63 | String cc = Integer.toHexString(v); 64 | if (cc.length() == 1) 65 | sb.append('0'); 66 | sb.append(cc); 67 | } 68 | 69 | return sb.toString(); 70 | } catch (Exception e) { 71 | } 72 | return ""; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/wustrive/aesrsa/util/EncryUtil.java: -------------------------------------------------------------------------------- 1 | package com.wustrive.aesrsa.util; 2 | 3 | import java.util.Iterator; 4 | import java.util.Map; 5 | import java.util.Map.Entry; 6 | import java.util.TreeMap; 7 | 8 | import org.apache.commons.lang.StringUtils; 9 | import org.apache.log4j.Logger; 10 | 11 | import com.alibaba.fastjson.JSON; 12 | import com.alibaba.fastjson.TypeReference; 13 | 14 | public class EncryUtil { 15 | private static final Logger log = Logger.getLogger(EncryUtil.class); 16 | /** 17 | * 生成RSA签名 18 | */ 19 | public static String handleRSA(TreeMap map, 20 | String privateKey) { 21 | StringBuffer sbuffer = new StringBuffer(); 22 | for (Map.Entry entry : map.entrySet()) { 23 | sbuffer.append(entry.getValue()); 24 | } 25 | String signTemp = sbuffer.toString(); 26 | 27 | String sign = ""; 28 | if (StringUtils.isNotEmpty(privateKey)) { 29 | sign = RSA.sign(signTemp, privateKey); 30 | } 31 | return sign; 32 | } 33 | 34 | /** 35 | * 返回的结果进行验签 36 | * 37 | * @param data 38 | * 业务数据密文 39 | * @param encrypt_key 40 | * 对ybAesKey加密后的密文 41 | * @param clientPublicKey 42 | * 客户端公钥 43 | * @param serverPrivateKey 44 | * 服务器私钥 45 | * @return 验签是否通过 46 | * @throws Exception 47 | */ 48 | public static boolean checkDecryptAndSign(String data, String encrypt_key, 49 | String clientPublicKey, String serverPrivateKey) throws Exception { 50 | 51 | /** 1.使用serverPrivateKey解开aesEncrypt。 */ 52 | String AESKey = ""; 53 | try { 54 | AESKey = RSA.decrypt(encrypt_key, serverPrivateKey); 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | /** AES密钥解密失败 */ 58 | log.error(e.getMessage(), e); 59 | return false; 60 | } 61 | 62 | /** 2.用aeskey解开data。取得data明文 */ 63 | String realData = AES.decryptFromBase64(data, AESKey); 64 | 65 | TreeMap map = JSON.parseObject(realData, 66 | new TypeReference>() { 67 | }); 68 | 69 | /** 3.取得data明文sign。 */ 70 | String sign = StringUtils.trimToEmpty(map.get("sign")); 71 | 72 | /** 4.对map中的值进行验证 */ 73 | StringBuffer signData = new StringBuffer(); 74 | Iterator> iter = map.entrySet().iterator(); 75 | while (iter.hasNext()) { 76 | Entry entry = iter.next(); 77 | 78 | /** 把sign参数隔过去 */ 79 | if (StringUtils.equals((String) entry.getKey(), "sign")) { 80 | continue; 81 | } 82 | signData.append(entry.getValue() == null ? "" : entry.getValue()); 83 | } 84 | 85 | /** 5. result为true时表明验签通过 */ 86 | boolean result = RSA.checkSign(signData.toString(), sign, 87 | clientPublicKey); 88 | 89 | return result; 90 | } 91 | 92 | /** 93 | * 生成hmac 94 | */ 95 | public static String handleHmac(TreeMap map, String hmacKey) { 96 | StringBuffer sbuffer = new StringBuffer(); 97 | for (Map.Entry entry : map.entrySet()) { 98 | sbuffer.append(entry.getValue()); 99 | } 100 | String hmacTemp = sbuffer.toString(); 101 | 102 | String hmac = ""; 103 | if (StringUtils.isNotEmpty(hmacKey)) { 104 | hmac = Digest.hmacSHASign(hmacTemp, hmacKey, Digest.ENCODE); 105 | } 106 | return hmac; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /rsa测试密钥对.md: -------------------------------------------------------------------------------- 1 | ### 测试RSA密钥对 2 | 3 | #### 客户端私钥 4 | 5 | ##### 原始的私钥: 6 | 7 | ``` 8 | MIICXAIBAAKBgQCmzaI2K/Cpaig/8gjne0F7t3uE7Kx3eLM914A2FhGWYGKiI1Q3 9 | KXJ5c7cKJoIzI/cUsXacgnPORjhmtJb2tXzWaRuil2EtcbhWvRuxUW2gAqAi99U0 10 | b/LeEzZH0IUO3tku2ZLaslHj1mC5c7vIceY13a4hK0SMdY1itatTXhHdzQIDAQAB 11 | AoGAMLOzm/uCXgS30cvaW7P6L6Qn9WyhApUESJcmQSR6aBymT87e5Og+G0X0+Iq7 12 | 0zC6EJmsFxBjvaN1Dk/GECx3US4rVtQmCi8vJPMnMjaQf9S9rz/pBw85jOj69CL5 13 | BYJ2yBUJl3kuTQVfsTnZQGM7jxZAsn1EjinZrdxfz23/RIUCQQDaxeVGsZpO6hl3 14 | 0Ve7Qk/n9u3gFrWItof4CXpy65rZHh4O0pIA4mBxKyQ57POb2uHJ4WgMwCNXkiB1 15 | Wl4dyRl3AkEAwy/Z7O/CzQ6/0LhzfaZng3ZUH4pHgys1vHTHFCKhlV+FkCTKbb4m 16 | bn93DL4JvfoQ01S70nj3U5QPWEgheFTT2wJBAL23ueF5aQigSF+4oi0ZD3Roldar 17 | uteI+xalGZQJLyqzzHssLkMoDVx2fh7hlkyFHyLUH0hXYw6xAQbjzBRmbXcCQFeT 18 | d8csiI3zCTOAHymIaTd99x6zr4R19cVZ7BznsPJRip7zMvRsddfsTyEjf0GDGtuH 19 | UEKOTgJtEzl8G7Be9zMCQB86mimT7BDdPCbp1gzirN2UvvdpmiSJtWBnWH+YqQfP 20 | wZt8BJZybAogHkamCpj6QDJQmecfmQLLgtbI3Kdq+8c= 21 | ``` 22 | 23 | ##### 转换成PKCS8格式的私钥 24 | 25 | ``` 26 | MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKbNojYr8KlqKD/y 27 | COd7QXu3e4TsrHd4sz3XgDYWEZZgYqIjVDcpcnlztwomgjMj9xSxdpyCc85GOGa0 28 | lva1fNZpG6KXYS1xuFa9G7FRbaACoCL31TRv8t4TNkfQhQ7e2S7ZktqyUePWYLlz 29 | u8hx5jXdriErRIx1jWK1q1NeEd3NAgMBAAECgYAws7Ob+4JeBLfRy9pbs/ovpCf1 30 | bKEClQRIlyZBJHpoHKZPzt7k6D4bRfT4irvTMLoQmawXEGO9o3UOT8YQLHdRLitW 31 | 1CYKLy8k8ycyNpB/1L2vP+kHDzmM6Pr0IvkFgnbIFQmXeS5NBV+xOdlAYzuPFkCy 32 | fUSOKdmt3F/Pbf9EhQJBANrF5Uaxmk7qGXfRV7tCT+f27eAWtYi2h/gJenLrmtke 33 | Hg7SkgDiYHErJDns85va4cnhaAzAI1eSIHVaXh3JGXcCQQDDL9ns78LNDr/QuHN9 34 | pmeDdlQfikeDKzW8dMcUIqGVX4WQJMptviZuf3cMvgm9+hDTVLvSePdTlA9YSCF4 35 | VNPbAkEAvbe54XlpCKBIX7iiLRkPdGiV1qu614j7FqUZlAkvKrPMeywuQygNXHZ+ 36 | HuGWTIUfItQfSFdjDrEBBuPMFGZtdwJAV5N3xyyIjfMJM4AfKYhpN333HrOvhHX1 37 | xVnsHOew8lGKnvMy9Gx11+xPISN/QYMa24dQQo5OAm0TOXwbsF73MwJAHzqaKZPs 38 | EN08JunWDOKs3ZS+92maJIm1YGdYf5ipB8/Bm3wElnJsCiAeRqYKmPpAMlCZ5x+Z 39 | AsuC1sjcp2r7xw== 40 | ``` 41 | 42 | #### 客户端公钥 43 | 44 | ``` 45 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmzaI2K/Cpaig/8gjne0F7t3uE 46 | 7Kx3eLM914A2FhGWYGKiI1Q3KXJ5c7cKJoIzI/cUsXacgnPORjhmtJb2tXzWaRui 47 | l2EtcbhWvRuxUW2gAqAi99U0b/LeEzZH0IUO3tku2ZLaslHj1mC5c7vIceY13a4h 48 | K0SMdY1itatTXhHdzQIDAQAB 49 | ``` 50 | 51 | #### 服务器端私钥 52 | 53 | ##### 原始私钥 54 | 55 | ``` 56 | MIICXAIBAAKBgQCyGffCqoC1vCDLeBvjfuHdw4johGvubOpQjEhhPzW1PbLSRKsN 57 | BLgj+eDGOiZE9BwmEwqy16sMOq0kMlhewTQlRrLJNlw3L0iogs9WTIGm3el1SuZL 58 | yMnMksnV0NCsuq538cPMNppZRwARb7NXmpmh0KM79fJ/1xqnpo1tgRcv4wIDAQAB 59 | AoGAMU9xQot0gVyp88u4ZP8/R+gYYtAvFd8/7Lc6XvpiQ2DmvsLWXQ9ecE+BxUBa 60 | UiMIHB6Pir6dlBA22du6jdmONwGWxfSzmpVk0VM2La/MC/DCG4LXsP0EPWBTVnZE 61 | 2ejMQiLYw/5ks9y65HKYb27MeFaAlWCCdOK/i6ItLfYNILkCQQDb5KX66tGy1UWF 62 | n2ooI5MeO5q9LayZAe5owA3uvSKrbDP9seXRz6QpQyu/MswFsVNga2Mznd9UCDpt 63 | 9ojCL0cVAkEAz1iTzDs3KvCarNTwDOw9IcZ7xd7UiQdAiQkFnRhZCYriGEm61pwl 64 | Re/IyclNgCtR90Q4vQcxjy9md4tkovvZFwJAD5yrQCZd3xGPTw5jbhgggNwAf3/3 65 | qiFd+Ofx1UpuZLdY9aEkzQGuCRPwzjFgFONjJQxazbZevcubwmTnjsnmhQJATiYn 66 | hplnAKMw2SVk2KoNnHZP3lNPLdpy43NoDz7HCEa1UswvRIYTsllfB1b9A+rP+O9Y 67 | pz5X2ozWBQafxqI/vwJBAInox1/+fFb/PnHFttkTGZssYh3GaU8PYc+7x1Alr9N/ 68 | n8lRrRjISeMbj7fFGmZvdch0j1lmqzPF2u3q6ymlzfQ= 69 | 70 | ``` 71 | 72 | ##### 转换成PKCS8格式的私钥 73 | 74 | ``` 75 | MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALIZ98KqgLW8IMt4 76 | G+N+4d3DiOiEa+5s6lCMSGE/NbU9stJEqw0EuCP54MY6JkT0HCYTCrLXqww6rSQy 77 | WF7BNCVGssk2XDcvSKiCz1ZMgabd6XVK5kvIycySydXQ0Ky6rnfxw8w2mllHABFv 78 | s1eamaHQozv18n/XGqemjW2BFy/jAgMBAAECgYAxT3FCi3SBXKnzy7hk/z9H6Bhi 79 | 0C8V3z/stzpe+mJDYOa+wtZdD15wT4HFQFpSIwgcHo+Kvp2UEDbZ27qN2Y43AZbF 80 | 9LOalWTRUzYtr8wL8MIbgtew/QQ9YFNWdkTZ6MxCItjD/mSz3Lrkcphvbsx4VoCV 81 | YIJ04r+Loi0t9g0guQJBANvkpfrq0bLVRYWfaigjkx47mr0trJkB7mjADe69Iqts 82 | M/2x5dHPpClDK78yzAWxU2BrYzOd31QIOm32iMIvRxUCQQDPWJPMOzcq8Jqs1PAM 83 | 7D0hxnvF3tSJB0CJCQWdGFkJiuIYSbrWnCVF78jJyU2AK1H3RDi9BzGPL2Z3i2Si 84 | +9kXAkAPnKtAJl3fEY9PDmNuGCCA3AB/f/eqIV345/HVSm5kt1j1oSTNAa4JE/DO 85 | MWAU42MlDFrNtl69y5vCZOeOyeaFAkBOJieGmWcAozDZJWTYqg2cdk/eU08t2nLj 86 | c2gPPscIRrVSzC9EhhOyWV8HVv0D6s/471inPlfajNYFBp/Goj+/AkEAiejHX/58 87 | Vv8+ccW22RMZmyxiHcZpTw9hz7vHUCWv03+fyVGtGMhJ4xuPt8UaZm91yHSPWWar 88 | M8Xa7errKaXN9A== 89 | ``` 90 | 91 | #### 服务器端公钥 92 | 93 | ``` 94 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyGffCqoC1vCDLeBvjfuHdw4jo 95 | hGvubOpQjEhhPzW1PbLSRKsNBLgj+eDGOiZE9BwmEwqy16sMOq0kMlhewTQlRrLJ 96 | Nlw3L0iogs9WTIGm3el1SuZLyMnMksnV0NCsuq538cPMNppZRwARb7NXmpmh0KM7 97 | 9fJ/1xqnpo1tgRcv4wIDAQAB 98 | ``` -------------------------------------------------------------------------------- /src/main/java/com/wustrive/aesrsa/util/AES.java: -------------------------------------------------------------------------------- 1 | package com.wustrive.aesrsa.util; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.security.Key; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.security.SecureRandom; 7 | 8 | import javax.crypto.Cipher; 9 | import javax.crypto.KeyGenerator; 10 | import javax.crypto.spec.SecretKeySpec; 11 | 12 | /** 13 | * 14 | * Description: 15 | * 16 | * @author: wubaoguo 17 | * @email: wustrive2008@gmail.com 18 | * @date: 2018/7/16 15:12 19 | */ 20 | public class AES { 21 | /** 22 | * 加密 23 | * 24 | * @param data 25 | * 需要加密的内容 26 | * @param key 27 | * 加密密码 28 | * @return 29 | */ 30 | public static byte[] encrypt(byte[] data, byte[] key) { 31 | CheckUtils.notEmpty(data, "data"); 32 | CheckUtils.notEmpty(key, "key"); 33 | if(key.length!=16){ 34 | throw new RuntimeException("Invalid AES key length (must be 16 bytes)"); 35 | } 36 | try { 37 | SecretKeySpec secretKey = new SecretKeySpec(key, "AES"); 38 | byte[] enCodeFormat = secretKey.getEncoded(); 39 | SecretKeySpec seckey = new SecretKeySpec(enCodeFormat,"AES"); 40 | Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.AES_ALGORITHM);// 创建密码器 41 | cipher.init(Cipher.ENCRYPT_MODE, seckey);// 初始化 42 | byte[] result = cipher.doFinal(data); 43 | return result; // 加密 44 | } catch (Exception e){ 45 | throw new RuntimeException("encrypt fail!", e); 46 | } 47 | } 48 | 49 | /** 50 | * 解密 51 | * 52 | * @param data 53 | * 待解密内容 54 | * @param key 55 | * 解密密钥 56 | * @return 57 | */ 58 | public static byte[] decrypt(byte[] data, byte[] key) { 59 | CheckUtils.notEmpty(data, "data"); 60 | CheckUtils.notEmpty(key, "key"); 61 | if(key.length!=16){ 62 | throw new RuntimeException("Invalid AES key length (must be 16 bytes)"); 63 | } 64 | try { 65 | SecretKeySpec secretKey = new SecretKeySpec(key, "AES"); 66 | byte[] enCodeFormat = secretKey.getEncoded(); 67 | SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "AES"); 68 | Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.AES_ALGORITHM);// 创建密码器 69 | cipher.init(Cipher.DECRYPT_MODE, seckey);// 初始化 70 | byte[] result = cipher.doFinal(data); 71 | return result; // 加密 72 | } catch (Exception e){ 73 | throw new RuntimeException("decrypt fail!", e); 74 | } 75 | } 76 | 77 | public static String encryptToBase64(String data, String key){ 78 | try { 79 | byte[] valueByte = encrypt(data.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING), key.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING)); 80 | return new String(Base64.encode(valueByte)); 81 | } catch (UnsupportedEncodingException e) { 82 | throw new RuntimeException("encrypt fail!", e); 83 | } 84 | 85 | } 86 | 87 | public static String decryptFromBase64(String data, String key){ 88 | try { 89 | byte[] originalData = Base64.decode(data.getBytes()); 90 | byte[] valueByte = decrypt(originalData, key.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING)); 91 | return new String(valueByte, ConfigureEncryptAndDecrypt.CHAR_ENCODING); 92 | } catch (UnsupportedEncodingException e) { 93 | throw new RuntimeException("decrypt fail!", e); 94 | } 95 | } 96 | 97 | public static String encryptWithKeyBase64(String data, String key){ 98 | try { 99 | byte[] valueByte = encrypt(data.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING), Base64.decode(key.getBytes())); 100 | return new String(Base64.encode(valueByte)); 101 | } catch (UnsupportedEncodingException e) { 102 | throw new RuntimeException("encrypt fail!", e); 103 | } 104 | } 105 | 106 | public static String decryptWithKeyBase64(String data, String key){ 107 | try { 108 | byte[] originalData = Base64.decode(data.getBytes()); 109 | byte[] valueByte = decrypt(originalData, Base64.decode(key.getBytes())); 110 | return new String(valueByte, ConfigureEncryptAndDecrypt.CHAR_ENCODING); 111 | } catch (UnsupportedEncodingException e) { 112 | throw new RuntimeException("decrypt fail!", e); 113 | } 114 | } 115 | 116 | public static byte[] genarateRandomKey(){ 117 | KeyGenerator keygen = null; 118 | try { 119 | keygen = KeyGenerator.getInstance(ConfigureEncryptAndDecrypt.AES_ALGORITHM); 120 | } catch (NoSuchAlgorithmException e) { 121 | throw new RuntimeException(" genarateRandomKey fail!", e); 122 | } 123 | SecureRandom random = new SecureRandom(); 124 | keygen.init(random); 125 | Key key = keygen.generateKey(); 126 | return key.getEncoded(); 127 | } 128 | 129 | public static String genarateRandomKeyWithBase64(){ 130 | return new String(Base64.encode(genarateRandomKey())); 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/com/wustrive/aesrsa/util/Digest.java: -------------------------------------------------------------------------------- 1 | package com.wustrive.aesrsa.util; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.util.Arrays; 7 | 8 | import org.apache.log4j.Logger; 9 | 10 | public class Digest { 11 | private static final Logger log = Logger.getLogger(Digest.class); 12 | public static final String ENCODE = "UTF-8"; 13 | 14 | public static String signMD5(String aValue, String encoding) { 15 | try { 16 | byte[] input = aValue.getBytes(encoding); 17 | MessageDigest md = MessageDigest.getInstance("MD5"); 18 | return ConvertUtils.toHex(md.digest(input)); 19 | } catch (NoSuchAlgorithmException e) { 20 | log.error(e.getMessage(), e); 21 | return null; 22 | } catch (UnsupportedEncodingException e) { 23 | log.error(e.getMessage(), e); 24 | return null; 25 | } 26 | } 27 | 28 | public static String hmacSign(String aValue) { 29 | try { 30 | byte[] input = aValue.getBytes(); 31 | MessageDigest md = MessageDigest.getInstance("MD5"); 32 | return ConvertUtils.toHex(md.digest(input)); 33 | } catch (NoSuchAlgorithmException e) { 34 | log.error(e.getMessage(), e); 35 | return null; 36 | } 37 | } 38 | 39 | public static String hmacSign(String aValue, String aKey) { 40 | return hmacSign(aValue, aKey, ENCODE); 41 | } 42 | 43 | public static String hmacSign(String aValue, String aKey, String encoding) { 44 | byte k_ipad[] = new byte[64]; 45 | byte k_opad[] = new byte[64]; 46 | byte keyb[]; 47 | byte value[]; 48 | try { 49 | keyb = aKey.getBytes(encoding); 50 | value = aValue.getBytes(encoding); 51 | } catch (UnsupportedEncodingException e) { 52 | keyb = aKey.getBytes(); 53 | value = aValue.getBytes(); 54 | } 55 | Arrays.fill(k_ipad, keyb.length, 64, (byte) 54); 56 | Arrays.fill(k_opad, keyb.length, 64, (byte) 92); 57 | for (int i = 0; i < keyb.length; i++) { 58 | k_ipad[i] = (byte) (keyb[i] ^ 0x36); 59 | k_opad[i] = (byte) (keyb[i] ^ 0x5c); 60 | } 61 | 62 | MessageDigest md = null; 63 | try { 64 | md = MessageDigest.getInstance("MD5"); 65 | } catch (NoSuchAlgorithmException e) { 66 | log.error(e.getMessage(), e); 67 | return null; 68 | } 69 | md.update(k_ipad); 70 | md.update(value); 71 | byte dg[] = md.digest(); 72 | md.reset(); 73 | md.update(k_opad); 74 | md.update(dg, 0, 16); 75 | dg = md.digest(); 76 | return ConvertUtils.toHex(dg); 77 | } 78 | 79 | public static String hmacSHASign(String aValue, String aKey, String encoding) { 80 | byte k_ipad[] = new byte[64]; 81 | byte k_opad[] = new byte[64]; 82 | byte keyb[]; 83 | byte value[]; 84 | try { 85 | keyb = aKey.getBytes(encoding); 86 | value = aValue.getBytes(encoding); 87 | } catch (UnsupportedEncodingException e) { 88 | keyb = aKey.getBytes(); 89 | value = aValue.getBytes(); 90 | } 91 | Arrays.fill(k_ipad, keyb.length, 64, (byte) 54); 92 | Arrays.fill(k_opad, keyb.length, 64, (byte) 92); 93 | for (int i = 0; i < keyb.length; i++) { 94 | k_ipad[i] = (byte) (keyb[i] ^ 0x36); 95 | k_opad[i] = (byte) (keyb[i] ^ 0x5c); 96 | } 97 | 98 | MessageDigest md = null; 99 | try { 100 | md = MessageDigest.getInstance("SHA"); 101 | } catch (NoSuchAlgorithmException e) { 102 | log.error(e.getMessage(), e); 103 | return null; 104 | } 105 | md.update(k_ipad); 106 | md.update(value); 107 | byte dg[] = md.digest(); 108 | md.reset(); 109 | md.update(k_opad); 110 | md.update(dg, 0, 20); 111 | dg = md.digest(); 112 | return ConvertUtils.toHex(dg); 113 | } 114 | 115 | public static String digest(String aValue) { 116 | return digest(aValue, ENCODE); 117 | 118 | } 119 | 120 | public static String digest(String aValue, String encoding) { 121 | aValue = aValue.trim(); 122 | byte value[]; 123 | try { 124 | value = aValue.getBytes(encoding); 125 | } catch (UnsupportedEncodingException e) { 126 | value = aValue.getBytes(); 127 | } 128 | MessageDigest md = null; 129 | try { 130 | md = MessageDigest.getInstance("SHA"); 131 | } catch (NoSuchAlgorithmException e) { 132 | log.error(e.getMessage(), e); 133 | return null; 134 | } 135 | return ConvertUtils.toHex(md.digest(value)); 136 | } 137 | 138 | 139 | public static String digest(String aValue, String alg, String encoding) { 140 | aValue = aValue.trim(); 141 | byte value[]; 142 | try { 143 | value = aValue.getBytes(encoding); 144 | } catch (UnsupportedEncodingException e) { 145 | value = aValue.getBytes(); 146 | } 147 | MessageDigest md = null; 148 | try { 149 | md = MessageDigest.getInstance(alg); 150 | } catch (NoSuchAlgorithmException e) { 151 | log.error(e.getMessage(), e); 152 | return null; 153 | } 154 | return ConvertUtils.toHex(md.digest(value)); 155 | } 156 | 157 | public static String udpSign(String aValue) { 158 | try { 159 | byte[] input = aValue.getBytes("UTF-8"); 160 | MessageDigest md = MessageDigest.getInstance("SHA1"); 161 | return new String(Base64.encode(md.digest(input)), ENCODE); 162 | } catch (Exception e) { 163 | return null; 164 | } 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /src/main/java/com/wustrive/Main.java: -------------------------------------------------------------------------------- 1 | package com.wustrive; 2 | 3 | import java.util.TreeMap; 4 | 5 | import com.alibaba.fastjson.JSON; 6 | import com.alibaba.fastjson.JSONObject; 7 | import com.wustrive.aesrsa.util.AES; 8 | import com.wustrive.aesrsa.util.EncryUtil; 9 | import com.wustrive.aesrsa.util.RSA; 10 | import com.wustrive.aesrsa.util.RandomUtil; 11 | 12 | /** 13 | * 14 | * Description: AES+RSA签名,加密 验签,解密 15 | * 16 | * @author: wubaoguo 17 | * @email: wustrive2008@gmail.com 18 | * @date: 2015/8/13 15:12 19 | */ 20 | public class Main 21 | { 22 | public static final String clientPrivateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKbNojYr8KlqKD/y"+ 23 | "COd7QXu3e4TsrHd4sz3XgDYWEZZgYqIjVDcpcnlztwomgjMj9xSxdpyCc85GOGa0"+ 24 | "lva1fNZpG6KXYS1xuFa9G7FRbaACoCL31TRv8t4TNkfQhQ7e2S7ZktqyUePWYLlz"+ 25 | "u8hx5jXdriErRIx1jWK1q1NeEd3NAgMBAAECgYAws7Ob+4JeBLfRy9pbs/ovpCf1"+ 26 | "bKEClQRIlyZBJHpoHKZPzt7k6D4bRfT4irvTMLoQmawXEGO9o3UOT8YQLHdRLitW"+ 27 | "1CYKLy8k8ycyNpB/1L2vP+kHDzmM6Pr0IvkFgnbIFQmXeS5NBV+xOdlAYzuPFkCy"+ 28 | "fUSOKdmt3F/Pbf9EhQJBANrF5Uaxmk7qGXfRV7tCT+f27eAWtYi2h/gJenLrmtke"+ 29 | "Hg7SkgDiYHErJDns85va4cnhaAzAI1eSIHVaXh3JGXcCQQDDL9ns78LNDr/QuHN9"+ 30 | "pmeDdlQfikeDKzW8dMcUIqGVX4WQJMptviZuf3cMvgm9+hDTVLvSePdTlA9YSCF4"+ 31 | "VNPbAkEAvbe54XlpCKBIX7iiLRkPdGiV1qu614j7FqUZlAkvKrPMeywuQygNXHZ+"+ 32 | "HuGWTIUfItQfSFdjDrEBBuPMFGZtdwJAV5N3xyyIjfMJM4AfKYhpN333HrOvhHX1"+ 33 | "xVnsHOew8lGKnvMy9Gx11+xPISN/QYMa24dQQo5OAm0TOXwbsF73MwJAHzqaKZPs"+ 34 | "EN08JunWDOKs3ZS+92maJIm1YGdYf5ipB8/Bm3wElnJsCiAeRqYKmPpAMlCZ5x+Z"+ 35 | "AsuC1sjcp2r7xw=="; 36 | 37 | public static final String clientPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmzaI2K/Cpaig/8gjne0F7t3uE"+ 38 | "7Kx3eLM914A2FhGWYGKiI1Q3KXJ5c7cKJoIzI/cUsXacgnPORjhmtJb2tXzWaRui"+ 39 | "l2EtcbhWvRuxUW2gAqAi99U0b/LeEzZH0IUO3tku2ZLaslHj1mC5c7vIceY13a4h"+ 40 | "K0SMdY1itatTXhHdzQIDAQAB"; 41 | 42 | public static final String serverPrivateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALIZ98KqgLW8IMt4"+ 43 | "G+N+4d3DiOiEa+5s6lCMSGE/NbU9stJEqw0EuCP54MY6JkT0HCYTCrLXqww6rSQy"+ 44 | "WF7BNCVGssk2XDcvSKiCz1ZMgabd6XVK5kvIycySydXQ0Ky6rnfxw8w2mllHABFv"+ 45 | "s1eamaHQozv18n/XGqemjW2BFy/jAgMBAAECgYAxT3FCi3SBXKnzy7hk/z9H6Bhi"+ 46 | "0C8V3z/stzpe+mJDYOa+wtZdD15wT4HFQFpSIwgcHo+Kvp2UEDbZ27qN2Y43AZbF"+ 47 | "9LOalWTRUzYtr8wL8MIbgtew/QQ9YFNWdkTZ6MxCItjD/mSz3Lrkcphvbsx4VoCV"+ 48 | "YIJ04r+Loi0t9g0guQJBANvkpfrq0bLVRYWfaigjkx47mr0trJkB7mjADe69Iqts"+ 49 | "M/2x5dHPpClDK78yzAWxU2BrYzOd31QIOm32iMIvRxUCQQDPWJPMOzcq8Jqs1PAM"+ 50 | "7D0hxnvF3tSJB0CJCQWdGFkJiuIYSbrWnCVF78jJyU2AK1H3RDi9BzGPL2Z3i2Si"+ 51 | "+9kXAkAPnKtAJl3fEY9PDmNuGCCA3AB/f/eqIV345/HVSm5kt1j1oSTNAa4JE/DO"+ 52 | "MWAU42MlDFrNtl69y5vCZOeOyeaFAkBOJieGmWcAozDZJWTYqg2cdk/eU08t2nLj"+ 53 | "c2gPPscIRrVSzC9EhhOyWV8HVv0D6s/471inPlfajNYFBp/Goj+/AkEAiejHX/58"+ 54 | "Vv8+ccW22RMZmyxiHcZpTw9hz7vHUCWv03+fyVGtGMhJ4xuPt8UaZm91yHSPWWar"+ 55 | "M8Xa7errKaXN9A=="; 56 | public static final String serverPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyGffCqoC1vCDLeBvjfuHdw4jo"+ 57 | "hGvubOpQjEhhPzW1PbLSRKsNBLgj+eDGOiZE9BwmEwqy16sMOq0kMlhewTQlRrLJ"+ 58 | "Nlw3L0iogs9WTIGm3el1SuZLyMnMksnV0NCsuq538cPMNppZRwARb7NXmpmh0KM7"+ 59 | "9fJ/1xqnpo1tgRcv4wIDAQAB"; 60 | 61 | public static void main(String[] args) throws Exception { 62 | TreeMap params = new TreeMap(); 63 | params.put("userid", "152255855"); 64 | params.put("phone", "18965621420"); 65 | 66 | client(params); 67 | 68 | server(); 69 | } 70 | 71 | public static void client(TreeMap params) throws Exception{ 72 | // 生成RSA签名 73 | String sign = EncryUtil.handleRSA(params, clientPrivateKey); 74 | params.put("sign", sign); 75 | 76 | String info = JSON.toJSONString(params); 77 | //随机生成AES密钥 78 | String aesKey = RandomUtil.getRandom(16); 79 | //AES加密数据 80 | String data = AES.encryptToBase64(info, aesKey); 81 | 82 | // 使用RSA算法将商户自己随机生成的AESkey加密 83 | String encryptkey = RSA.encrypt(aesKey, serverPublicKey); 84 | 85 | Req.data = data; 86 | Req.encryptkey = encryptkey; 87 | 88 | System.out.println("加密后的请求数据:\n" + new Req().toString()); 89 | } 90 | 91 | public static void server() throws Exception { 92 | 93 | // 验签 94 | boolean passSign = EncryUtil.checkDecryptAndSign(Req.data, 95 | Req.encryptkey, clientPublicKey, serverPrivateKey); 96 | 97 | if(passSign){ 98 | // 验签通过 99 | String aeskey = RSA.decrypt(Req.encryptkey, 100 | serverPrivateKey); 101 | String data = AES.decryptFromBase64(Req.data, 102 | aeskey); 103 | 104 | JSONObject jsonObj = JSONObject.parseObject(data); 105 | String userid = jsonObj.getString("userid"); 106 | String phone = jsonObj.getString("phone"); 107 | 108 | System.out.println("解密后的明文:userid:"+userid+" phone:"+phone); 109 | 110 | }else{ 111 | System.out.println("验签失败"); 112 | } 113 | } 114 | 115 | static class Req{ 116 | public static String data; 117 | public static String encryptkey; 118 | 119 | @Override 120 | public String toString() { 121 | return "data:"+data+"\nencryptkey:"+encryptkey; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/com/wustrive/aesrsa/util/RSA.java: -------------------------------------------------------------------------------- 1 | package com.wustrive.aesrsa.util; 2 | 3 | /* 4 | --------------------------------------------**********-------------------------------------------- 5 | 6 | 该算法于1977年由美国麻省理工学院MIT(Massachusetts Institute of Technology)的Ronal Rivest,Adi Shamir和Len Adleman三位年轻教授提出,并以三人的姓氏Rivest,Shamir和Adlernan命名为RSA算法,是一个支持变长密钥的公共密钥算法,需要加密的文件快的长度也是可变的! 7 | 8 | 所谓RSA加密算法,是世界上第一个非对称加密算法,也是数论的第一个实际应用。它的算法如下: 9 | 10 | 1.找两个非常大的质数p和q(通常p和q都有155十进制位或都有512十进制位)并计算n=pq,k=(p-1)(q-1)。 11 | 12 | 2.将明文编码成整数M,保证M不小于0但是小于n。 13 | 14 | 3.任取一个整数e,保证e和k互质,而且e不小于0但是小于k。加密钥匙(称作公钥)是(e, n)。 15 | 16 | 4.找到一个整数d,使得ed除以k的余数是1(只要e和n满足上面条件,d肯定存在)。解密钥匙(称作密钥)是(d, n)。 17 | 18 | 加密过程: 加密后的编码C等于M的e次方除以n所得的余数。 19 | 20 | 解密过程: 解密后的编码N等于C的d次方除以n所得的余数。 21 | 22 | 只要e、d和n满足上面给定的条件。M等于N。 23 | 24 | --------------------------------------------**********-------------------------------------------- 25 | */ 26 | import java.math.BigInteger; 27 | import java.security.Key; 28 | import java.security.KeyFactory; 29 | import java.security.KeyPair; 30 | import java.security.KeyPairGenerator; 31 | import java.security.PrivateKey; 32 | import java.security.PublicKey; 33 | import java.security.SecureRandom; 34 | import java.security.Signature; 35 | import java.security.interfaces.RSAPublicKey; 36 | import java.security.spec.PKCS8EncodedKeySpec; 37 | import java.security.spec.X509EncodedKeySpec; 38 | import java.util.HashMap; 39 | import java.util.Map; 40 | 41 | import javax.crypto.Cipher; 42 | 43 | import org.apache.log4j.Logger; 44 | 45 | public class RSA { 46 | private static final Logger log = Logger.getLogger(RSA.class); 47 | /** 指定key的大小 */ 48 | private static int KEYSIZE = 1024; 49 | /** 50 | * 生成密钥对 51 | */ 52 | public static Map generateKeyPair() throws Exception { 53 | /** RSA算法要求有一个可信任的随机数源 */ 54 | SecureRandom sr = new SecureRandom(); 55 | /** 为RSA算法创建一个KeyPairGenerator对象 */ 56 | KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); 57 | /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */ 58 | kpg.initialize(KEYSIZE, sr); 59 | /** 生成密匙对 */ 60 | KeyPair kp = kpg.generateKeyPair(); 61 | /** 得到公钥 */ 62 | Key publicKey = kp.getPublic(); 63 | byte[] publicKeyBytes = publicKey.getEncoded(); 64 | String pub = new String(Base64.encodeBase64(publicKeyBytes), 65 | ConfigureEncryptAndDecrypt.CHAR_ENCODING); 66 | /** 得到私钥 */ 67 | Key privateKey = kp.getPrivate(); 68 | byte[] privateKeyBytes = privateKey.getEncoded(); 69 | String pri = new String(Base64.encodeBase64(privateKeyBytes), 70 | ConfigureEncryptAndDecrypt.CHAR_ENCODING); 71 | 72 | Map map = new HashMap(); 73 | map.put("publicKey", pub); 74 | map.put("privateKey", pri); 75 | RSAPublicKey rsp = (RSAPublicKey) kp.getPublic(); 76 | BigInteger bint = rsp.getModulus(); 77 | byte[] b = bint.toByteArray(); 78 | byte[] deBase64Value = Base64.encodeBase64(b); 79 | String retValue = new String(deBase64Value); 80 | map.put("modulus", retValue); 81 | return map; 82 | } 83 | 84 | /** 85 | * 加密方法 source: 源数据 86 | */ 87 | public static String encrypt(String source, String publicKey) 88 | throws Exception { 89 | Key key = getPublicKey(publicKey); 90 | /** 得到Cipher对象来实现对源数据的RSA加密 */ 91 | Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.RSA_ALGORITHM); 92 | cipher.init(Cipher.ENCRYPT_MODE, key); 93 | byte[] b = source.getBytes(); 94 | /** 执行加密操作 */ 95 | byte[] b1 = cipher.doFinal(b); 96 | return new String(Base64.encodeBase64(b1), 97 | ConfigureEncryptAndDecrypt.CHAR_ENCODING); 98 | } 99 | 100 | /** 101 | * 解密算法 cryptograph:密文 102 | */ 103 | public static String decrypt(String cryptograph, String privateKey) 104 | throws Exception { 105 | Key key = getPrivateKey(privateKey); 106 | /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */ 107 | Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.RSA_ALGORITHM); 108 | cipher.init(Cipher.DECRYPT_MODE, key); 109 | byte[] b1 = Base64.decodeBase64(cryptograph.getBytes()); 110 | /** 执行解密操作 */ 111 | byte[] b = cipher.doFinal(b1); 112 | return new String(b); 113 | } 114 | 115 | /** 116 | * 得到公钥 117 | * 118 | * @param key 119 | * 密钥字符串(经过base64编码) 120 | * @throws Exception 121 | */ 122 | public static PublicKey getPublicKey(String key) throws Exception { 123 | X509EncodedKeySpec keySpec = new X509EncodedKeySpec( 124 | Base64.decodeBase64(key.getBytes())); 125 | KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 126 | PublicKey publicKey = keyFactory.generatePublic(keySpec); 127 | return publicKey; 128 | } 129 | 130 | /** 131 | * 得到私钥 132 | * 133 | * @param key 134 | * 密钥字符串(经过base64编码) 135 | * @throws Exception 136 | */ 137 | public static PrivateKey getPrivateKey(String key) throws Exception { 138 | PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec( 139 | Base64.decodeBase64(key.getBytes())); 140 | KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 141 | PrivateKey privateKey = keyFactory.generatePrivate(keySpec); 142 | return privateKey; 143 | } 144 | 145 | public static String sign(String content, String privateKey) { 146 | String charset = ConfigureEncryptAndDecrypt.CHAR_ENCODING; 147 | try { 148 | PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec( 149 | Base64.decodeBase64(privateKey.getBytes())); 150 | KeyFactory keyf = KeyFactory.getInstance("RSA"); 151 | PrivateKey priKey = keyf.generatePrivate(priPKCS8); 152 | 153 | Signature signature = Signature.getInstance("SHA1WithRSA"); 154 | 155 | signature.initSign(priKey); 156 | signature.update(content.getBytes(charset)); 157 | 158 | byte[] signed = signature.sign(); 159 | 160 | return new String(Base64.encodeBase64(signed)); 161 | } catch (Exception e) { 162 | 163 | } 164 | 165 | return null; 166 | } 167 | 168 | public static boolean checkSign(String content, String sign, String publicKey) 169 | { 170 | try 171 | { 172 | KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 173 | byte[] encodedKey = Base64.decode2(publicKey); 174 | PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); 175 | 176 | 177 | java.security.Signature signature = java.security.Signature 178 | .getInstance("SHA1WithRSA"); 179 | 180 | signature.initVerify(pubKey); 181 | signature.update( content.getBytes("utf-8") ); 182 | 183 | boolean bverify = signature.verify( Base64.decode2(sign) ); 184 | return bverify; 185 | 186 | } 187 | catch (Exception e) 188 | { 189 | log.error(e.getMessage(), e); 190 | } 191 | 192 | return false; 193 | } 194 | 195 | } -------------------------------------------------------------------------------- /src/main/java/com/wustrive/aesrsa/util/ConvertUtils.java: -------------------------------------------------------------------------------- 1 | package com.wustrive.aesrsa.util; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.sql.Date; 5 | import java.sql.Time; 6 | import java.sql.Timestamp; 7 | import java.text.DecimalFormat; 8 | import java.util.Calendar; 9 | import java.util.GregorianCalendar; 10 | import java.util.Locale; 11 | import java.util.TimeZone; 12 | 13 | public abstract class ConvertUtils { 14 | 15 | private static final DecimalFormat simpleFormat = new DecimalFormat("####"); 16 | 17 | public static final boolean objectToBoolean(Object o){ 18 | return o != null ? Boolean.valueOf(o.toString()).booleanValue() : false; 19 | } 20 | 21 | public static final int objectToInt(Object o){ 22 | if(o instanceof Number) 23 | return ((Number)o).intValue(); 24 | try{ 25 | if(o == null) 26 | return -1; 27 | else 28 | return Integer.parseInt(o.toString()); 29 | }catch(NumberFormatException e){ 30 | return -1; 31 | } 32 | } 33 | 34 | public static final short objectToShort(Object o){ 35 | if(o instanceof Number) 36 | return ((Number)o).shortValue(); 37 | try{ 38 | if(o == null) 39 | return -1; 40 | else 41 | return Short.parseShort(o.toString()); 42 | }catch(NumberFormatException e){ 43 | return -1; 44 | } 45 | } 46 | 47 | public static final double objectToDouble(Object o){ 48 | if(o instanceof Number) 49 | return ((Number)o).doubleValue(); 50 | try{ 51 | if(o == null) 52 | return -1D; 53 | else 54 | return Double.parseDouble(o.toString()); 55 | }catch(NumberFormatException e){ 56 | return -1D; 57 | } 58 | } 59 | 60 | public static final long objectToLong(Object o) 61 | { 62 | if(o instanceof Number) 63 | return ((Number)o).longValue(); 64 | try{ 65 | if(o == null) 66 | return -1L; 67 | else 68 | return Long.parseLong(o.toString()); 69 | }catch(NumberFormatException e){ 70 | return -1L; 71 | } 72 | } 73 | 74 | public static final String objectToString(Object obj, DecimalFormat fmt) 75 | { 76 | fmt.setDecimalSeparatorAlwaysShown(false); 77 | if(obj instanceof Double) 78 | return fmt.format(((Double)obj).doubleValue()); 79 | if(obj instanceof Long) 80 | return fmt.format(((Long)obj).longValue()); 81 | else 82 | return obj.toString(); 83 | } 84 | 85 | public static final Object getObjectValue(String value) 86 | { 87 | try{ 88 | return Long.valueOf(value); 89 | }catch(NumberFormatException e) {} 90 | 91 | try{ 92 | return Double.valueOf(value); 93 | }catch(NumberFormatException e){ 94 | return value; 95 | } 96 | } 97 | 98 | public static String longToSimpleString(long value){ 99 | return simpleFormat.format(value); 100 | } 101 | 102 | public static String asHex(byte hash[]){ 103 | return toHex(hash); 104 | } 105 | 106 | public static String toHex(byte input[]){ 107 | if(input == null) 108 | return null; 109 | StringBuffer output = new StringBuffer(input.length * 2); 110 | for(int i = 0; i < input.length; i++){ 111 | int current = input[i] & 0xff; 112 | if(current < 16) 113 | output.append("0"); 114 | output.append(Integer.toString(current, 16)); 115 | } 116 | 117 | return output.toString(); 118 | } 119 | 120 | public static byte[] fromHex(String input){ 121 | if(input == null) 122 | return null; 123 | byte output[] = new byte[input.length() / 2]; 124 | for(int i = 0; i < output.length; i++) 125 | output[i] = (byte)Integer.parseInt(input.substring(i * 2, (i + 1) * 2), 16); 126 | 127 | return output; 128 | } 129 | 130 | public static String stringToHexString(String input, String encoding) 131 | throws UnsupportedEncodingException{ 132 | return input != null ? toHex(input.getBytes(encoding)) : null; 133 | } 134 | 135 | public static String stringToHexString(String input){ 136 | try{ 137 | return stringToHexString(input, "UTF-8"); 138 | }catch(UnsupportedEncodingException e){ 139 | throw new IllegalStateException("UTF-8 encoding is not supported by JVM"); 140 | } 141 | } 142 | 143 | public static String hexStringToString(String input, String encoding) 144 | throws UnsupportedEncodingException{ 145 | return input != null ? new String(fromHex(input), encoding) : null; 146 | } 147 | 148 | public static String hexStringToString(String input){ 149 | try{ 150 | return hexStringToString(input, "UTF-8"); 151 | }catch(UnsupportedEncodingException e){ 152 | throw new IllegalStateException("UTF-8 encoding is not supported by JVM"); 153 | } 154 | } 155 | 156 | public static String timeZoneToCode(TimeZone tz){ 157 | 158 | return timeZoneToString(tz); 159 | } 160 | 161 | public static TimeZone codeToTimeZone(String tzString){ 162 | 163 | return stringToTimeZone(tzString); 164 | } 165 | 166 | public static String timeZoneToString(TimeZone tz){ 167 | 168 | return tz != null ? tz.getID() : ""; 169 | } 170 | 171 | public static TimeZone stringToTimeZone(String tzString){ 172 | 173 | return TimeZone.getTimeZone(tzString != null ? tzString : ""); 174 | } 175 | 176 | public static String localeToCode(Locale aLocale){ 177 | 178 | return localeToString(aLocale); 179 | } 180 | 181 | public static Locale codeToLocale(String locString){ 182 | 183 | return stringToLocale(locString); 184 | } 185 | 186 | public static String localeToString(Locale loc){ 187 | 188 | return loc != null ? loc.toString() : ""; 189 | } 190 | 191 | public static Locale stringToLocale(String locString){ 192 | 193 | locString = locString != null ? locString.trim() : ""; 194 | if(locString.equals("")) 195 | return new Locale("", "", ""); 196 | int pos = locString.indexOf(95); 197 | if(pos == -1) 198 | return new Locale(locString, "", ""); 199 | String language = locString.substring(0, pos); 200 | locString = locString.substring(pos + 1); 201 | pos = locString.indexOf(95); 202 | if(pos == -1){ 203 | return new Locale(language, locString, ""); 204 | }else{ 205 | String country = locString.substring(0, pos); 206 | locString = locString.substring(pos + 1); 207 | return new Locale(language, country, locString); 208 | } 209 | } 210 | 211 | public static Date dateToSQLDate(java.util.Date d){ 212 | 213 | return d != null ? new Date(d.getTime()) : null; 214 | } 215 | 216 | public static Time dateToSQLTime(java.util.Date d){ 217 | 218 | return d != null ? new Time(d.getTime()) : null; 219 | } 220 | 221 | public static Timestamp dateToSQLTimestamp(java.util.Date d){ 222 | 223 | return d != null ? new Timestamp(d.getTime()) : null; 224 | } 225 | 226 | public static java.util.Date sqlTimestampToDate(Timestamp t){ 227 | 228 | return t != null ? new java.util.Date(Math.round((double)t.getTime() + (double)t.getNanos() / 1000000D)) : null; 229 | } 230 | 231 | public static Timestamp getCurrentDate(){ 232 | 233 | Calendar c = Calendar.getInstance(); 234 | c.set(c.get(1), c.get(2), c.get(5), 0, 0, 0); 235 | Timestamp t = new Timestamp(c.getTime().getTime()); 236 | t.setNanos(0); 237 | return t; 238 | } 239 | 240 | public static java.util.Date getDate(int y, int m, int d, boolean inclusive) 241 | { 242 | java.util.Date dt = null; 243 | Calendar c = Calendar.getInstance(); 244 | c.clear(); 245 | if(c.getActualMinimum(1) <= y && y <= c.getActualMaximum(1)) 246 | { 247 | c.set(1, y); 248 | if(c.getActualMinimum(2) <= m && m <= c.getActualMaximum(2)) 249 | { 250 | c.set(2, m); 251 | if(c.getActualMinimum(5) <= d && d <= c.getActualMaximum(5)) 252 | c.set(5, d); 253 | } 254 | if(inclusive) 255 | { 256 | c.add(5, 1); 257 | c.add(14, -1); 258 | } 259 | dt = c.getTime(); 260 | } 261 | return dt; 262 | } 263 | 264 | public static java.util.Date getDateStart(java.util.Date d) 265 | { 266 | 267 | Calendar c = new GregorianCalendar(); 268 | c.clear(); 269 | Calendar co = new GregorianCalendar(); 270 | co.setTime(d); 271 | c.set(Calendar.DAY_OF_MONTH,co.get(Calendar.DAY_OF_MONTH)); 272 | c.set(Calendar.MONTH,co.get(Calendar.MONTH)); 273 | c.set(Calendar.YEAR,co.get(Calendar.YEAR)); 274 | //c.add(Calendar.DAY_OF_MONTH,1); 275 | //c.add(Calendar.MILLISECOND,-1); 276 | return c.getTime(); 277 | } 278 | 279 | public static java.util.Date getDateEnd(java.util.Date d) 280 | { 281 | Calendar c = Calendar.getInstance(); 282 | c.clear(); 283 | Calendar co = Calendar.getInstance(); 284 | co.setTime(d); 285 | c.set(Calendar.DAY_OF_MONTH,co.get(Calendar.DAY_OF_MONTH)); 286 | c.set(Calendar.MONTH,co.get(Calendar.MONTH)); 287 | c.set(Calendar.YEAR,co.get(Calendar.YEAR)); 288 | c.add(Calendar.DAY_OF_MONTH,1); 289 | c.add(Calendar.MILLISECOND,-1); 290 | return c.getTime(); 291 | } 292 | 293 | public static double roundNumber(double rowNumber, int roundingPoint) 294 | { 295 | double base = Math.pow(10D, roundingPoint); 296 | return (double)Math.round(rowNumber * base) / base; 297 | } 298 | public static Object getObject(String type,String value) throws Exception{ 299 | 300 | type=type.toLowerCase(); 301 | if("boolean".equals(type)) 302 | return Boolean.valueOf(value); 303 | if("byte".equals(type)) 304 | return Byte.valueOf(value); 305 | if("short".equals(type)) 306 | return Short.valueOf(value); 307 | if("char".equals(type)) 308 | if(value.length() != 1) 309 | throw new NumberFormatException("Argument is not a character!"); 310 | else 311 | return Character.valueOf(value.toCharArray()[0]); 312 | if("int".equals(type)) 313 | return Integer.valueOf(value); 314 | if("long".equals(type)) 315 | return Long.valueOf(value); 316 | if("float".equals(type)) 317 | return Float.valueOf(value); 318 | if("double".equals(type)) 319 | return Double.valueOf(value); 320 | if("string".equals(type)) 321 | return value; 322 | else{ 323 | Object objs[]=new String[]{value}; 324 | return Class.forName(type).getConstructor(new Class[] { 325 | java.lang.String.class 326 | }).newInstance(objs); 327 | } 328 | } 329 | private ConvertUtils(){} 330 | 331 | // public static void main(String[] args) 332 | // { 333 | // System.out.println(getDateStart(new java.util.Date())); 334 | // } 335 | } 336 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /src/main/java/com/wustrive/aesrsa/util/Base64.java: -------------------------------------------------------------------------------- 1 | package com.wustrive.aesrsa.util; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | 5 | public class Base64 { 6 | /** 7 | * Chunk size per RFC 2045 section 6.8. 8 | * 9 | *

The {@value} character limit does not count the trailing CRLF, but counts 10 | * all other characters, including any equal signs.

11 | * 12 | * @see RFC 2045 section 6.8 13 | */ 14 | static final int CHUNK_SIZE = 76; 15 | 16 | /** 17 | * Chunk separator per RFC 2045 section 2.1. 18 | * 19 | * @see RFC 2045 section 2.1 20 | */ 21 | static final byte[] CHUNK_SEPARATOR = "\r\n".getBytes(); 22 | 23 | /** 24 | * The base length. 25 | */ 26 | static final int BASELENGTH = 255; 27 | 28 | /** 29 | * Lookup length. 30 | */ 31 | static final int LOOKUPLENGTH = 64; 32 | 33 | /** 34 | * Used to calculate the number of bits in a byte. 35 | */ 36 | static final int EIGHTBIT = 8; 37 | 38 | /** 39 | * Used when encoding something which has fewer than 24 bits. 40 | */ 41 | static final int SIXTEENBIT = 16; 42 | 43 | /** 44 | * Used to determine how many bits data contains. 45 | */ 46 | static final int TWENTYFOURBITGROUP = 24; 47 | 48 | /** 49 | * Used to get the number of Quadruples. 50 | */ 51 | static final int FOURBYTE = 4; 52 | 53 | /** 54 | * Used to test the sign of a byte. 55 | */ 56 | static final int SIGN = -128; 57 | 58 | /** 59 | * Byte used to pad output. 60 | */ 61 | static final byte PAD = (byte) '='; 62 | 63 | // Create arrays to hold the base64 characters and a 64 | // lookup for base64 chars 65 | private static byte[] base64Alphabet = new byte[BASELENGTH]; 66 | private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; 67 | 68 | // Populating the lookup and character arrays 69 | static { 70 | for (int i = 0; i < BASELENGTH; i++) { 71 | base64Alphabet[i] = (byte) -1; 72 | } 73 | for (int i = 'Z'; i >= 'A'; i--) { 74 | base64Alphabet[i] = (byte) (i - 'A'); 75 | } 76 | for (int i = 'z'; i >= 'a'; i--) { 77 | base64Alphabet[i] = (byte) (i - 'a' + 26); 78 | } 79 | for (int i = '9'; i >= '0'; i--) { 80 | base64Alphabet[i] = (byte) (i - '0' + 52); 81 | } 82 | 83 | base64Alphabet['+'] = 62; 84 | base64Alphabet['/'] = 63; 85 | 86 | for (int i = 0; i <= 25; i++) { 87 | lookUpBase64Alphabet[i] = (byte) ('A' + i); 88 | } 89 | 90 | for (int i = 26, j = 0; i <= 51; i++, j++) { 91 | lookUpBase64Alphabet[i] = (byte) ('a' + j); 92 | } 93 | 94 | for (int i = 52, j = 0; i <= 61; i++, j++) { 95 | lookUpBase64Alphabet[i] = (byte) ('0' + j); 96 | } 97 | 98 | lookUpBase64Alphabet[62] = (byte) '+'; 99 | lookUpBase64Alphabet[63] = (byte) '/'; 100 | } 101 | 102 | private static boolean isBase64(byte octect) { 103 | if (octect == PAD) { 104 | return true; 105 | } else if (base64Alphabet[octect] == -1) { 106 | return false; 107 | } else { 108 | return true; 109 | } 110 | } 111 | 112 | /** 113 | * Tests a given byte array to see if it contains 114 | * only valid characters within the Base64 alphabet. 115 | * 116 | * @param arrayOctect byte array to test 117 | * @return true if all bytes are valid characters in the Base64 118 | * alphabet or if the byte array is empty; false, otherwise 119 | */ 120 | public static boolean isArrayByteBase64(byte[] arrayOctect) { 121 | 122 | arrayOctect = discardWhitespace(arrayOctect); 123 | 124 | int length = arrayOctect.length; 125 | if (length == 0) { 126 | // shouldn't a 0 length array be valid base64 data? 127 | // return false; 128 | return true; 129 | } 130 | for (int i = 0; i < length; i++) { 131 | if (!isBase64(arrayOctect[i])) { 132 | return false; 133 | } 134 | } 135 | return true; 136 | } 137 | 138 | /** 139 | * Encodes binary data using the base64 algorithm but 140 | * does not chunk the output. 141 | * 142 | * @param binaryData binary data to encode 143 | * @return Base64 characters 144 | */ 145 | public static byte[] encodeBase64(byte[] binaryData) { 146 | return encodeBase64(binaryData, false); 147 | } 148 | 149 | /** 150 | * Encodes binary data using the base64 algorithm and chunks 151 | * the encoded output into 76 character blocks 152 | * 153 | * @param binaryData binary data to encode 154 | * @return Base64 characters chunked in 76 character blocks 155 | */ 156 | public static byte[] encodeBase64Chunked(byte[] binaryData) { 157 | return encodeBase64(binaryData, true); 158 | } 159 | 160 | /** 161 | * Decodes a byte[] containing containing 162 | * characters in the Base64 alphabet. 163 | * 164 | * @param pArray A byte array containing Base64 character data 165 | * @return a byte array containing binary data 166 | */ 167 | public static byte[] decode(byte[] pArray) { 168 | return decodeBase64(pArray); 169 | } 170 | 171 | /** 172 | * Encodes binary data using the base64 algorithm, optionally 173 | * chunking the output into 76 character blocks. 174 | * 175 | * @param binaryData Array containing binary data to encode. 176 | * @param isChunked if isChunked is true this encoder will chunk 177 | * the base64 output into 76 character blocks 178 | * @return Base64-encoded data. 179 | */ 180 | public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) { 181 | int lengthDataBits = binaryData.length * EIGHTBIT; 182 | int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; 183 | int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; 184 | byte encodedData[] = null; 185 | int encodedDataLength = 0; 186 | int nbrChunks = 0; 187 | 188 | if (fewerThan24bits != 0) { 189 | //data not divisible by 24 bit 190 | encodedDataLength = (numberTriplets + 1) * 4; 191 | } else { 192 | // 16 or 8 bit 193 | encodedDataLength = numberTriplets * 4; 194 | } 195 | 196 | // If the output is to be "chunked" into 76 character sections, 197 | // for compliance with RFC 2045 MIME, then it is important to 198 | // allow for extra length to account for the separator(s) 199 | if (isChunked) { 200 | 201 | nbrChunks = 202 | (CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math.ceil((float) encodedDataLength / CHUNK_SIZE)); 203 | encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length; 204 | } 205 | 206 | encodedData = new byte[encodedDataLength]; 207 | 208 | byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; 209 | 210 | int encodedIndex = 0; 211 | int dataIndex = 0; 212 | int i = 0; 213 | int nextSeparatorIndex = CHUNK_SIZE; 214 | int chunksSoFar = 0; 215 | 216 | //log.debug("number of triplets = " + numberTriplets); 217 | for (i = 0; i < numberTriplets; i++) { 218 | dataIndex = i * 3; 219 | b1 = binaryData[dataIndex]; 220 | b2 = binaryData[dataIndex + 1]; 221 | b3 = binaryData[dataIndex + 2]; 222 | 223 | //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3); 224 | 225 | l = (byte) (b2 & 0x0f); 226 | k = (byte) (b1 & 0x03); 227 | 228 | byte val1 = 229 | ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 230 | byte val2 = 231 | ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); 232 | byte val3 = 233 | ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); 234 | 235 | encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; 236 | //log.debug( "val2 = " + val2 ); 237 | //log.debug( "k4 = " + (k<<4) ); 238 | //log.debug( "vak = " + (val2 | (k<<4)) ); 239 | encodedData[encodedIndex + 1] = 240 | lookUpBase64Alphabet[val2 | (k << 4)]; 241 | encodedData[encodedIndex + 2] = 242 | lookUpBase64Alphabet[(l << 2) | val3]; 243 | encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f]; 244 | 245 | encodedIndex += 4; 246 | 247 | // If we are chunking, let's put a chunk separator down. 248 | if (isChunked) { 249 | // this assumes that CHUNK_SIZE % 4 == 0 250 | if (encodedIndex == nextSeparatorIndex) { 251 | System.arraycopy( 252 | CHUNK_SEPARATOR, 253 | 0, 254 | encodedData, 255 | encodedIndex, 256 | CHUNK_SEPARATOR.length); 257 | chunksSoFar++; 258 | nextSeparatorIndex = 259 | (CHUNK_SIZE * (chunksSoFar + 1)) + 260 | (chunksSoFar * CHUNK_SEPARATOR.length); 261 | encodedIndex += CHUNK_SEPARATOR.length; 262 | } 263 | } 264 | } 265 | 266 | // form integral number of 6-bit groups 267 | dataIndex = i * 3; 268 | 269 | if (fewerThan24bits == EIGHTBIT) { 270 | b1 = binaryData[dataIndex]; 271 | k = (byte) (b1 & 0x03); 272 | //log.debug("b1=" + b1); 273 | //log.debug("b1<<2 = " + (b1>>2) ); 274 | byte val1 = 275 | ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 276 | encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; 277 | encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4]; 278 | encodedData[encodedIndex + 2] = PAD; 279 | encodedData[encodedIndex + 3] = PAD; 280 | } else if (fewerThan24bits == SIXTEENBIT) { 281 | 282 | b1 = binaryData[dataIndex]; 283 | b2 = binaryData[dataIndex + 1]; 284 | l = (byte) (b2 & 0x0f); 285 | k = (byte) (b1 & 0x03); 286 | 287 | byte val1 = 288 | ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 289 | byte val2 = 290 | ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); 291 | 292 | encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; 293 | encodedData[encodedIndex + 1] = 294 | lookUpBase64Alphabet[val2 | (k << 4)]; 295 | encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2]; 296 | encodedData[encodedIndex + 3] = PAD; 297 | } 298 | 299 | if (isChunked) { 300 | // we also add a separator to the end of the final chunk. 301 | if (chunksSoFar < nbrChunks) { 302 | System.arraycopy( 303 | CHUNK_SEPARATOR, 304 | 0, 305 | encodedData, 306 | encodedDataLength - CHUNK_SEPARATOR.length, 307 | CHUNK_SEPARATOR.length); 308 | } 309 | } 310 | 311 | return encodedData; 312 | } 313 | 314 | /** 315 | * Decodes Base64 data into octects 316 | * 317 | * @param base64Data Byte array containing Base64 data 318 | * @return Array containing decoded data. 319 | */ 320 | public static byte[] decodeBase64(byte[] base64Data) { 321 | // RFC 2045 requires that we discard ALL non-Base64 characters 322 | base64Data = discardNonBase64(base64Data); 323 | 324 | // handle the edge case, so we don't have to worry about it later 325 | if (base64Data.length == 0) { 326 | return new byte[0]; 327 | } 328 | 329 | int numberQuadruple = base64Data.length / FOURBYTE; 330 | byte decodedData[] = null; 331 | byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; 332 | 333 | // Throw away anything not in base64Data 334 | 335 | int encodedIndex = 0; 336 | int dataIndex = 0; 337 | { 338 | // this sizes the output array properly - rlw 339 | int lastData = base64Data.length; 340 | // ignore the '=' padding 341 | while (base64Data[lastData - 1] == PAD) { 342 | if (--lastData == 0) { 343 | return new byte[0]; 344 | } 345 | } 346 | decodedData = new byte[lastData - numberQuadruple]; 347 | } 348 | 349 | for (int i = 0; i < numberQuadruple; i++) { 350 | dataIndex = i * 4; 351 | marker0 = base64Data[dataIndex + 2]; 352 | marker1 = base64Data[dataIndex + 3]; 353 | 354 | b1 = base64Alphabet[base64Data[dataIndex]]; 355 | b2 = base64Alphabet[base64Data[dataIndex + 1]]; 356 | 357 | if (marker0 != PAD && marker1 != PAD) { 358 | //No PAD e.g 3cQl 359 | b3 = base64Alphabet[marker0]; 360 | b4 = base64Alphabet[marker1]; 361 | 362 | decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 363 | decodedData[encodedIndex + 1] = 364 | (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 365 | decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4); 366 | } else if (marker0 == PAD) { 367 | //Two PAD e.g. 3c[Pad][Pad] 368 | decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 369 | } else if (marker1 == PAD) { 370 | //One PAD e.g. 3cQ[Pad] 371 | b3 = base64Alphabet[marker0]; 372 | 373 | decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 374 | decodedData[encodedIndex + 1] = 375 | (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 376 | } 377 | encodedIndex += 3; 378 | } 379 | return decodedData; 380 | } 381 | 382 | /** 383 | * Discards any whitespace from a base-64 encoded block. 384 | * 385 | * @param data The base-64 encoded data to discard the whitespace 386 | * from. 387 | * @return The data, less whitespace (see RFC 2045). 388 | */ 389 | static byte[] discardWhitespace(byte[] data) { 390 | byte groomedData[] = new byte[data.length]; 391 | int bytesCopied = 0; 392 | 393 | for (int i = 0; i < data.length; i++) { 394 | switch (data[i]) { 395 | case (byte) ' ' : 396 | case (byte) '\n' : 397 | case (byte) '\r' : 398 | case (byte) '\t' : 399 | break; 400 | default: 401 | groomedData[bytesCopied++] = data[i]; 402 | } 403 | } 404 | 405 | byte packedData[] = new byte[bytesCopied]; 406 | 407 | System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); 408 | 409 | return packedData; 410 | } 411 | 412 | /** 413 | * Discards any characters outside of the base64 alphabet, per 414 | * the requirements on page 25 of RFC 2045 - "Any characters 415 | * outside of the base64 alphabet are to be ignored in base64 416 | * encoded data." 417 | * 418 | * @param data The base-64 encoded data to groom 419 | * @return The data, less non-base64 characters (see RFC 2045). 420 | */ 421 | static byte[] discardNonBase64(byte[] data) { 422 | byte groomedData[] = new byte[data.length]; 423 | int bytesCopied = 0; 424 | 425 | for (int i = 0; i < data.length; i++) { 426 | if (isBase64(data[i])) { 427 | groomedData[bytesCopied++] = data[i]; 428 | } 429 | } 430 | 431 | byte packedData[] = new byte[bytesCopied]; 432 | 433 | System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); 434 | 435 | return packedData; 436 | } 437 | 438 | /** 439 | * Encodes a byte[] containing binary data, into a byte[] containing 440 | * characters in the Base64 alphabet. 441 | * 442 | * @param pArray a byte array containing binary data 443 | * @return A byte array containing only Base64 character data 444 | */ 445 | public static byte[] encode(byte[] pArray) { 446 | return encodeBase64(pArray, false); 447 | } 448 | 449 | public static String encode(String str) throws UnsupportedEncodingException 450 | { 451 | String baseStr = new String(encode(str.getBytes("UTF-8"))); 452 | String tempStr = Digest.digest(str).toUpperCase(); 453 | String result = tempStr+baseStr; 454 | return new String(encode(result.getBytes("UTF-8"))); 455 | } 456 | 457 | public static String decode(String cryptoStr) throws 458 | UnsupportedEncodingException { 459 | if(cryptoStr.length()<40) 460 | return ""; 461 | try 462 | { 463 | String tempStr = new String(decode(cryptoStr.getBytes("UTF-8"))); 464 | String result = tempStr.substring(40, tempStr.length()); 465 | return new String(decode(result.getBytes("UTF-8"))); 466 | } 467 | catch(java.lang.ArrayIndexOutOfBoundsException ex) 468 | { 469 | return ""; 470 | } 471 | } 472 | 473 | /** 474 | * Decodes Base64 data into octects 475 | * 476 | * @param encoded string containing Base64 data 477 | * @return Array containind decoded data. 478 | */ 479 | public static byte[] decode2(String encoded) { 480 | 481 | if (encoded == null) { 482 | return null; 483 | } 484 | 485 | char[] base64Data = encoded.toCharArray(); 486 | // remove white spaces 487 | int len = removeWhiteSpace(base64Data); 488 | 489 | if (len % FOURBYTE != 0) { 490 | return null;//should be divisible by four 491 | } 492 | 493 | int numberQuadruple = (len / FOURBYTE); 494 | 495 | if (numberQuadruple == 0) { 496 | return new byte[0]; 497 | } 498 | 499 | byte decodedData[] = null; 500 | byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; 501 | char d1 = 0, d2 = 0, d3 = 0, d4 = 0; 502 | 503 | int i = 0; 504 | int encodedIndex = 0; 505 | int dataIndex = 0; 506 | decodedData = new byte[(numberQuadruple) * 3]; 507 | 508 | for (; i < numberQuadruple - 1; i++) { 509 | 510 | if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])) 511 | || !isData((d3 = base64Data[dataIndex++])) 512 | || !isData((d4 = base64Data[dataIndex++]))) { 513 | return null; 514 | }//if found "no data" just return null 515 | 516 | b1 = base64Alphabet[d1]; 517 | b2 = base64Alphabet[d2]; 518 | b3 = base64Alphabet[d3]; 519 | b4 = base64Alphabet[d4]; 520 | 521 | decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 522 | decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 523 | decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); 524 | } 525 | 526 | if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) { 527 | return null;//if found "no data" just return null 528 | } 529 | 530 | b1 = base64Alphabet[d1]; 531 | b2 = base64Alphabet[d2]; 532 | 533 | d3 = base64Data[dataIndex++]; 534 | d4 = base64Data[dataIndex++]; 535 | if (!isData((d3)) || !isData((d4))) {//Check if they are PAD characters 536 | if (isPad(d3) && isPad(d4)) { 537 | if ((b2 & 0xf) != 0)//last 4 bits should be zero 538 | { 539 | return null; 540 | } 541 | byte[] tmp = new byte[i * 3 + 1]; 542 | System.arraycopy(decodedData, 0, tmp, 0, i * 3); 543 | tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 544 | return tmp; 545 | } else if (!isPad(d3) && isPad(d4)) { 546 | b3 = base64Alphabet[d3]; 547 | if ((b3 & 0x3) != 0)//last 2 bits should be zero 548 | { 549 | return null; 550 | } 551 | byte[] tmp = new byte[i * 3 + 2]; 552 | System.arraycopy(decodedData, 0, tmp, 0, i * 3); 553 | tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 554 | tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 555 | return tmp; 556 | } else { 557 | return null; 558 | } 559 | } else { //No PAD e.g 3cQl 560 | b3 = base64Alphabet[d3]; 561 | b4 = base64Alphabet[d4]; 562 | decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 563 | decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 564 | decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); 565 | 566 | } 567 | 568 | return decodedData; 569 | } 570 | 571 | private static boolean isWhiteSpace(char octect) { 572 | return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); 573 | } 574 | 575 | private static boolean isData(char octect) { 576 | return (octect < BASELENGTH && base64Alphabet[octect] != -1); 577 | } 578 | 579 | private static boolean isPad(char octect) { 580 | return (octect == PAD); 581 | } 582 | 583 | /** 584 | * remove WhiteSpace from MIME containing encoded Base64 data. 585 | * 586 | * @param data the byte array of base64 data (with WS) 587 | * @return the new length 588 | */ 589 | private static int removeWhiteSpace(char[] data) { 590 | if (data == null) { 591 | return 0; 592 | } 593 | 594 | // count characters that's not whitespace 595 | int newSize = 0; 596 | int len = data.length; 597 | for (int i = 0; i < len; i++) { 598 | if (!isWhiteSpace(data[i])) { 599 | data[newSize++] = data[i]; 600 | } 601 | } 602 | return newSize; 603 | } 604 | } 605 | --------------------------------------------------------------------------------