RSA在前端加密后端解密的应用
来源:互联网 发布:js 导航栏点击后变色 编辑:程序博客网 时间:2024/05/22 02:05
问题来源
本人要搭出一个系统的原型,需要账户登录功能,那最实用的密码加密算法肯定是RSA了,鉴于密钥使用的特殊性,所以在前端加密后端解密是最好的选择了。本文有两个可行的思路,主要详细写第一个(以JFinal框架为例)。
思路
为了避免密钥对传到前端被截获,所以密钥要在后端生成,并存于session里,然后把公钥传给前端供前端JS加密,前端ajax只传回账号和公钥加密密码,后端得到公钥加密密码后取得session中的私钥进行解密(一般来说密码最好再用对称加密处理一下再存进数据库里更妥,例如MD5)
- 在一个会话期间只生成一次密钥对:这就需要使用HttpSessionListener来对会话的创建和销毁进行密钥对生成(记得在web.xml里注册监听器)
/** * 会话监听器 * @author Wilson 2016/04/02 * */public class SessionListener implements HttpSessionListener{private static final Logger logger = Logger.getLogger(SessionListener.class); @Override public void sessionCreated(HttpSessionEvent hse) { try { Map<String,Object> keyPair = CryptoKit.initKey(); hse.getSession().setAttribute("rsa_public_key", CryptoKit.getPublicKey(keyPair)); hse.getSession().setAttribute("rsa_private_key", CryptoKit.getPrivateKey(keyPair)); } catch (Exception e) { logger.error(e); } } @Override public void sessionDestroyed(HttpSessionEvent hse) { }}
- 在功能里创建密钥对,每次调用页面都重新生成一对,同样放在session里(记得判断和清除上一次的密钥对),可能比上一个方法更为保密,但确实不方便,见仁见智把
/** * 登陆控制器 * @author Wilson 2017/04/03 * */public class LoginController extends Controller{public void index() throws Exception {HttpSession session = getSession();session.removeAttribute("rsa_public_key");session.removeAttribute("rsa_private_key");Map<String,Object> keyPair = CryptoKit.initKey();String pubKey = CryptoKit.getPublicKey(keyPair); session.setAttribute("rsa_public_key", pubKey); session.setAttribute("rsa_private_key", CryptoKit.getPrivateKey(keyPair));setAttr("rsa_public_key",pubKey);renderFreeMarker("Login.html");}}
步骤
- 先设计好加密工具类(这里借用了网上的代码,并改用common.codec来处理base64)
/** * 密文工具 * @author Wilson 2017/04/01 * */public class CryptoKit {public static final String KEY_ALGORITHM = "RSA"; public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; private static final String PUBLIC_KEY = "RSAPublicKey"; private static final String PRIVATE_KEY = "RSAPrivateKey"; private static final int MAX_ENCRYPT_BLOCK = 117; //RSA最大加密明文大小 private static final int MAX_DECRYPT_BLOCK = 128; //RSA最大解密密文大小 public static final String KEY_SHA = "SHA"; public static final String KEY_MD5 = "MD5";private CryptoKit(){} public static void main(String[] args) throws Exception{ Map<String, Object> keyPair = initKey(); String privateKey = getPrivateKey(keyPair); String publicKey = getPublicKey(keyPair); System.err.println("公钥加密——私钥解密"); String source = "这是一行没有任何意义的文字,你看完了等于没看,不是吗?"; System.out.println("\r加密前文字:\r\n" + source); byte[] data = source.getBytes(); byte[] encodedData = encryptByPublicKey(data, publicKey);byte[] encodedData2 = encryptByPublicKey(data, publicKey);System.out.println("加密后文字:\r\n" + new String(encodedData));System.out.println("加密后文字:\r\n" + new String(encodedData2));byte[] decodedData = decryptByPrivateKey(encodedData, privateKey); String target = new String(decodedData); System.out.println("解密后文字: \r\n" + target);System.err.println("私钥加密——公钥解密"); byte[] encodedDa = encryptByPrivateKey(data, privateKey); System.out.println("加密后:\r\n" + new String(encodedDa)); byte[] decodedDa = decryptByPublicKey(encodedDa, publicKey); String tar = new String(decodedDa); System.out.println("解密后: \r\n" + tar); System.err.println("私钥签名——公钥验证签名"); String sign = sign(encodedData, privateKey); System.err.println("签名:\r" + sign); boolean status = verify(encodedData, publicKey, sign); System.err.println("验证结果:\r" + status); } /** * BASE64解密 * * @param key * @return * @throws Exception */ public static byte[] decryptBASE64(String key) { return Base64.decodeBase64(key); } /** * BASE64加密 * * @param key * @return * @throws Exception */ public static String encryptBASE64(byte[] key) { return Base64.encodeBase64String(key); } /** * MD5加密 (信息摘要不可逆) * * @param data * @return * @throws Exception */ public static byte[] encryptMD5(byte[] data) throws Exception { MessageDigest md5 = MessageDigest.getInstance(KEY_MD5); md5.update(data); return md5.digest(); } /** * SHA加密 * * @param data * @return * @throws Exception */ public static byte[] encryptSHA(byte[] data) throws Exception { MessageDigest sha = MessageDigest.getInstance(KEY_SHA); sha.update(data); return sha.digest(); } /** * 用私钥对信息生成数字签名 * * @param data 加密数据 * @param privateKey 私钥 * @return * @throws Exception */ public static String sign(byte[] data, String privateKey) throws Exception { // 解密由base64编码的私钥 byte[] keyBytes = decryptBASE64(privateKey); // 构造PKCS8EncodedKeySpec对象 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); // KEY_ALGORITHM 指定的加密算法 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); // 取私钥匙对象 PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec); // 用私钥对信息生成数字签名 Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(priKey); signature.update(data); return encryptBASE64(signature.sign()); } /** * 校验数字签名 * * @param data 加密数据 * @param publicKey 公钥 * @param sign 数字签名 * @return 校验成功返回true 失败返回false * @throws Exception */ public static boolean verify(byte[] data, String publicKey, String sign) throws Exception { // 解密由base64编码的公钥 byte[] keyBytes = decryptBASE64(publicKey); // 构造X509EncodedKeySpec对象 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); // KEY_ALGORITHM 指定的加密算法 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); // 取公钥匙对象 PublicKey pubKey = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(pubKey); signature.update(data); // 验证签名是否正常 return signature.verify(decryptBASE64(sign)); } /** * 用私钥解密 * @param data * @param key (BASE64) * @return * @throws Exception */ public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception { // 取得私钥 byte[] keyBytes = decryptBASE64(key); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); // 对数据解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateKey); int inputLen = data.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(data, offSet, MAX_DECRYPT_BLOCK); else cache = cipher.doFinal(data, offSet, inputLen - offSet); out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; } /** * 用公钥解密 * @param data * @param key (BASE64) * @return * @throws Exception */ public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception { // 取得公钥 byte[] keyBytes = decryptBASE64(key); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicKey = keyFactory.generatePublic(x509KeySpec); // 对数据解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicKey); int inputLen = data.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(data, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; } /** * 用公钥加密 * * @param data * @param key (BASE64) * @return * @throws Exception */ public static byte[] encryptByPublicKey(byte[] data, String key) throws Exception { // 对公钥解密 byte[] keyBytes = decryptBASE64(key); // 取得公钥 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicKey = keyFactory.generatePublic(x509KeySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); 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; } /** * 用私钥加密 * * @param data * @param key (BASE64) * @return * @throws Exception */ public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception { // 对密钥解密 byte[] keyBytes = decryptBASE64(key); // 取得私钥 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * 取得私钥 * * @param keyMap * @return * @throws Exception */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { RSAPrivateKey key = (RSAPrivateKey) keyMap.get(PRIVATE_KEY); return encryptBASE64(key.getEncoded()); } /** * 取得公钥 * * @param keyMap * @return * @throws Exception */ public static String getPublicKey(Map<String, Object> keyMap) throws Exception { RSAPublicKey key = (RSAPublicKey) keyMap.get(PUBLIC_KEY); return encryptBASE64(key.getEncoded()); } /** * 初始化密钥对 * * @return * @throws Exception */ public static Map<String, Object> initKey() 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; } }
- 前端JS,利用了jsencrypt.js来进行加密,通过后端的公钥便可以进行密码的加密(这里是requireJS的写法)
<script>require([ 'jquery', '${base}/res/plugin/cryptico/jsencrypt.min.js' ], function($,jsencrypt) {var t = '${rsa_public_key}';var encrypt = new jsencrypt.JSEncrypt(); encrypt.setPublicKey(t); var encrypted = encrypt.encrypt("123456");$.ajax({url: '${base}/index/login',data: {user:'admin',password:encrypted},success: function(data){}});});</script>
- 后端java
/** * 登陆控制器 * @author Wilson 2017/04/03 * */public class LoginController extends Controller{public void index() {String pubKey = getSessionAttr("rsa_public_key");setAttr("rsa_public_key",pubKey);renderFreeMarker("Login.html");}/** * 登陆 * @throws Exception */public void login() throws Exception {String user = getPara("user");String password = getPara("password");String priKey = getSessionAttr("rsa_private_key");String text2 = new String(CryptoKit.decryptByPrivateKey(CryptoKit.decryptBASE64(password), priKey));//TO DOrenderNull();}}
0 0
- RSA在前端加密后端解密的应用
- RSA前端加密后端解密
- RSA前端加密后端解密
- RSA非对称性前端加密后端解密
- RSA前端JS加密,后端JAVA解密实现
- RSA前端JS加密,后端JAVA解密实现
- RSA前端JS加密,后端JAVA解密实现
- RSA实现JS前端加密,PHP后端解密
- 【Flask】前端RSA加密后端Python解密示例
- RSA实现JS前端加密,PHP后端解密
- RSA实现JS前端加密,PHP后端解密
- AES前端加密后端解密
- RSA加密解密的原理与应用
- 加密–RSA前端与后台的加密&解密
- base64之前端加密后端解密
- 前端登陆加密和后端解密
- 关于base64前端加密,后端解密
- RSA前端加密,java后台解密
- 92. Reverse Linked List II
- 数据库的连接的方式
- 【android】数据库升级完整解决方案
- HDOJ 4893 Wow! Such Sequence! (线段树)
- ACM递归递推练习 Problem L
- RSA在前端加密后端解密的应用
- hackinglab基础关WP
- Android 本地推送
- 上传项目 到 Git 图文教程
- 使用VS2013做简单的C程序解析
- 微信预约系统怎么做?
- JAVA运行时の数据区域
- The inferior stopped because it received a signal from the operating system.
- 大学生程序设计竞赛暨西南地区高校邀请赛 赛后总结