码上敲享录 > java常见报错解答 > RSA加密算法-前端(JS)加密,后端(JAVA)解密

RSA加密算法-前端(JS)加密,后端(JAVA)解密

上一章章节目录下一章 2021-07-04已有1322人阅读 评论(0)

简述:

RSA非对称加密算法, 简单理解就是: 准备两把钥匙-公钥, 私钥.

加密的时候使用公钥进行加密, 解密的时候使用私钥进行解密, 这两把钥匙是不同的.

js里面包含了解密和加密方法, 我们需要做的就是使用方法的时候传递 钥匙和数据进去.

RSA工具类里面也包含 解密js端传递来的密文方法, 以及在后台进行数据的加密解密方法.

直接开始:

1. 准备前端需要的js

security.js,已上传

security.rar

2. jsp或者html页面, 控制层传密钥

controller层将公钥系统和公钥指数传递到前端


RSAPublicKey publicKey = RSAUtils.getDefaultPublicKey(); //获取公钥对象--注意:前端需要用到公钥系数和指数

//公钥-系数(n)

model.addAttribute("modulus",new String(Hex.encode(publicKey.getModulus().toByteArray())));

//公钥-指数(e1)

model.addAttribute("exponent",new String(Hex.encode(publicKey.getPublicExponent().toByteArray())));


js或者html文件:

<script type="text/javascript" th:src="@{/js/security.js}"></script>

//登录验证之前需要加密用户名密码

$("#loginUp").on('click', function (event) {

 var userAccount = $("#userAccount").val();
 var password = $("#inputPassword").val();
 var validCode = $("#validCode").val();

 if (userAccount.trim() === "") {
   $("#enterUserName").show();
   return false;
 }
 if (password.trim() === "") {
   $("#enterPassword").show();
   return false;
 }
 if (validCode.trim() === "") {
   $("#enterCode").show();
   return false;
 }

 //获取公钥系数
 var modulus = [[${modulus}]];
 //获取公钥指数
 var exponent = [[${exponent}]];
 //获取最终公钥
 var key = RSAUtils.getKeyPair(exponent, '', modulus);
 //进行数据加密
 //var ap = RSAUtils.encryptedString(key,  encodeURI(word));
 $.get(ctx + "oauth/loginValidate", {"userAccount": RSAUtils.encryptedString(key,encodeURI(userAccount)), "password": RSAUtils.encryptedString(key,encodeURI(password)), "validCode": validCode, "codeNumber": codeNumber}, function (data) {

     if (data.errorCode === 1) {
         $("#spanText").text(data.errorMsg).show();
         refreshCode();
     }
     if (data.code == 506) {
       $("#spanText").text(data.msg).show();
       refreshCode();
     }
     if (data.errorCode === 0) {
         submitForm();
     }
 });

});

3. java端需要的RSA工具类.

注意点:

该工具类中需要引入org.bouncycastle..包依赖,如下 ,其余RSA需要的jar包都是java自带

<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcprov-jdk15on</artifactId>
  <version>1.69</version>
</dependency>

RSAUtils工具类

package com.prenatalscreen.util;

import org.apache.commons.lang.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Cipher;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

/**
* RSA算法加密/解密工具类。
*/
public class RSAUtils {

   /**
    * 算法名称
    */
   private static final String ALGORITHOM = "RSA";
   /**
    * 密钥大小
    */
   private static final int KEY_SIZE = 1024;
   /**
    * 默认的安全服务提供者
    */
   private static final Provider DEFAULT_PROVIDER = new BouncyCastleProvider();
   private static KeyPairGenerator keyPairGen = null;
   private static KeyFactory keyFactory = null;
   /**
    * 缓存的密钥对。
    */
   private static KeyPair oneKeyPair = null;

   //密文种子, 当想更换RSA钥匙的时候,只需要修改密文种子,即可更换
   private static final String radamKey = "wuxiaomin";

   //类加载后进行初始化数据
   static {
       try {
           keyPairGen = KeyPairGenerator.getInstance(ALGORITHOM,
                   DEFAULT_PROVIDER);
           keyFactory = KeyFactory.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
       } catch (NoSuchAlgorithmException ex) {
           ex.printStackTrace();
       }
   }

   /**
    * 根据指定的密文种子,生成并返回RSA密钥对。
    */
   private static synchronized KeyPair generateKeyPair() {
       try {
           keyPairGen.initialize(KEY_SIZE,
                   new SecureRandom(radamKey.getBytes()));
           oneKeyPair = keyPairGen.generateKeyPair();
           return oneKeyPair;
       } catch (InvalidParameterException ex) {
           ex.printStackTrace();
       } catch (NullPointerException ex) {
           ex.printStackTrace();
       }
       return null;
   }

   /**
    * 返回初始化时默认的公钥。
    */
   public static RSAPublicKey getDefaultPublicKey() {
       KeyPair keyPair = generateKeyPair();
       if (keyPair != null) {
           return (RSAPublicKey) keyPair.getPublic();
       }
       return null;
   }

   /**
    * 使用指定的私钥解密数据。
    *
    * @param privateKey 给定的私钥。
    * @param data       要解密的数据。
    * @return 原数据。
    */
   public static byte[] decrypt(PrivateKey privateKey, byte[] data) throws Exception {
       Cipher ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
       ci.init(Cipher.DECRYPT_MODE, privateKey);
       return ci.doFinal(data);
   }

