前后台加解密的使用--SHA256算法 RSA算法 AES算法

SHA256算法

sha256与md5一样是散列算法,不是加密算法,不存在解密的问题,因此是不可逆的,可以通过key+password,对密码进行加密,在后台进行比对,安全性比md5高一点,加密后生成的密文为64位,而md5为32位;此外还可以使用sha512安全性相对更高一些,密文为128位。

前端使用
vue引入npm install js-sha256
下载地址为:https://cdnjs.cloudflare.com/ajax/libs/js-sha256/0.9.0/sha256.jshttps://cdnjs.cloudflare.com/ajax/libs/js-sha256/0.9.0/sha256.min.js

// If you use node.js, you should require the module first:
// var sha256 = require('js-sha256');
// or TypeScript
import { sha256, sha224 } from 'js-sha256';
function randomString(e) {  
  e = e || 32;  //e为随机码位数
  var t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
  a = t.length;
  n = "";
  for (i = 0; i < e; i++){
     n += t.charAt(Math.floor(Math.random() * a));
  }
  return n;
}
var key=randomString(16);
var enctyptData = sha256(key+password);  //前台页面输入的密码
// var enctyptData = sha256.hex(key+password);  支持中英文 数组 sha256()和sha256.hex()密文一致

java后端使用

String decryptData = DigestUtils.sha256Hex(key+password);  //后台从数据库中获取的密码

以上可看出在使用sha256算法进行加密时,前后台同时需要key值,为了保证前后台在传输key的过程中安全性更高,使得key值不被泄露,因此可以使用ras加密算法对key值进行加密。

RSA算法

RSA算法是一种非对称的加密算法,通过生成一对私钥密钥进行加解密,后台将私钥进行存储在session中,将公钥传到前台进行关键值加密,将加密之后的密文传往后台,通过使用私钥进行解密,因此rsa算法是可逆的,通常用于对key值进行加解密,与AES算法结合使用,保证系统的安全性。
前台使用
vue引入 npm install jsencrypt
或下载地址(jsencrypt.js / jsencrypt.min.js)为:https://github.com/travist/jsencrypt/blob/master/bin/jsencrypt.js

<!doctype html>
<html>
  <head>
    <title>JavaScript RSA Encryption</title>
    <script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
    <script src="bin/jsencrypt.min.js"></script>
    <script type="text/javascript">

      // Call this code when the page is done loading.
      $(function() {

        // Run a quick encryption/decryption when they click.
        $('#testme').click(function() {

          // Encrypt with the public key...
          var encrypt = new JSEncrypt();
          encrypt.setPublicKey($('#pubkey').val());
          var encrypted = encrypt.encrypt($('#key').val());

          // Decrypt with the private key...
          var decrypt = new JSEncrypt();
          decrypt.setPrivateKey($('#privkey').val());
          var decryptedkey = decrypt.decrypt(encrypted);

          // Now a simple check to see if the round-trip worked.
          if (decryptedkey == $('#input').val()) {
            alert('It works!!!');
          }
          else {
            alert('Something went wrong....');
          }
        });
      });
    </script>
  </head>
  <body>
    <label for="privkey">Private Key</label><br/>
    <textarea id="privkey" rows="15" cols="65">
   						     -----BEGIN RSA PRIVATE KEY-----
				MIICXQIBAAKBgQDlOJu6TyygqxfWT7eLtGDwajtNFOb9I5XRb6khyfD1Yt3YiCgQ
				WMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76xFxdU6jE0NQ+Z+zEdhUTooNR
				aY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4gwQco1KRMDSmXSMkDwIDAQAB
				AoGAfY9LpnuWK5Bs50UVep5c93SJdUi82u7yMx4iHFMc/Z2hfenfYEzu+57fI4fv
				xTQ//5DbzRR/XKb8ulNv6+CHyPF31xk7YOBfkGI8qjLoq06V+FyBfDSwL8KbLyeH
				m7KUZnLNQbk8yGLzB3iYKkRHlmUanQGaNMIJziWOkN+N9dECQQD0ONYRNZeuM8zd
				8XJTSdcIX4a3gy3GGCJxOzv16XHxD03GW6UNLmfPwenKu+cdrQeaqEixrCejXdAF
				z/7+BSMpAkEA8EaSOeP5Xr3ZrbiKzi6TGMwHMvC7HdJxaBJbVRfApFrE0/mPwmP5
				rN7QwjrMY+0+AbXcm8mRQyQ1+IGEembsdwJBAN6az8Rv7QnD/YBvi52POIlRSSIM
				V7SwWvSK4WSMnGb1ZBbhgdg57DXaspcwHsFV7hByQ5BvMtIduHcT14ECfcECQATe
				aTgjFnqE/lQ22Rk0eGaYO80cc643BXVGafNfd9fcvwBMnk0iGX0XRsOozVt5Azil
				psLBYuApa66NcVHJpCECQQDTjI2AQhFc1yRnCU/YgDnSpJVm1nASoRUnU8Jfm3Oz
				uku7JUXcVpt08DFSceCEX9unCuMcT72rAQlLpdZir876
						    -----END RSA PRIVATE KEY-----
	</textarea><br/>
    <label for="pubkey">Public Key</label><br/>
    <textarea id="pubkey" rows="15" cols="65">
			              -----BEGIN PUBLIC KEY-----
			MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlOJu6TyygqxfWT7eLtGDwajtN
			FOb9I5XRb6khyfD1Yt3YiCgQWMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76
			xFxdU6jE0NQ+Z+zEdhUTooNRaY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4
			gwQco1KRMDSmXSMkDwIDAQAB
			              -----END PUBLIC KEY-----
