vue对密码对称加密和非对称加密处理

之前博客请求参数与数据库存储都是明文密码,可以说毫无安全性。所以近期对密码进行加密处理。我首先选用的是对称加密方式处理密码。

AES加密

AES加密是对称加密,前端加密:

1、首先npm安装

//安装
npm install crypto-js --save-dev

2、第二步:在src目录下的公用js文件夹中,再建一个AES.js文件

import CryptoJS from 'crypto-js/crypto-js'

// 默认的 KEY 与 iv 如果没有给
const KEY = CryptoJS.enc.Utf8.parse("1234567890123456");//秘钥
const IV = CryptoJS.enc.Utf8.parse('1234567890123456');//偏移量
/**
 \* AES加密 :字符串 key iv 返回base64
 */
export function Encrypt(word, keyStr, ivStr) {
  let key = KEY;
  let iv = IV;
  if (keyStr) {
    key = CryptoJS.enc.Utf8.parse(keyStr);
    iv = CryptoJS.enc.Utf8.parse(ivStr);
  }
  let srcs = CryptoJS.enc.Utf8.parse(word);
  var encrypted = CryptoJS.AES.encrypt(srcs, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.ZeroPadding
  });
  return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);

}
/**
 \* AES 解密 :字符串 key iv 返回base64
 *
 \* @return {string}
 */
export function Decrypt(word, keyStr, ivStr) {
  let key = KEY;
  let iv = IV;

  if (keyStr) {
    key = CryptoJS.enc.Utf8.parse(keyStr);
    iv = CryptoJS.enc.Utf8.parse(ivStr);
  }

  let base64 = CryptoJS.enc.Base64.parse(word);
  let src = CryptoJS.enc.Base64.stringify(base64);

  let decrypt = CryptoJS.AES.decrypt(src, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.ZeroPadding
  });

  let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
  return decryptedStr.toString();
}

3、在vue中使用

引入上面的js方法

import {Encrypt,Decrypt} from "../../assets/js/secret"
testAes: function () {
 var s = '什么是快乐'
 var s1=Encrypt(s)
 console.log('加密后的字符串:'+s1);
 var s2=Decrypt(s1)
 console.log('解密后的字符串:'+s2);
}

运行截图

java调用接口 前后端加密验签 java前端密码加密_java调用接口 前后端加密验签

前端加密后使用ajax传入后端,后端处理接收的加密解密

1、maven添加依赖

<dependency>
  <groupId>commons-codec</groupId>
  <artifactId>commons-codec</artifactId>
  <version>1.15</version>
</dependency>

2、java 方法

public class Encrypt {

  //--------------AES---------------
  private static final String KEY = "1234567890123456"; // 密匙,必须16位
  private static final String ENCODING = "UTF-8"; // 编码
  private static final String ALGORITHM = "AES"; //算法
  private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding"; // 默认的加密算法,ECB模式

  /**
   \* AES加密
   \* @param data
   \* @return String
   */
  public static String AESencrypt(String data) throws Exception
  {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    kgen.init(128);
    Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
    cipher.init(Cipher.ENCRYPT_MODE,new SecretKeySpec(KEY.getBytes(),"AES"));
    byte[] b = cipher.doFinal(data.getBytes("utf-8"));
    //采用base64算法进行转码,避免出现中文乱码
    return Base64.encodeBase64String(b);
  }

  /**
   \* AES解密
   \* @param data
   \* @return String
   */
  public static String AESdecrypt(String data) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    kgen.init(128);
    Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(KEY.getBytes(), "AES"));
    byte[] b = cipher.doFinal(Base64.decodeBase64(data));
    //采用base64算法进行转码,避免出现中文乱码
    return new String(b);
  }
  public static void main(String[] args) throws Exception {
    String mi = Encrypt.AESencrypt("111111");
    System.out.println(mi);
  }

}

这个需要注意的是:前端和后段的对加密的填充方式必需保持一致。java本身只支持NoPadding和PKCS5Padding填充。而crypto-js提供的padding没有PKCS5Padding。这里的解决方法参考:

在使用AES加密的过程中,我发现我的密码是在前端加密的,并且密钥啥的是存在JS里。在浏览器的开发者选项中都能直接查到。那就等于直接给别人看密码了,所以感觉这个加密方式并不适合我。继续学习后发现了:非对称加密算法

RSA加密

RSA加密是一个非对称加密,它包括了一对私钥和公钥,公钥是公开出去的,私钥是保密的。公钥加密的内容需要用私钥解密。基于这个特性对于密码加密有了新的思路:vue对密码进行公钥加密,通过ajax请求将密文传入后端,后端使用私钥解密。

公钥密钥有工具网站可以生成:第三方生成RSA密钥工具

由于并不放心第三方网站自动生成的密钥,所以打算后端随机生成一对公私钥。公钥传给前端加密,将私钥上传redis。用户注册或者登录将公钥加密后的密文传入后端,后端获取redis存储的私钥解密。在进行业务处理。数据库也不能存储明文密码,在保存数据库时在做一次加密。

生成公钥私钥

创建一个RSAEncrypt.java文件