   /**
    * 使用默认的私钥解密给定的字符串。
    * @param encryptText 密文。
    * @return 原文字符串。
    */
   public static String decryptString(String encryptText) {
       if (StringUtils.isBlank(encryptText)) {
           return null;
       }
       KeyPair keyPair = generateKeyPair();
       try {
           byte[] en_data = Hex.decode(encryptText);
           byte[] data = decrypt((RSAPrivateKey) keyPair.getPrivate(), en_data);
           return new String(data);
       } catch (NullPointerException ex) {
           ex.printStackTrace();
       } catch (Exception ex) {
           ex.printStackTrace();
       }
       return null;
   }

   /**
    * 使用秘钥 - js端传递过来密文进行解密
    *
    * @param encryptText 密文。
    * @return {@code encryptText} 的原文字符串。
    */
   public static String decryptStringByJs(String encryptText) {
       String text = decryptString(encryptText);
       if (text == null) {
           return null;
       }
       String reverse = StringUtils.reverse(text);
       String decode = null;
       try {
           //这里需要进行编码转换.:在前端js对明文加密前需要先进行转码-"编码转换"
           decode = URLDecoder.decode(reverse, "UTF-8");
           System.out.println("解密后文字:" + decode);
       } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
       }
       return decode;
   }

   //java - 使用公钥进行加密
   public static byte[] encrypt(String plaintext) throws Exception {
       // 获取公钥及参数e,n
       RSAPublicKey publicKey = RSAUtils.getDefaultPublicKey();
       //获取公钥指数 e
       BigInteger e = publicKey.getPublicExponent();
       //获取公钥系数 n
       BigInteger n = publicKey.getModulus();
       //先将明文进行编码
       String encode = URLEncoder.encode(plaintext);
       // 获取明文字节数组 m
       BigInteger m = new BigInteger(encode.getBytes());
       // 进行明文加密 c
       BigInteger c = m.modPow(e, n);
       //返回密文字节数组
       return c.toByteArray();
   }

   //java - 使用私钥进行解密
   public static String decrypt(byte[] cipherText) throws Exception {
       // 读取私钥
       KeyPair keyPair = generateKeyPair();
       RSAPrivateKey prk = (RSAPrivateKey) keyPair.getPrivate();
       // 获取私钥参数-指数/系数
       BigInteger d = prk.getPrivateExponent();
       BigInteger n = prk.getModulus();
       // 读取密文
       BigInteger c = new BigInteger(cipherText);
       // 进行解密
       BigInteger m = c.modPow(d, n);
       // 解密结果-字节数组
       byte[] mt = m.toByteArray();
       //转成String,此时是乱码
       String en = new String(mt);
       //再进行编码
       String result = java.net.URLDecoder.decode(en, "UTF-8");
       //最后返回解密后得到的明文
       return result;
   }


   public static void main(String[] args) {
       /*解密js端传递过来的密文*/
       //获取公钥对象--注意:前端那边需要用到公钥系数和指数
       RSAPublicKey publicKey = RSAUtils.getDefaultPublicKey();
       //公钥-系数(n)
       System.out.println("public key modulus:" + new String(Hex.encode(publicKey.getModulus().toByteArray())));
       //公钥-指数(e1)
       System.out.println("public key exponent:" + new String(Hex.encode(publicKey.getPublicExponent().toByteArray())));
       //JS加密后的字符串
       String param = "8c49dfb92a0c8d15b0187b1eabc343a80f340962ebecc497205f83f6a4792141d4e711b6d439388ecf691df4eda2cae1e6431573b61e3f564ffe1c757e32f3e846b5983e5939ddeb28c9570001d7f208ffbaa069677d363cc73e4c78c0d508e8b0b9f6205473269bbfbc22e7fb9413be4c449520eb6cfb4fbbff4e7e189a005a";
       //解密后的字符串
       String param1 = RSAUtils.decryptStringByJs(param);

       System.out.println(param1);
//        /*后端的加密和解密-在加密的方法中已经使用了公钥指数和系数*/

//        try {
//            //加密
//            byte[] param3 = encrypt("你好> @# !!# #");
//            //解密
//            String decrypt = RSAUtils.decrypt(param3);
//            System.out.println(decrypt);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }

   }


}


4. 验证用户名密码是否正确之前先将用户名密码解密

@ResponseBody
@RequestMapping("/oauth/loginValidate")
public ResMessage loginValidate(String userAccount, String password, String validCode, String codeNumber) {

      //解密后的字符串
              userAccount = RSAUtils.decryptStringByJs(userAccount);
       password = RSAUtils.decryptStringByJs(password);

       ResMessage result = new ResMessage();
       SysUser user = sysUserServices.queryUserAccount(userAccount);

       user = sysUserServices.queryUserAccount(userAccount);

       String codeSession = RedisUtil.getCodeNumber(codeNumber);

}


向大家推荐《Activiti工作流实战教程》:https://xiaozhuanlan.com/activiti
0

有建议,请留言!

  • *您的姓名:

  • *所在城市:

  • *您的联系电话:

    *您的QQ:

  • 咨询问题:

  • 提 交