简述:
RSA非对称加密算法, 简单理解就是: 准备两把钥匙-公钥, 私钥.
加密的时候使用公钥进行加密, 解密的时候使用私钥进行解密, 这两把钥匙是不同的.
js里面包含了解密和加密方法, 我们需要做的就是使用方法的时候传递 钥匙和数据进去.
RSA工具类里面也包含 解密js端传递来的密文方法, 以及在后台进行数据的加密解密方法.
直接开始:
1. 准备前端需要的js
security.js,已上传
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);
}
