zoukankan      html  css  js  c++  java
  • Java 对称加密

    最近在做一个用户 token 功能,学习了加密相关 AES/DES、RSA 等。其中涉及一个对称和非对称加密问题。对称加密虽然没有非对称加密那样安全性高,但好处是加密速度快,但某些场合还是可以选择使用的,例如当下的用户认知机制,它是基于 token 无状态的,每次请求过来都会认证一次,这样就必须要比较高速度的加密解密运算,于是我们选择了 AES 加密方式。

    下面是对称加密的工具类,完全可以不依赖其他三方 jar 包。不过有个 base64 方法我封装起来了(下面会补充)。

    import java.nio.charset.StandardCharsets;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.KeyGenerator;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.SecretKey;
    
    import com.ajaxjs.util.Encode;
    
    /**
     * 对称算法
     * @author admin
     *
     */
    public class SymmetricCipher {
    	public SymmetricCipher() {}
    	public SymmetricCipher(String ALGORITHM, int keySize) {
    		this.ALGORITHM = ALGORITHM;
    		this.keySize = keySize;
    	}
    	/**
    	 * DES = 56 | AES = 128
    	 */
    	private int keySize = 128;
    
    	/**
    	 * 加密算法,可以 DES | AES
    	 */
    	private String ALGORITHM = "AES";
    	
    	/**
    	 * 加密
    	 * 
    	 * @param str
    	 *            要加密的内容
    	 * @param key
    	 *            密钥
    	 * @return 加密后的内容
    	 */
    	public String encrypt(String str, String key) {
    		// 这里要设置为utf-8不然内容中如果有中文和英文混合中文就会解密为乱码
    		return doCipher(true, key, str, str.getBytes(StandardCharsets.UTF_8));
    	}
    
    	/**
    	 * 解密
    	 * 
    	 * @param str
    	 *            要解密的内容
    	 * @param key
    	 *            密钥
    	 * @return 解密后的内容
    	 */
    	public String decrypt(String str, String key) {
    		return doCipher(false, key, str, Encode.base64DecodeAsByte(str));
    	}
    	
    	private String doCipher(boolean isENCRYPT_MODE, String key, String str, byte[] bytes) {
    		Cipher cipher = null;
    		
    		try {
    			cipher = Cipher.getInstance(ALGORITHM);
    			cipher.init(isENCRYPT_MODE ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, generateKey(key));
    		} catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException e) {
    			e.printStackTrace();
    			return null;
    		}
    		
    		byte[] buf;
    		try {
    			// 为了防止解密时报javax.crypto.IllegalBlockSizeException: Input length must
    			// be multiple of 8 when decrypting with padded cipher异常,
    			// 不能把加密后的字节数组直接转换成字符串
    			buf = cipher.doFinal(bytes);
    		} catch (IllegalBlockSizeException | BadPaddingException e) {
    			e.printStackTrace();
    			return null;
    		}
    		
    		return isENCRYPT_MODE ? Encode.base64Encode(buf) : Encode.byte2String(buf);
    	}
    
    	/**
    	 * 获得密钥对象
    	 * 
    	 * @param key
    	 *            密钥
    	 * @return 密钥对象
    	 */
    	private SecretKey generateKey(String key) {
    		SecureRandom secureRandom;
    		KeyGenerator kg;
    		
    		try {
    			secureRandom = SecureRandom.getInstance("SHA1PRNG");
    			secureRandom.setSeed(key.getBytes());
    			kg = KeyGenerator.getInstance(ALGORITHM);
    		} catch (NoSuchAlgorithmException e) {
    			e.printStackTrace();
    			return null;
    		}
    		
    		kg.init(keySize, secureRandom);
    		return kg.generateKey();// 生成密钥
    	}
    	
    	final static SymmetricCipher AES = new SymmetricCipher();
    	final static SymmetricCipher DES = new SymmetricCipher("DES", 56);
    
    	/**
    	 * AES 加密
    	 * 
    	 * @param str
    	 *            要加密的内容
    	 * @param key
    	 *            密钥
    	 * @return 加密后的内容
    	 */
    	public static String AES_Encrypt(String str, String key) {
    		return AES.encrypt(str, key);
    	}
    
    	/**
    	 * AES 解密
    	 * @param str
    	 * @param key
    	 * @return
    	 */
    	public static String AES_Decrypt(String str, String key) {
    		return AES.decrypt(str, key);
    	}
    }

    使用方法如下

    import org.junit.Test;
    import static org.junit.Assert.*;
    
    import com.ajaxjs.user.password.SymmetricCipher;
    
    public class TestPassword {
    	String input = "cy11Xlbrmzyh:604:301:1353064296";
    	String key = "37d5aed075525d4fa0fe635231cba447";
    	
    	@Test
    	public void testEncryption() {
    		String EncryptedPassword = SymmetricCipher.AES_Encrypt(input, key);
    //		System.out.println("EncryptedPassword::" +EncryptedPassword);
    		
    		assertEquals(input, SymmetricCipher.AES_Decrypt(EncryptedPassword, key));
    	}
    }

    Base64 编码解码方法

    package com.ajaxjs.util;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.net.URLDecoder;
    import java.net.URLEncoder;
    import java.nio.charset.StandardCharsets;
    
    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;
    
    /**
     * 字符串的编码、解密
     * @author admin
     *
     */
    public class Encode {
    	/**
    	 * 字节转编码为 字符串( UTF-8 编码)
    	 * 
    	 * @param bytes
    	 *            输入的字节数组
    	 * @return 字符串
    	 */
    	public static String byte2String(byte[] bytes) {
    		return new String(bytes, StandardCharsets.UTF_8);
    	}
    	
    	/**
    	 * 字符串转为 UTF-8 编码的字符串
    	 * 
    	 * @param str
    	 *            输入的字符串
    	 * @return UTF-8 字符串
    	 */
    	public static String byte2String(String str) {
    		return byte2String(str.getBytes());
    	}
    	
    	/**
    	 * 将 URL 编码的字符还原,默认 UTF-8 编码
    	 * 
    	 * @param str
    	 *            已 URL 编码的字符串
    	 * @return 正常的 Java 字符串
    	 */
    	public static String urlDecode(String str) {
    		try {
    			return URLDecoder.decode(str, StandardCharsets.UTF_8.toString());
    		} catch (UnsupportedEncodingException e) {
    			return null;
    		}
    	}
    
    	/**
    	 * 将字符进行 URL 编码,默认 UTF-8 编码
    	 * 
    	 * @param str
    	 *            正常的 Java 字符串
    	 * 
    	 * @return 已 URL 编码的字符串
    	 */
    	public static String urlEncode(String str) {
    		try {
    			return URLEncoder.encode(str, StandardCharsets.UTF_8.toString());
    		} catch (UnsupportedEncodingException e) {
    			return null;
    		}
    	}
    
    	/**
    	 * url 网址中文乱码处理。
    	 * 如果 Tomcat 过滤器设置了 utf-8 那么这里就不用重复转码了
    	 * 
    	 * @param str
    	 *            通常是 url Query String 参数
    	 * @return 中文
    	 */
    	public static String urlChinese(String str) {
    		return byte2String(str.getBytes(StandardCharsets.ISO_8859_1));
    	}
    	
    	/**
    	 * BASE64 编码
    	 * @param bytes输入的字节数组
    	 * @return 已编码的字符串
    	 */
    	public static String base64Encode(byte[] bytes) {
    		return new BASE64Encoder().encode(bytes);
    	}
    	
    	/**
    	 * BASE64 编码
    	 * 
    	 * @param str
    	 *            待编码的字符串
    	 * @return 已编码的字符串
    	 */
    	public static String base64Encode(String str) {
    		return base64Encode(str.getBytes());
    	}
    	
    	public static byte[] base64DecodeAsByte(String str) {
    		BASE64Decoder decoder = new BASE64Decoder();
    
    		try {
    			return decoder.decodeBuffer(str);
    		} catch (IOException e) {
    			e.printStackTrace();
    			return null;
    		}
    	}
    
    	/**
    	 * BASE64 解码 这里需要强制捕获异常。
    	 * 中文乱码:http://s.yanghao.org/program/viewdetail.php?i=54806
    	 * 
    	 * @param str
    	 *            已解码的字符串
    	 * @return 已解码的字符串
    	 */
    	public static String base64Decode(String str) {
    		return byte2String(base64DecodeAsByte(str));
    	}
    }
     java学习群669823128
  • 相关阅读:
    【JAVASCRIPT】JS实现淘宝,百度评分功能
    【数据结构】链式线性表的几种常用用法
    【JAVASCRIPT】无刷新评论
    【JAVASCRIPT】表单序列化问题
    【JAVASCRIPT】如何不使用jquery函数和ajax框架实现ajax效果
    图灵北京作译者交流会
    是起点,而非终点——评《程序员的思维修炼》
    2011图灵新春特献
    图灵2011.01书讯
    图灵2010.12书讯
  • 原文地址:https://www.cnblogs.com/rese-t/p/7941764.html
Copyright © 2011-2022 走看看