</textarea><br/>
    <label for="key">Text to encrypt:</label><br/>
    <textarea id="key" name="input" type="text" rows=4 cols=70>This is a test!</textarea><br/>
    <input id="testme" type="button" value="Test Me!!!" /><br/>
  </body>
</html>

后台使用
生成私钥密钥对+加解密数据

package RSA;
 
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
 
import javax.crypto.Cipher;
 
import org.apache.commons.collections.set.SynchronizedSet;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
 
public class RSAUtils {
    public static final String KEY_ALGORITHM = "RSA";
 
    private static final String PUBLIC_KEY = "RSAPublicKey";
 
    private static final String PRIVATE_KEY = "RSAPrivateKey";
 
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
    /**
     * RSA最大加密明文大小
     * */
    private static final int MAX_ENCRYPT_BLOCK = 117;
 
    /**
    * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;
 
    private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
 
    //获得公钥字符串
    public static String getPublicKeyStr(Map<String, Object> keyMap) throws Exception {
        //获得map中的公钥对象 转为key对象
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        //编码返回字符串
        return bytesToHex(encryptBASE64(key.getEncoded()).getBytes());
    }
 
    //获得私钥字符串
    public static String getPrivateKeyStr(Map<String, Object> keyMap) throws Exception {
        //获得map中的私钥对象 转为key对象
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        //编码返回字符串
        return bytesToHex(encryptBASE64(key.getEncoded()).getBytes());
    }
 
 
    //获取公钥
    public static PublicKey getPublicKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = (new BASE64Decoder()).decodeBuffer(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }
 
    //获取私钥
    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = (new BASE64Decoder()).decodeBuffer(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }
 
    //解码返回byte
    public static byte[] decryptBASE64(String key) throws Exception {
        return (new BASE64Decoder()).decodeBuffer(key);
    }
 
    //编码返回字符串
    public static String encryptBASE64(byte[] key) throws Exception {
        return (new BASE64Encoder()).encodeBuffer(key);
    }
 
    //***************************签名和验证*******************************  
    public static String sign(byte[] data, String privateKeyStr) throws Exception {
        PrivateKey priK = getPrivateKey(new String(hexToBytes(privateKeyStr)));
        Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
        sig.initSign(priK);
        sig.update(data);
        return bytesToHex(sig.sign());
    }
 
    public static boolean verify(byte[] data, String sign, String publicKeyStr) throws Exception {
        PublicKey pubK = getPublicKey(new String(hexToBytes(publicKeyStr)));
        Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
        sig.initVerify(pubK);
        sig.update(data);
        return sig.verify(hexToBytes(sign));
    }
 
    //************************加密解密**************************  
    public static String encrypt(byte[] plainText, String publicKeyStr) throws Exception {
        PublicKey publicKey = getPublicKey(new String(hexToBytes(publicKeyStr)));
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        int inputLen = plainText.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        int i = 0;
        byte[] cache;
        while(inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK){
                cache = cipher.doFinal(plainText, offSet, MAX_ENCRYPT_BLOCK);
            } else{
                cache = cipher.doFinal(plainText, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptText = out.toByteArray();
        out.close();
        return bytesToHex(encryptText);
    }
 
    public static String decrypt(String encryptTextHex, String privateKeyStr) throws Exception {
        byte[] encryptText = hexToBytes(encryptTextHex);
        PrivateKey privateKey = getPrivateKey(new String(hexToBytes(privateKeyStr)));
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        int inputLen = encryptText.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(encryptText, offSet, MAX_DECRYPT_BLOCK);
            } else{
               cache = cipher.doFinal(encryptText, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] plainText = out.toByteArray();
        out.close();
        return new String(plainText);
    }
 
    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(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }
 
    /**
     * 将byte[]转换为16进制字符串
     */
    public static String bytesToHex(byte[] bytes) {
        //一个byte为8位,可用两个十六进制位标识
        char[] buf = new char[bytes.length * 2];
        int a = 0;
        int index = 0;
        for(byte b : bytes) { // 使用除与取余进行转换
            if(b < 0) {
                a = 256 + b;
            } else {
                a = b;
            }
 
            buf[index++] = HEX_CHAR[a / 16];
            buf[index++] = HEX_CHAR[a % 16];
        }
        return new String(buf);
    }
    /**
     * 将16进制字符串转换为byte[]
     *
     * @param str
     * @return
     */
    public static byte[] hexToBytes(String str) {
        if(str == null || str.trim().equals("")) {
            return new byte[0];
        }
 
        byte[] bytes = new byte[str.length() / 2];
        for(int i = 0; i < str.length() / 2; i++) {
            String subStr = str.substring(i * 2, i * 2 + 2);
            bytes[i] = (byte) Integer.parseInt(subStr, 16);
        }
 
        return bytes;
    }
    
