• JsEncrypt.js前端加密,java后端解密


    RSA与AES加密与解密

    1.什么是对称加密

    ​ 对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yao)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。

    image-20210923223743479

    1. 特点

    对称加密算法的特点是算法公开、计算量小、加密速度快、加密效率高。

    不足之处是,交易双方都使用同样钥匙,安全性得不到保证。此外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的惟一钥匙,这会使得发收信双方所拥有的钥匙数量呈几何级数增长,密钥管理成为用户的负担。对称加密算法在分布式网络系统上使用较为困难,主要是因为密钥管理困难,使用成本较高。而与公开密钥加密算法比起来,对称加密算法能够提供加密和认证却缺乏了签名功能,使得使用范围有所缩小。在计算机专网系统中广泛使用的对称加密算法有DES和IDEA等。美国国家标准局倡导的AES即将作为新标准取代DES。

    2.实现步骤

    image-20210923225834371

    代码实现流程:

    image-20210923231323491

    • 首先在页面加载完成时向后台发送ajax请求,后台随机生成一个16位的字符串key返回给前端
    • 前端使用CryptoJS.js和后台生成的key对password进行加密
    • 点击“登录”按钮后提交到后台,后台获取到加密后的密码进行解密后,把解密后的密码返回给前端展示出来。

    导入依赖

    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    

    后端controller

    package com.sean.jsencrypt.controller;
    
    
    import cn.hutool.core.util.RandomUtil;
    import org.apache.commons.lang3.RandomUtils;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    import utils.AesUtils;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.HashMap;
    import java.util.Map;
    
    @Controller
    public class AesController {
    
        @GetMapping("/key")
        @ResponseBody
        private String create16String()
        {
            return RandomUtil.randomString(16);
        }
    
        @RequestMapping(value = "/login", method = RequestMethod.POST)
        @ResponseBody
        public Object login(HttpServletRequest request) throws Exception {
            String userName = request.getParameter("userName");
            String encryptedPassword = request.getParameter("password");
            String key = request.getParameter("key");
    
            String password = AesUtils.decrypt(encryptedPassword,key);
    
          return password;
        }
    }
    

    后端代码:AesUtils工具类

    package utils;
    
    import org.apache.commons.codec.binary.Base64;
    import javax.crypto.Cipher;
    import javax.crypto.spec.SecretKeySpec;
    
    public class AesUtils {
    
            private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
    
            public static String encrypt(String content, String key) {
                try {
                    //获得密码的字节数组
                    byte[] raw = key.getBytes();
                    //根据密码生成AES密钥
                    SecretKeySpec skey = new SecretKeySpec(raw, "AES");
                    //根据指定算法ALGORITHM自成密码器
                    Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
                    //初始化密码器,第一个参数为加密(ENCRYPT_MODE)或者解密(DECRYPT_MODE)操作,第二个参数为生成的AES密钥
                    cipher.init(Cipher.ENCRYPT_MODE, skey);
                    //获取加密内容的字节数组(设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码
                    byte [] byte_content = content.getBytes("utf-8");
                    //密码器加密数据
                    byte [] encode_content = cipher.doFinal(byte_content);
                    //将加密后的数据转换为字符串返回
                    return Base64.encodeBase64String(encode_content);
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
    
            public static String decrypt(String encryptStr, String decryptKey) {
                try {
                    //获得密码的字节数组
                    byte[] raw = decryptKey.getBytes();
                    //根据密码生成AES密钥
                    SecretKeySpec skey = new SecretKeySpec(raw, "AES");
                    //根据指定算法ALGORITHM自成密码器
                    Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
                    //初始化密码器,第一个参数为加密(ENCRYPT_MODE)或者解密(DECRYPT_MODE)操作,第二个参数为生成的AES密钥
                    cipher.init(Cipher.DECRYPT_MODE, skey);
                    //把密文字符串转回密文字节数组
                    byte [] encode_content = Base64.decodeBase64(encryptStr);
                    //密码器解密数据
                    byte [] byte_content = cipher.doFinal(encode_content);
                    //将解密后的数据转换为字符串返回
                    return new String(byte_content,"utf-8");
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
    }
    

    前端代码:

    <!DOCTYPE html>
    <html lang="en"
    	  xmlns:th="http://www.w3.org/1999/xhtml"
    >
    <head>
    	<meta charset="utf-8">
    	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    	<meta name="viewport" content="width=device-width, initial-scale=1">
    	<link rel="stylesheet" href="/css/bootstrap.min.css">
    
    	<script src="/js/jquery-3.3.1.min.js" ></script>
    	<script src="/js/bootstrap.min.js" ></script>
    	<script src="https://cdn.bootcss.com/crypto-js/3.1.9-1/crypto-js.min.js"></script>
    
    
    	<title>AES</title>
    
    	<style>
    		.bgColor {
    			background-color: rgba(243, 66, 111, 0.15)
    		}
    
    		.divBorder {
    			border: solid 1px rgba(12, 24, 255, 0.15);
    			padding: 10px;
    			margin-top: 10px;
    			border-radius: 10px;
    			text-align: center;
    			vertical-align: middle;
    		}
    
    		.h4font {
    			margin-top: 0px;
    			font-family: 微软雅黑;
    			font-weight: 500;
    		}
    
    		.center {
    			padding: 20% 0;
    		}
    
    		.verifyInput {
    			vertical-align: middle;
    			font-size: 14px;
    			font-weight: normal;
    			line-height: 1;
    			/*border:1px solid #999;*/
    			float: left;
    			 180px;
    			height: 30px;
    
    		}
    
    		.verifyImage {
    			vertical-align: middle;
    			float: right;
    			height: 30px;
    		}
    
    	</style>
    
    
    </head>
    <body>
    
    <div class="container">
    	<div class="row center">
    		<div class="divBorder col-sm-offset-4 col-sm-4">
    			<h3 class="panel panel-heading h4font">
    				用户登录
    			</h3>
    			<h4 name="msg" th:text="${msg}"></h4>
    			<input type="hidden" name="key" value="">
    			<form class="form-horizontal" method="post">
    				<div class="input-group">
    					<span class="input-group-addon"><i class="glyphicon glyphicon-user" aria-hidden="true"></i></span>
    					<input type="text" class="form-control" name="userName" placeholder="请输入用户名称"
    						   th:value="${userName}"/>
    				</div>
    				<br>
    				<div class="input-group">
    					<span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
    					<input type="text" class="form-control" name="password" th:value="${password}"
    						   placeholder="请输入密码"/>
    				</div>
    				<br/>
    
    				<br>
    				<input type="button" name="btnLogin" class="btn btn-lg btn-block btn-info" value="登 录">
    			</form>
    		</div>
    
    
    	</div>
    
    </div>
    <script th:inline="javascript">
    	$(function () {
    		$.ajax({
    			type: "get",
    			url: "/key",
    			success: function (result) {
    				console.log(result);
    				$('input[name="key"]').val(result)
    			}
    		})
    
    		$('input[name="btnLogin"]').click(function () {
    			var $key = $('input[name="key"]').val();
    			var $userName = $('input[name="userName"]').val();
    			var $password = $('input[name="password"]').val();
    
    			var key = CryptoJS.enc.Utf8.parse($key);
    			console.log("key:" + key + ",$key:" + $key);
    			var password = CryptoJS.enc.Utf8.parse($password);
    			var encrypted = CryptoJS.AES.encrypt(password, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7});
    			var encryptedPwd = encrypted.toString();
    
               console.log("encrypted:" + encrypted);
               console.log("encryptedPwd:" + encryptedPwd);
    
    			var decrypt = CryptoJS.AES.decrypt(encryptedPwd, key, {
    				mode: CryptoJS.mode.ECB,
    				padding: CryptoJS.pad.Pkcs7
    			});
    			var testDecryptStr = CryptoJS.enc.Utf8.stringify(decrypt).toString();
    
               console.log("decrypt:" + decrypt);
               console.log("testDecryptStr:" + testDecryptStr);
    
    
    			$.ajax({
    				type: "post",
    				url: "/login",
    				data: {userName: $userName, password: encryptedPwd, key: $key },
    				dataType: "json",
    				success: function (result) {
    					alert("后端解密后的密码:"+result);
    				}
    			});
    
    		})
    	})
    </script>
    </body>
    </html>
    

    AES是通过后台随机生成的key进行密码的加密和解密的

    2.什么是非对称加密

    ​ 非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

    RAS则是一种非对称加密算法

    代码实现流程

    image-20210923232048916

    image-20210923233341155

    实现步骤

    生成公钥和私钥

    首先对于非对称加密的话必须要有公钥和私钥,产生公钥和私钥的方式有很多种,我使用支付宝开放平台开发助手工具生成,也可以使用在线生成

    image-20210923232444342

    把生成的公钥和私钥保存起来,前端页面用公钥加密,后端通过私钥解密

    导入依赖

    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    

    前端代码

    <!DOCTYPE html >
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Login</title>
        <script src="https://blog.yoodb.com/app/default/js/jquery-2.1.4.min.js"></script>
        <script src="http://passport.cnblogs.com/scripts/jsencrypt.min.js"></script>
        <script type="text/javascript">
    
            $(function () {
                $("#btn").click(function () {
                    let inputData = $('#data').val();
                    let encrypt = new JSEncrypt();
                    encrypt.setPublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXQHkn4dX3oUppqr2Vj7pBEDoe5Y+wJuTFqVImFU7xyDHCzwVY40q8/2OCmoMnrnjORL6Yh7UZl9GQ/FOvJHAnXrClU2mMRDzhTG9tw4mvsfDk/EHpJ+oCDUmlSqp1rG78mc89rjXqoaRzSsdqYB9bnpBHVjG8r1gmcRqKvCpuvQIDAQAB");
                    let data = encrypt.encrypt(inputData);
                    $("#encrypt").val(data);
    
                    $.ajax({
                        type: "GET",
                        url: "/rsaDecrypt",
                        data:{
                            data:data
                        },
                        success: function (result) {
                            console.log(result);
                            $("#decrypt").val(result);
                        }
                    })
                })
            });
    
    
        </script>
    </head>
    <body>
    <div>
        <div>
            <label> 请输入要加密的字符串:</label>
            <input type="text" id="data" value="" />
            <button id = btn >发送</button>
        </div>
    
        <div style=" margin-top: 20px">
            <label>前端加密后:</label>
            <textarea id="encrypt"></textarea>
        </div>
    
        <div style=" margin-top: 20px">
            <label>后端解密后:</label>
            <textarea id="decrypt"></textarea>
    
        </div>
    </div>
    </body>
    </html>
    

    后端代码:RSAUtils工具类

    package utils;
    
    import org.apache.commons.codec.binary.Base64;
    import javax.crypto.Cipher;
    import java.security.*;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    
    /**
     * @author : sean
     * @version V1.0
     * @Project: jsencrypt
     * @Package utils
     * @date Date : 2021年09月23日 21:36
     * @Description: RSA加解密工具类,实现公钥加密私钥解密和私钥解密公钥解密
     */
    
    public class RsaUtils {
    
            /**
             * 公钥加密私钥解密
             */
            private static void test1(RSAKeyPair keyPair, String source) throws Exception {
                System.out.println("***************** 公钥加密私钥解密开始 *****************");
                String text1 = encryptByPublicKey(keyPair.getPublicKey(), source);
                String text2 = decryptByPrivateKey(keyPair.getPrivateKey(), text1);
                System.out.println("加密前:" + source);
                System.out.println("加密后:" + text1);
                System.out.println("解密后:" + text2);
                if (source.equals(text2)) {
                    System.out.println("解密字符串和原始字符串一致,解密成功");
                } else {
                    System.out.println("解密字符串和原始字符串不一致,解密失败");
                }
                System.out.println("***************** 公钥加密私钥解密结束 *****************");
            }
    
            /**
             * 私钥加密公钥解密
             *
             * @throws Exception
             */
            private static void test2(RSAKeyPair keyPair, String source) throws Exception {
                System.out.println("***************** 私钥加密公钥解密开始 *****************");
                String text1 = encryptByPrivateKey(keyPair.getPrivateKey(), source);
                String text2 = decryptByPublicKey(keyPair.getPublicKey(), text1);
                System.out.println("加密前:" + source);
                System.out.println("加密后:" + text1);
                System.out.println("解密后:" + text2);
                if (source.equals(text2)) {
                    System.out.println("解密字符串和原始字符串一致,解密成功");
                } else {
                    System.out.println("解密字符串和原始字符串不一致,解密失败");
                }
                System.out.println("***************** 私钥加密公钥解密结束 *****************");
            }
    
            /**
             * 公钥解密
             *
             * @param publicKeyText
             * @param text
             * @return
             * @throws Exception
             */
            public static String decryptByPublicKey(String publicKeyText, String text) throws Exception {
                X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
                Cipher cipher = Cipher.getInstance("RSA");
                cipher.init(Cipher.DECRYPT_MODE, publicKey);
                byte[] result = cipher.doFinal(Base64.decodeBase64(text));
                return new String(result);
            }
    
            /**
             * 私钥加密
             *
             * @param privateKeyText
             * @param text
             * @return
             * @throws Exception
             */
            public static String encryptByPrivateKey(String privateKeyText, String text) throws Exception {
                PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
                Cipher cipher = Cipher.getInstance("RSA");
                cipher.init(Cipher.ENCRYPT_MODE, privateKey);
                byte[] result = cipher.doFinal(text.getBytes());
                return Base64.encodeBase64String(result);
            }
    
            /**
             * 私钥解密
             *
             * @param privateKeyText
             * @param text
             * @return
             * @throws Exception
             */
            public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception {
                PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
                Cipher cipher = Cipher.getInstance("RSA");
                cipher.init(Cipher.DECRYPT_MODE, privateKey);
                byte[] result = cipher.doFinal(Base64.decodeBase64(text));
                return new String(result);
            }
    
            /**
             * 公钥加密
             *
             * @param publicKeyText
             * @param text
             * @return
             */
            public static String encryptByPublicKey(String publicKeyText, String text) throws Exception {
                X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
                Cipher cipher = Cipher.getInstance("RSA");
                cipher.init(Cipher.ENCRYPT_MODE, publicKey);
                byte[] result = cipher.doFinal(text.getBytes());
                return Base64.encodeBase64String(result);
            }
    
            /**
             * 构建RSA密钥对
             *
             * @return
             * @throws NoSuchAlgorithmException
             */
            public static RSAKeyPair generateKeyPair() throws NoSuchAlgorithmException {
                KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
                keyPairGenerator.initialize(1024);
                KeyPair keyPair = keyPairGenerator.generateKeyPair();
                RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
                RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
                String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
                String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
                RSAKeyPair rsaKeyPair = new RSAKeyPair(publicKeyString, privateKeyString);
                return rsaKeyPair;
            }
    
    
            /**
             * RSA密钥对对象
             */
            public static class RSAKeyPair {
    
                private String publicKey;
                private String privateKey;
    
                public RSAKeyPair(String publicKey, String privateKey) {
                    this.publicKey = publicKey;
                    this.privateKey = privateKey;
                }
    
                public String getPublicKey() {
                    return publicKey;
                }
    
                public String getPrivateKey() {
                    return privateKey;
                }
    
            }
    
    }
    
    

    后端代码:RSAController

    @RestController
    public class RsaController {
        private static final String privateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANdAeSfh1fehSmmqvZWPukEQOh7lj7Am5MWpUiYVTvHIMcLPBVjjSrz/Y4KagyeueM5EvpiHtRmX0ZD8U68kcCdesKVTaYxEPOFMb23Dia+x8OT8Qekn6gINSaVKqnWsbvyZzz2uNeqhpHNKx2pgH1uekEdWMbyvWCZxGoq8Km69AgMBAAECgYEAj+d0mCstRv43p2kUkfaiyHi2wo0qgNOfwl2uo/M+8fmq+tg4dPKPtsbumhP+dvr3nL7sxUCE3HVZD5sBv2eW6iFCW8TRm9z3OHmcBPWPoCoc9BtWwXcm6MA29J1KJqvsGNLwGUcRtoMcYE/OWed1hCrp4kn9AI6LhgPt75rj8qkCQQDuxSJrc1x2TIiQfkAYFiw5U6SldDNEM0PRy2qZv2+cSHCuMrDmr0b2nBPj0RR6Q9yvQbYVUfR4LGCD6Cd1l5q3AkEA5sjhY+qLMghjMyJNUTXZceBxc99o5H6d8CUe16zeCfbdQkeI5JUnzk6Mjg8Wcf8XxTboi/uRUYWcKjJg+v4eKwJAM5ezLUabFxDIfXhaPxojaiuxqvKl1TnCkMWEfj5ITpu0hV98rAv5qHXnMlXON/EL8W6gepDf40urezUhuZ4NlwJBAOKFLWVq4zE6tlOMSaN6XXG+wNzg3g3YkaESblF3JYFWQxo5KI5kMGv5AVC2UmuV3HkASgSL6bjAkeWBCVuSbX0CQC5xBG/83h0Q1Rnozv1hfj0pQL9QDBsxYKRl0XpyjUbCBF/F0oAv1DfUEOwHbCkgDlBl5U8jSHXvkvOOd8Qe18U=";
    
        @GetMapping("/rsaDecrypt")
        public String DecryptAction(String data) throws Exception {
            System.out.println(data);
            String decrypt = RsaUtils.decryptByPrivateKey(privateKey, data);
            return decrypt;
        }
    }
    
  • 相关阅读:
    2月25日
    Maven启动tomcat7:run运行异常:org.apache.catalina.LifecycleException: Failed to start component
    Junit测试报错:java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing
    tomcat启动控制台乱码
    Java虚拟机内存详解
    Ajax使用
    Struts2工作流程
    java.lang.IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required
    Spring-Aop的两种代理方式
    springboot与dubbo整合遇到的坑
  • 原文地址:https://www.cnblogs.com/seanRay/p/15336332.html
Copyright © 2020-2023  润新知