开发者社区> sp42> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Java 对称加密

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

最近在做一个用户 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小工匠聊密码学】--对称加密--DES
1、 DES算法   DES对称加密,对称加密,是一种比较传统的加密方式,其加密运算、解密运算使用的是同样的密钥,信息的发送者和信息的接收者在进行信息的传输与处理时,必须共同持有该密码(称为对称密码),是一对称加密算法。
1279 0
Java也可以非常简单的实现图片灰度化
本文通过一个简单的实例,演示如何使用java来实现图片灰度化处理,主要借助下面两种策略来处理颜色
162 0
JAVA | Spring + quartz 实现定时任务
很久不见,因为忙着泡妞,断更了一个月,实在是罪过。废话不多说,最近在工作中遇到了使用 quartz 实现定时任务的需求。写出来分享给大家,权当笔记。
59 0
Java使用数组和循环结构实现简单的商品管理系统
今天使用数组和循环结构实现了一个简单的商品管理系统主要功能如下: 1.查询所有商品、2.添加、3.修改、4.删除、5.退出 查询: 编号 名称 价格 1 苹果 3.1 2 橘子 3.5 添加: 输入编号名称价格添加到数组中 修改: 根据编号修改名称、价...
1008 0
Java实现文本编辑时基于拼音输入的补全原型
尝试中文输入法和IDE补全/提示的集成
827 0
Java实现命令式简易文本编辑器原型
Java实现"命令式"简易文本编辑器原型
1121 0
Java实现英汉词典API初版发布在Maven
基于ECDICT词典数据, 开发一个Java库实现词典接口, 发布到Maven主库. Publish Java library to provide English-to-Chinese dictionary API on Maven Central.
1154 0
JAVA线程及简单同步实现的原理解析
JAVA线程及简单同步实现的原理解析线程一、内容简介:  本文主要讲述计算机中有关线程的相关内容,以及JAVA中关于线程的基础知识点,为以后的深入学习做铺垫。如果你已经是高手了,那么这篇文章并不适合你。
1245 0
线性表概述及单链表的Java实现
线性表概述及单链表的Java实现一、线性表概述线性表是指一组数据元素之间具有线性关系的元素序列,它表现为:除第一个元素没有直接前驱元素、最后一个元素没有直接后继元素外,其余所有元素都有且仅有一个直接前驱元素和直接后继元素。
881 0
烂尾工程: Java实现的汇编语言编译器
一个半拉子工程, 用Java实现的汇编语言编译器的介绍. 代码中使用中文命名. An unfinished project, an assembler implemented in Java, with naming in Chinese.
998 0
+关注
sp42
移动项目技术负责人。多年全栈经验,熟悉 Java 和 JS,CSDN 博客技术专家,著有《ExtJS 详解与实践》等书。
文章
问答
文章排行榜
最热
最新
相关电子书
更多
Java开发手册1.4.0
立即下载
Java开发手册1.3.0
立即下载
Java开发手册1.1.0
立即下载