    public static void main(String[] args) throws Exception {
        Map<String, Object> keyMap;
        String cipherText;
        String input = "10001eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
        try {
            keyMap = initKey();
            String publicKey = RSAUtils.getPublicKeyStr(keyMap);
            System.out.println("公钥------------------");
            System.out.println(publicKey);
            System.out.println("length: " + publicKey.length());
 
            String privateKey = RSAUtils.getPrivateKeyStr(keyMap);
            System.out.println("私钥------------------");
            System.out.println(privateKey);
            System.out.println("length: " + privateKey.length());
 
            System.out.println("测试可行性-------------------");
            System.out.println("明文=======" + input);
            System.out.println("length: " + input.length());
 
            cipherText = RSAUtils.encrypt(input.getBytes(), publicKey);
            //加密后的东西 
            System.out.println("密文=======" + cipherText);
            System.out.println("length: " + cipherText.length());
 
            //开始解密 
            String plainText =RSAUtils. decrypt(cipherText, privateKey);
            System.out.println("解密后明文===== " + new String(plainText));
            System.out.println("验证签名-----------");
 
            String str = "被签名的内容sssssssassssssssssssssssssssssssssssssssss";
            System.out.println("\n原文:" + str);
            String signature = RSAUtils.sign(str.getBytes(), privateKey);
            System.out.println(signature);
            System.out.println(signature.length());
            boolean status = RSAUtils.verify(str.getBytes(), signature, publicKey);
            System.out.println("验证情况:" + status);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 

AES算法

AES算法是对称算法,经常与RSA算法结合使用,但因AES算法是对称的,解密相比RSA算法会快一点,效率高一点,因此经常使用RSA算法通过公钥加密key值,使用AES算法加密key+参数,将两个密文通过ajax传到后台,使用RSA算法的私钥解密key值,使用AES算法通过解密后的key来解密参数,根据业务处理参数,将结果通过AES进行加密返回前台,然后通过前端AES解密将结果在前端进行渲染。
前台使用
vue引入 npm install crypto-js
下载地址为:https://gitee.com/gitcrazy/crypto-js/tree/master

// Plain text encryption  简单使用
var CryptoJS = require("crypto-js");

// Encrypt
var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123').toString();

// Decrypt
var bytes  = CryptoJS.AES.decrypt(ciphertext, 'secret key 123');
var originalText = bytes.toString(CryptoJS.enc.Utf8);

console.log(originalText); // 'my message'
// Object encryption
var CryptoJS = require("crypto-js");

var data = [{id: 1}, {id: 2}]

// Encrypt
var ciphertext = CryptoJS.AES.encrypt(JSON.stringify(data), 'secret key 123').toString();

// Decrypt
var bytes  = CryptoJS.AES.decrypt(ciphertext, 'secret key 123');
var decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8));

console.log(decryptedData); // [{id: 1}, {id: 2}]
//推荐这种方式
import CryptoJS from 'crypto-js/crypto-js'   

// 默认的 KEY 与 iv 如果没有给
const KEY = CryptoJS.enc.Utf8.parse('1019E2991V09O17L1019E2991V09O17L')
const IV = CryptoJS.enc.Utf8.parse('1019E2991V09O17L')
/**
 * AES加密 :字符串 key iv  返回base64
 */
export function Encrypt (data, 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(data)
  var encrypted = CryptoJS.AES.encrypt(srcs, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  })
  // console.log("-=-=-=-", encrypted.ciphertext)
  return CryptoJS.enc.Base64.stringify(encrypted.ciphertext)
}
/**
 * AES 解密 :字符串 key iv  返回base64
 *
 */