package com.lijie.ljblog.util;
import org.apache.tomcat.util.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;
import java.util.HashMap;
import java.util.Map;

/**
 * @Title: ljblog_springboot
 * @Description: ()
 * @Author:lijie
 * @Version:1.1.0
 * @since 2022/1/11
 */
public class RSAEncrypt {

    /**
     * 随机生成密钥对
     * @return map存公钥秘钥;key:0 -公钥  ;key:1 -私钥
     * @throws NoSuchAlgorithmException
     */
    public static Map<Integer, String> genKeyPair() throws NoSuchAlgorithmException {
        Map<Integer, String> result=new HashMap<>();
        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        // 初始化密钥对生成器,密钥大小为96-1024位
        keyPairGen.initialize(1024,new SecureRandom());
        // 生成一个密钥对,保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥
        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
        // 得到私钥字符串
        String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
        // 将公钥和私钥保存到Map
        result.put(0,publicKeyString);  //0表示公钥
        result.put(1,privateKeyString);  //1表示私钥
        return result;
    }
    /**
     * RSA公钥加密
     *
     * @param str
     *            加密字符串
     * @param publicKey
     *            公钥
     * @return 密文
     * @throws Exception
     *             加密过程中的异常信息
     */
    public static String encrypt( String str, String publicKey ) throws Exception{
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
        return outStr;
    }

    /**
     * RSA私钥解密
     *
     * @param str
     *            加密字符串
     * @param privateKey
     *            私钥
     * @return 铭文
     * @throws Exception
     *             解密过程中的异常信息
     */
    public static String decrypt(String str, String privateKey) throws Exception{
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = Base64.decodeBase64(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }


    /**
     * RSA私钥加密
     *
     * @param str
     *            加密字符串
     * @param privateKey
     *            私钥
     * @return 密文
     * @throws Exception
     *             加密过程中的异常信息
     */
    public static String encryptBypri( String str, String privateKey ) throws Exception{
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(privateKey);
        RSAPrivateKey pubKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
//        String outStr = java.util.Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes("UTF-8")));
        String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
        return outStr;
    }

    /**
     * RSA公钥解密
     *
     * @param str
     *            加密字符串
     * @param publicKey
     *            公钥
     * @return 密文
     * @throws Exception
     *             加密过程中的异常信息
     */
    public static String decryptBypub( String str, String publicKey ) throws Exception{
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey priKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }
	
   
    public static void main(String[] args) throws Exception {
        //生成公钥和私钥
        Map<Integer, String> keyMap = genKeyPair();
        //加密字符串
        String message = "什么是快乐";
        System.out.println("随机生成的公钥为:" + keyMap.get(0));
        System.out.println("随机生成的私钥为:" + keyMap.get(1));
        String messageEn = encrypt(message,keyMap.get(0));
        String messageEn2 = decrypt(messageEn,keyMap.get(1));
        System.out.println(messageEn);
        System.out.println(messageEn2);
    }
}

测试运行截图

java调用接口 前后端加密验签 java前端密码加密_java调用接口 前后端加密验签_02

随机生成的公钥为:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9dbooWM72qimN1WjxnkXTR2FNMX+EUDIA3BTPQQX2bn61bntD9hps+DOhNX4Wgb3l6wsqOEy/MhLXLojI0lBWfzf6Ch5MuAj9vnIINZsAEgcZw+d8F1R73czZIGk3f4OWCLYV3ZcXlxJChSGuTRKLOfuq1eMrJbfY9l0F1QZp7wIDAQAB
随机生成的私钥为:MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAL11uihYzvaqKY3VaPGeRdNHYU0xf4RQMgDcFM9BBfZufrVue0P2Gmz4M6E1fhaBveXrCyo4TL8yEtcuiMjSUFZ/N/oKHky4CP2+cgg1mwASBxnD53wXVHvdzNkgaTd/g5YIthXdlxeXEkKFIa5NEos5+6rV4yslt9j2XQXVBmnvAgMBAAECgYBvJ4zqcwAp87ehgR2q9ELfLDfIBExeInbTzktfNTT8WeN5KrKjMtZaLFyOLkYlikURiY7pXFKashQfryuNNubuczHvb3n+iyGpWySETx7QYgKeTIDy3/zYbcHOI2Y7yixfBQ29IrSv1SWhhG5UEQqIVJrs2QEWL6+FOsGiPOwPYQJBAP+5dn1kmYtSK11mZVkzwHFbmezZNs/AQE6v6TErd7amBQpyCP9wwoEeOsreHDxt8/NiqbAvr43orgHHcOdAG0kCQQC9qfyEIIagCui3zM04tzN6WmclDXL8t+dHMRkt8Zmyu7WMqXoYjgwMcv5n7qNJaxi9V2MMA9Y+P3EyCCjFyON3AkAgrNv9Dbuo16j+2DSe/0PZuDCk2ORuC0ysQUH0rG8xgWkneoa3zPqtcOVmQpctCYegU70G7DDsWwzQ4WEFy2UxAkAJ0QKA1C4jmmzxFmiIxvKjIoq0ID4TVnFh/eiPuDF8TrrWzO7E1pVJD6qbNn69Dg35vswhkxFDp4T0UffKRNuBAkBe1e4IhJzFvXlTtjA2PBXvMrpIH8d7KAGvMvJ2MuWvwYCXOkHdBdO9Z9y9A4H2y3rjeFPtZqALVB9P/5yhqsfn
公钥加密后:nVwqASzu5zwJOy1ADkVC1Vji9LxCmgwVjd1+2S1KEsKvk/ru0Hmij5weZMjkgORxpxjwqF7Dx7xVUcOuUwGtDMY/mhJVkAMRUWfRZyLFZXb5C710EqpEkzWIFbCdhqXWpgDzc5W/enBjHednxVlZ7tlXJCivwgkxg+4l1+mN2Ho=
私钥钥加密后:什么是快乐

上述代码参考了,RSA加密与解密(Java实现)。但是它只有公钥加密,私钥解密。再此基础上我增加了私钥加密,公钥解密的方法。

前端加密

后端成功公钥私钥后下一步就是在前端对数据进行公钥加密

第一步 npm引入jsencrypt

npm i jsencrypt -S

第二步 创建一个js文件

/* 产引入jsencrypt实现数据RSA加密 */
import JSEncrypt from 'jsencrypt' // 处理长文本数据时报错 jsencrypt.js Message too long for RSA
/* 产引入encryptlong实现数据RSA加密 */
import Encrypt from 'encryptlong' // encryptlong是基于jsencrypt扩展的长文本分段加解密功能。


