AES对称加密的简单运用

前端JS对称加密、解密数据

准备事项:引入jquery.js与crypto-js.js



加密

//AES加密
function encrypt(context) {
    var encrypted = '';
    if (typeof(context) == 'object') {
        context = JSON.stringify(context);
    }
    var srcs = CryptoJS.enc.Utf8.parse(context);
    encrypted = CryptoJS.AES.encrypt(srcs, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return encrypted.toString()
}

解密

// AES解密
function decrypt(context) {
    var decrypt = CryptoJS.AES.decrypt(context, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr.toString();
}

 

 

后端Java对称加密、解密数据

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Base64;

/**
 * 对称加密解密AES算法
 *
 * @author JustryDeng
 * @date 2018年7月20日 下午6:12:35
 */
public class AESEncryptAndDecryptUtil {

	/** 对应:算法/模式/补码方式 */
	private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";

	/** 高级加密标准算法 */
	private static final String ALGORITHM = "AES";

	/** 字符编码 */
	private static final String CHARSET = "utf-8";

	/** 必须16位 must be 16 bytes long */
	private static final String IV = "A-16-Byte-String";

	/**
	 * key为 [16位字节长度 或 24位字节长度 或者 32位字节长度]的字符串 注: key不要是中文
	 * 注:我们可以定死key,也可以通过传参来获取传过来的key(本人采用传参的方式,所以这个属性注释掉了)
	 */
	// private static final String KEY = "A-16-Byte-keyVal";

	/**
	 * 加密
	 *
	 * @param context
	 *            要加密的字符串数据
	 * @param key
	 *            秘钥
	 * @return 加密后的数据字符串
	 * @date 2018年7月20日 下午6:17:44
	 */
	public static String encrypt(String context, String key) {
		try {
			byte[] decode = context.getBytes(CHARSET);
			byte[] bytes = createKeyAndIv(decode, Cipher.ENCRYPT_MODE, key);
			return Base64.getEncoder().encodeToString(bytes);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 解密
	 *
	 * @param context
	 *            要解密的字符串数据
	 * @param key
	 *            对应的秘钥(不论是前端还是后端加的密,key都要和加密时的一样)
	 * @return 解密后的数据字符串
	 * @date 2018年7月20日 下午6:18:35
	 */
	public static String decrypt(String context, String key) {
		try {
			Base64.Decoder decoder = Base64.getDecoder();
			byte[] decode = decoder.decode(context);
			byte[] bytes = createKeyAndIv(decode, Cipher.DECRYPT_MODE, key);
			return new String(bytes, CHARSET);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 与cipherFilter方法配合,获取加密/解密后的字节数组
	 *
	 * @date 2018年7月20日 下午6:21:34
	 */
	public static byte[] createKeyAndIv(byte[] context, int opmode, final String key) throws Exception {
		byte[] keyArray = key.getBytes(CHARSET);
		byte[] iv = IV.getBytes(CHARSET);
		return cipherFilter(context, opmode, keyArray, iv);
	}

	public static byte[] cipherFilter(byte[] context, int opmode, byte[] key, byte[] iv) throws Exception {
		Key secretKeySpec = new SecretKeySpec(key, ALGORITHM);
		AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(iv);
		Cipher cipher = Cipher.getInstance(TRANSFORMATION);
		cipher.init(opmode, secretKeySpec, ivParameterSpec);
		return cipher.doFinal(context);
	}

}

后端对称加密、解密主函数测试一下

import com.aspire.util.AESEncryptAndDecryptUtil;

/**
 * 以主函数进行测试
 *
 * @author JustryDeng
 * @date 2018年7月20日 下午6:40:05
 */
public class Test {
	public static void main(String[] args) {
		// 16个 或 24个 或 32个 字节长度 即可(注:不要是中文)
		String key = "key0123456789key";
		String context = "JustryDeng";
		System.out.println("原数据:" + context);
		// 加密
		String encrypt = AESEncryptAndDecryptUtil.encrypt(context, key);
		System.out.println("加密后:" + encrypt);
		// 解密
		String decrypt = AESEncryptAndDecryptUtil.decrypt(encrypt, key);
		System.out.println("解密后:" + decrypt);
	}
}

输出结果为

 

 

前端JS对称加密、后端JAVA接收并解密数据

先给出后端Controller层的代码示例

package com.aspire.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.aspire.util.AESEncryptAndDecryptUtil;

/**
 * 前端对称加密 给 后端加密
 *
 * @author JustryDeng
 * @date 2018年7月20日 下午3:19:44
 */
@RestController
public class EncryptAndDecryptController {
	
	// KEY要与前端加密时保持一致(且:应为:16或24或32字节长度)
	private static final String KEY = "A-16-Byte-keyVal";

	/**
	 * 
	 *
	 * @param encryptedTarget
	 *            加密后的数据字符串
	 * @return 
	 * @date 2018年7月20日 下午6:47:28
	 */
	@RequestMapping("/EncryptAndDecryptTest")
	public String test(@RequestParam("encryptedTarget") String encryptedTarget) {
		StringBuffer sb = new StringBuffer();
		try {
            // 调用后端AES加密解密工具类(在上面的示例中以给出)
			String decryptTarget = AESEncryptAndDecryptUtil.decrypt(encryptedTarget,KEY);
			sb.append(">>>解密前:" + encryptedTarget);
			sb.append(">>>解密前的内容长度:" + encryptedTarget.length());
			sb.append(">>>加密密钥和解密密钥:" + KEY);
			sb.append(">>>解密后:" + decryptTarget);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return sb.toString();
	}

}

再给出前端HTML的测试代码为




	
	加密demo
	
	
	
	




    
加密前:
加密后:

页面是这样的

AES对称加密的简单运用_第1张图片

提交表单访问后台接口,返回的结果是

由此可见:前端加密,后端解密,成功!

 

提示1:实际上,秘钥key可以设置为动态的,每次前端要发送加密数据前,先问后端要一                  个 key,然后用这个key加密数据并发送到后端;后端使用这个key解密后,再销毁这个             key使其失效。

提示2:再严格一点就是,前后端不仅更换秘钥key,甚至还不停地更换加密方法等。

 

本人内容参考自菜鸟学堂

代码托管链接https://github.com/JustryDeng/PublicRepository

如有不当之处,欢迎指正

本文已经被收录进《程序员成长笔记(二)》,作者JustryDeng

 

你可能感兴趣的:(Java知识大杂烩)