export function Decrypt (encryotData, 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(encryotData)
  let src = CryptoJS.enc.Base64.stringify(base64)

  var decrypt = CryptoJS.AES.decrypt(src, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  })

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

后台使用

		package com.winning.devops.util;
		
		import org.apache.commons.codec.binary.Base64;
		
		import javax.crypto.Cipher;
		import javax.crypto.spec.IvParameterSpec;
		import javax.crypto.spec.SecretKeySpec;
		
		public class AesUtil {
		
		    private static String KEY = "1019E2991V09O17L1019E2991V09O17L";
		
		    private static String IV = "1019E2991V09O17L";
		
		
		    /**
		     * 加密方法
		     *
		     * @param data 要加密的数据
		     * @param key  加密key
		     * @param iv   加密iv
		     * @return 加密的结果
		     * @throws Exception
		     */
		    public static String encrypt(String data, String key, String iv) throws Exception {
		        try {
		            //"算法/模式/补码方式"PKCS5Padding"
		            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
		            byte[] plaintext = data.getBytes("UTF-8");
		
		            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
		            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
		
		            cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
		            byte[] encrypted = cipher.doFinal(plaintext);
		
		            return new Base64().encodeToString(encrypted);
		
		        } catch (Exception e) {
		            e.printStackTrace();
		            return null;
		        }
		    }
		
		    /**
		     * 解密方法
		     *
		     * @param data 要解密的数据
		     * @param key  解密key
		     * @param iv   解密iv
		     * @return 解密的结果
		     * @throws Exception
		     */
		    public static String decrypt(String data, String key, String iv) throws Exception {
		        try {
		            byte[] encrypted1 = new Base64().decode(data);
		
		            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
		            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
		            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
		
		            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
		
		            byte[] original = cipher.doFinal(encrypted1);
		            String originalString = new String(original, "UTF-8");
		            return originalString;
		        } catch (Exception e) {
		            e.printStackTrace();
		            return null;
		        }
		    }
		
		    /**
		     * 使用默认的key和iv加密
		     *
		     * @param data
		     * @return
		     * @throws Exception
		     */
		    public static String encrypt(String data) throws Exception {
		        return encrypt(data, KEY, IV);
		    }
		
		    /**
		     * 使用默认的key和iv解密
		     *
		     * @param data
		     * @return
		     * @throws Exception
		     */
		    public static String decrypt(String data) throws Exception {
		        return decrypt(data, KEY, IV);
		    }
		
		
		    /**
		     * 测试
		     */
		    public static void main(String args[]) throws Exception {
		
		        String test1 = "root";
		        String test = new String(test1.getBytes(), "UTF-8");
		        String data = null;
		        String key = KEY;
		        String iv = IV;
		        data = encrypt(test, key, iv);
		        System.out.println("数据:" + test);
		        System.out.println("加密:" + data);
		        String jiemi = decrypt(data, key, iv);
		        System.out.println("解密:" + jiemi);
		    }
		
		}

注意: 后端的补码方式设置为PKCS5Padding,对应vue前端的CryptoJS.pad.Pkcs7。如果此处改为无补码的方式,解密后得到的字符串会有多余空格。

上一篇:Java实现简单的加密,解密实例


下一篇:Java版AES-CBC-CMAC加密