    //加密,公钥加密
export function   encrypt(data,publicKey) {
        var encryptor = new Encrypt()
        encryptor.setPublicKey(publicKey)
        // 如果是对象/数组的话,需要先JSON.stringify转换成字符串
        const result = encryptor.encryptLong(data)
        return result
    }
export function   decrypt(data,publicKey) {
        var encryptor = new Encrypt()
        encryptor.setPrivateKey(publicKey)
        // 如果是对象/数组的话,需要先JSON.stringify转换成字符串
        var result = encryptor.decryptLong(data)
        return result
    }

第三、在vue文件中使用

引入上面的方法

import {encrypt,decrypt} from "../../assets/js/rsaUtil"

测试代码:

testAes: function () {
      var s = '什么是快乐'
      var pubKey='MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9dbooWM72qimN1WjxnkXTR2FNMX+EUDIA3BTPQQX2bn61bntD9hps+DOhNX4Wgb3l6wsqOEy/MhLXLojI0lBWfzf6Ch5MuAj9vnIINZsAEgcZw+d8F1R73czZIGk3f4OWCLYV3ZcXlxJChSGuTRKLOfuq1eMrJbfY9l0F1QZp7wIDAQAB'
      var s1=encrypt(s,pubKey)
      console.log('加密后的字符串:'+s1);
      var priKey='MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAL11uihYzvaqKY3VaPGeRdNHYU0xf4RQMgDcFM9BBfZufrVue0P2Gmz4M6E1fhaBveXrCyo4TL8yEtcuiMjSUFZ/N/oKHky4CP2+cgg1mwASBxnD53wXVHvdzNkgaTd/g5YIthXdlxeXEkKFIa5NEos5+6rV4yslt9j2XQXVBmnvAgMBAAECgYBvJ4zqcwAp87ehgR2q9ELfLDfIBExeInbTzktfNTT8WeN5KrKjMtZaLFyOLkYlikURiY7pXFKashQfryuNNubuczHvb3n+iyGpWySETx7QYgKeTIDy3/zYbcHOI2Y7yixfBQ29IrSv1SWhhG5UEQqIVJrs2QEWL6+FOsGiPOwPYQJBAP+5dn1kmYtSK11mZVkzwHFbmezZNs/AQE6v6TErd7amBQpyCP9wwoEeOsreHDxt8/NiqbAvr43orgHHcOdAG0kCQQC9qfyEIIagCui3zM04tzN6WmclDXL8t+dHMRkt8Zmyu7WMqXoYjgwMcv5n7qNJaxi9V2MMA9Y+P3EyCCjFyON3AkAgrNv9Dbuo16j+2DSe/0PZuDCk2ORuC0ysQUH0rG8xgWkneoa3zPqtcOVmQpctCYegU70G7DDsWwzQ4WEFy2UxAkAJ0QKA1C4jmmzxFmiIxvKjIoq0ID4TVnFh/eiPuDF8TrrWzO7E1pVJD6qbNn69Dg35vswhkxFDp4T0UffKRNuBAkBe1e4IhJzFvXlTtjA2PBXvMrpIH8d7KAGvMvJ2MuWvwYCXOkHdBdO9Z9y9A4H2y3rjeFPtZqALVB9P/5yhqsfn'
      var s2=decrypt(s1,priKey)
      console.log(s2);
    }

运行结果

java调用接口 前后端加密验签 java前端密码加密_ci_03


可以看到虽然前端和后端两者加密后的密文不一样,但是都能通过私钥成功解码。

在之后就是明文加密后保存数据库了。