Java 对称加密

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 最近在做一个用户 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));
	}
}


目录
相关文章
|
2月前
|
Java Maven 数据安全/隐私保护
如何实现Java打包程序的加密代码混淆,避免被反编译?
【10月更文挑战第15天】如何实现Java打包程序的加密代码混淆,避免被反编译?
67 2
|
2月前
|
安全 算法 Java
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
本文提供了在数据库中对密码等敏感信息进行加盐加密的详细教程,包括手写MD5加密算法和使用Spring Security的BCryptPasswordEncoder进行加密,并强调了使用BCryptPasswordEncoder时需要注意的Spring Security配置问题。
155 0
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
|
4月前
|
存储 算法 Java
在Java中使用MD5对用户输入密码进行加密存储、同时登录验证。
这篇文章详细介绍了在Java项目中如何使用MD5算法对用户密码进行加密存储和登录验证,包括加入依赖、编写MD5工具类、注册时的密码加密和登录时的密码验证等步骤,并通过示例代码和数据库存储信息展示了测试效果。
在Java中使用MD5对用户输入密码进行加密存储、同时登录验证。
|
3月前
|
安全 Java 数据安全/隐私保护
- 代码加密混淆工具-Java 编程安全性
在Java编程领域,保护代码安全与知识产权至关重要。本文探讨了代码加密混淆工具的重要性,并介绍了五款流行工具:ProGuard、DexGuard、Jscrambler、DashO 和 Ipa Guard。这些工具通过压缩、优化、混淆和加密等手段,提升代码安全性,保护知识产权。ProGuard 是开源工具,用于压缩和混淆Java代码;DexGuard 专为Android应用程序设计,提供强大加密功能;Jscrambler 基于云,保护Web和移动应用的JavaScript及HTML5代码;DashO 支持多种Java平台和
231 1
|
4月前
|
安全 Java 应用服务中间件
网络安全的护城河:漏洞防御与加密技术深入浅出Java并发编程
【8月更文挑战第31天】在数字世界的棋盘上,每一次点击都可能是一步棋。网络安全的战场无声却激烈,漏洞如同裂缝中的风,悄无声息地侵袭着数据的堡垒。本文将揭示网络漏洞的隐蔽角落,探讨如何通过加密技术筑起防线,同时提升个人和组织的安全意识,共同守护我们的数字家园。
|
4月前
|
安全 算法 Java
java系列之~~网络通信安全 非对称加密算法的介绍说明
这篇文章介绍了非对称加密算法,包括其定义、加密解密过程、数字签名功能,以及与对称加密算法的比较,并解释了非对称加密在网络安全中的应用,特别是在公钥基础设施和信任网络中的重要性。
|
4月前
|
Java C# 数据安全/隐私保护
如何 使 Java、C# md5 加密的值保持一致
如何 使 Java、C# md5 加密的值保持一致
54 0
|
算法 Java 数据安全/隐私保护
【Java小工匠聊密码学】--对称加密--DES
1、 DES算法   DES对称加密,对称加密,是一种比较传统的加密方式,其加密运算、解密运算使用的是同样的密钥,信息的发送者和信息的接收者在进行信息的传输与处理时,必须共同持有该密码(称为对称密码),是一对称加密算法。
1473 0
|
13天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
4天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####