1. RSA算法介绍
RSA算法是一种非对称算法,即是加密的密码和解密的密码是不一致的。因此对RSA的加密和加密的密码分为公钥和私钥。根据RSA的算法介绍,只要密钥的长度足够长,现在没有任何方法可以破解。而且这个算法的专利已经在2000年9月21日失效,因此应该是可以任意使用的。
密钥获取:
选用PKCS#8生成密钥,选PKCS#1可能会导致解密失败
http://web.chacuo.net/netrsakeypair
1. javaweb使用RSA
1.1. 前端加密
要在前端加密密码,就要使用到jsencrypt的js
1.1.1. jsencrypt下载
官网:http://travistidwell.com/jsencrypt/
github: https://github.com/travist/jsencrypt/releases
在bin目录下面可以找到相关js:
1.1.2. 代码示例
1 //RSA加密 2 function encryptRequest(reqUrl, data) { 3 var publicKey = "****"; 4 var encrypt = new JSEncrypt(); 5 encrypt.setPublicKey(publicKey); 6 // ajax请求发送的数据对象 7 var password = ‘xxxx’; 8 // 将data数组赋给ajax对象 9 password = encrypt.encrypt(password ); 10 $.ajax({ 11 type: 'post', 12 url: reqUrl, 13 data: password, 14 async:false, 15 success: function(data){ 16 return false; 17 } 18 error : function(XMLResponse) { 19 var msg = XMLResponse.responseText; 20 console.log(msg); 21 } 22 }); 23 }
1.1. 后端解密
1.1.1. 相关工具类准备
1.1.1.1. Base64Utils
Base64工具类,可以让rsa编码的乱码变成一串字符序列
1 package cn.sinobest.common.misc; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 import java.io.File; 6 import java.io.FileInputStream; 7 import java.io.FileOutputStream; 8 import java.io.InputStream; 9 import java.io.OutputStream; 10 11 import org.apache.commons.codec.binary.Base64; 12 13 14 /** */ 15 /** 16 * <p> 17 * BASE64编码解码工具包 18 * </p> 19 * <p> 20 * 依赖javabase64-1.3.1.jar 21 * </p> 22 * 23 * @date 2012-5-19 24 * @version 1.0 25 */ 26 public class Base64Utils { 27 28 /** */ 29 /** 30 * 文件读取缓冲区大小 31 */ 32 private static final int CACHE_SIZE = 1024; 33 34 /** */ 35 /** 36 * <p> 37 * BASE64字符串解码为二进制数据 38 * </p> 39 * 40 * @param base64 41 * @return 42 * @throws Exception 43 */ 44 public static byte[] decode(String base64str) throws Exception { 45 Base64 base64 = new Base64(); 46 return base64.decode(base64str.getBytes()); 47 } 48 49 /** */ 50 /** 51 * <p> 52 * 二进制数据编码为BASE64字符串 53 * </p> 54 * 55 * @param bytes 56 * @return 57 * @throws Exception 58 */ 59 public static String encode(byte[] bytes) throws Exception { 60 Base64 base64 = new Base64(); 61 return new String(base64.encode(bytes)); 62 } 63 64 /** */ 65 /** 66 * <p> 67 * 将文件编码为BASE64字符串 68 * </p> 69 * <p> 70 * 大文件慎用,可能会导致内存溢出 71 * </p> 72 * 73 * @param filePath 74 * 文件绝对路径 75 * @return 76 * @throws Exception 77 */ 78 public static String encodeFile(String filePath) throws Exception { 79 byte[] bytes = fileToByte(filePath); 80 return encode(bytes); 81 } 82 83 /** */ 84 /** 85 * <p> 86 * BASE64字符串转回文件 87 * </p> 88 * 89 * @param filePath 90 * 文件绝对路径 91 * @param base64 92 * 编码字符串 93 * @throws Exception 94 */ 95 public static void decodeToFile(String filePath, String base64) throws Exception { 96 byte[] bytes = decode(base64); 97 byteArrayToFile(bytes, filePath); 98 } 99 100 /** */ 101 /** 102 * <p> 103 * 文件转换为二进制数组 104 * </p> 105 * 106 * @param filePath 107 * 文件路径 108 * @return 109 * @throws Exception 110 */ 111 public static byte[] fileToByte(String filePath) throws Exception { 112 byte[] data = new byte[0]; 113 File file = new File(filePath); 114 if (file.exists()) { 115 FileInputStream in = new FileInputStream(file); 116 ByteArrayOutputStream out = new ByteArrayOutputStream(2048); 117 byte[] cache = new byte[CACHE_SIZE]; 118 int nRead = 0; 119 while ((nRead = in.read(cache)) != -1) { 120 out.write(cache, 0, nRead); 121 out.flush(); 122 } 123 out.close(); 124 in.close(); 125 data = out.toByteArray(); 126 } 127 return data; 128 } 129 130 /** */ 131 /** 132 * <p> 133 * 二进制数据写文件 134 * </p> 135 * 136 * @param bytes 137 * 二进制数据 138 * @param filePath 139 * 文件生成目录 140 */ 141 public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception { 142 InputStream in = new ByteArrayInputStream(bytes); 143 File destFile = new File(filePath); 144 if (!destFile.getParentFile().exists()) { 145 destFile.getParentFile().mkdirs(); 146 } 147 destFile.createNewFile(); 148 OutputStream out = new FileOutputStream(destFile); 149 byte[] cache = new byte[CACHE_SIZE]; 150 int nRead = 0; 151 while ((nRead = in.read(cache)) != -1) { 152 out.write(cache, 0, nRead); 153 out.flush(); 154 } 155 out.close(); 156 in.close(); 157 } 158 159 }
1.1.1.1. RsaUtil
RsaUtil工具类,可以调用里面的方法,产生公钥私钥对,和采用公钥加密,私钥加密等
package cn.sinobest.common.misc; import java.io.ByteArrayOutputStream; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; /** */ /** * <p> * RSA公钥/私钥/签名工具包 * </p> * <p> * 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman) * </p> * <p> * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/> * 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/> * 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全 * </p> * * @version 1.0 */ public class RSAUtils { /** */ /** * 加密算法RSA */ public static final String KEY_ALGORITHM = "RSA"; /** */ /** * 签名算法 */ public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; /** */ /** * 获取公钥的key */ private static final String PUBLIC_KEY = "RSAPublicKey"; /** */ /** * 获取私钥的key */ private static final String PRIVATE_KEY = "RSAPrivateKey"; /** */ /** * RSA最大加密明文大小 */ private static final int MAX_ENCRYPT_BLOCK = 117; /** */ /** * RSA最大解密密文大小 */ private static final int MAX_DECRYPT_BLOCK = 128; /** */ /** * <p> * 生成密钥对(公钥和私钥) * </p> * * @return * @throws Exception */ public static Map<String, Object> genKeyPair() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } /** */ /** * <p> * 用私钥对信息生成数字签名 * </p> * * @param data * 已加密数据 * @param privateKey * 私钥(BASE64编码) * * @return * @throws Exception */ public static String sign(byte[] data, String privateKey) throws Exception { byte[] keyBytes = Base64Utils.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(privateK); signature.update(data); return Base64Utils.encode(signature.sign()); } /** */ /** * <p> * 校验数字签名 * </p> * * @param data * 已加密数据 * @param publicKey * 公钥(BASE64编码) * @param sign * 数字签名 * * @return * @throws Exception * */ public static boolean verify(byte[] data, String publicKey, String sign) throws Exception { byte[] keyBytes = Base64Utils.decode(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PublicKey publicK = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(publicK); signature.update(data); return signature.verify(Base64Utils.decode(sign)); } /** */ /** * <P> * 私钥解密 * </p> * * @param encryptedData * 已加密数据 * @param privateKey * 私钥(BASE64编码) * @return * @throws Exception */ public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception { byte[] keyBytes = Base64Utils.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; } /** */ /** * <p> * 公钥解密 * </p> * * @param encryptedData * 已加密数据 * @param publicKey * 公钥(BASE64编码) * @return * @throws Exception */ public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception { byte[] keyBytes = Base64Utils.decode(publicKey); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicK = keyFactory.generatePublic(x509KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; } /** */ /** * <p> * 公钥加密 * </p> * * @param data * 源数据 * @param publicKey * 公钥(BASE64编码) * @return * @throws Exception */ public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception { byte[] keyBytes = Base64Utils.decode(publicKey); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicK = keyFactory.generatePublic(x509KeySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段加密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); out.close(); return encryptedData; } /** */ /** * <p> * 私钥加密 * </p> * * @param data * 源数据 * @param privateKey * 私钥(BASE64编码) * @return * @throws Exception */ public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception { byte[] keyBytes = Base64Utils.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段加密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); out.close(); return encryptedData; } /** */ /** * <p> * 获取私钥 * </p> * * @param keyMap * 密钥对 * @return * @throws Exception */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return Base64Utils.encode(key.getEncoded()); } /** */ /** * <p> * 获取公钥 * </p> * * @param keyMap * 密钥对 * @return * @throws Exception */ public static String getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return Base64Utils.encode(key.getEncoded()); } /** * java端公钥加密 */ public static String encryptedDataOnJava(String data, String PUBLICKEY) { try { data = Base64Utils.encode(encryptByPublicKey(data.getBytes(), PUBLICKEY)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return data; } /** * java端私钥解密 */ public static String decryptDataOnJava(String data, String PRIVATEKEY) { String temp = ""; try { byte[] rs = Base64Utils.decode(data); temp = new String(RSAUtils.decryptByPrivateKey(rs, PRIVATEKEY),"UTF-8"); //以utf-8的方式生成字符串 } catch (Exception e) { e.printStackTrace(); } return temp; } }
1.1.1. 后端实例
1 public class TestAction { 2 private static final String PrivateKey = "***"; 3 4 public void test(String password) { 5 password = RSAUtils.decryptDataOnJava(password, PrivateKey); 6 System.out.println("密码是:"+password); 7 } 8 }
该文档参考以下两篇文章:
https://www.cnblogs.com/Leo_wl/p/5763243.html
https://www.cnblogs.com/nanyangke-cjz/p/5898361.html