`
aubdiy
  • 浏览: 693046 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java 加密解密之对称加密算法PBE

    博客分类:
  • Java
阅读更多

 

Java 加密解密基础

 

Java byte数组与十六进制字符串互转

 

Java BASE64加密解密

 

Java 加密解密之消息摘要算法(MD5 SHA MAC)

 

Java 加密解密之对称加密算法DES

 

Java 加密解密之对称加密算法DESede

 

Java 加密解密之对称加密算法AES

 

Java 加密解密之对称加密算法PBE

 

 

Java 加密解密之对称加密算法PBE

PBE是一种基于口令的加密算法,使用口令代替其他对称加密算法中的密钥,其特点在于口令由用户自己掌管,不借助任何物理媒体;采用随机数(这里我们叫做盐)杂凑多重加密等方法保证数据的安全性。

PBE算法是对称加密算法的综合算法,常见算法PBEWithMD5AndDES,使用MD5和DES算法构建了PBE算法。将盐附加在口令上,通过消息摘要算法经过迭代获得构建密钥的基本材料,构建密钥后使用对称加密算法进行加密解密。

 

JDK对DESede算法的支持

 

算法/密钥长度/默认密钥长度:

1.PBEWithMD5AndDES/56/56
2.PBEWithMD5AndTripleDES/112,168/168
3.PBEWithSHA1AndDESede/112,168/168
4.PBEWithSHA1AndRC2_40/40 to 1024/128

工作模式:CBC
填充方式:PKCS5Padding

 

 

工作模式和填充方式请参考:      JAVA加密解密基础

十六进制工具类Hex.java,见:   java byte数组与十六进制字符串互转

PBE加密解密的java实现:
PBECoder.java

import java.security.Key;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

/**
 * PBE Coder<br/>
 * Algorithm/secret key length/default secret key length/<br/>
 * 1.PBEWithMD5AndDES/56/56
 * 2.PBEWithMD5AndTripleDES/112,168/168
 * 3.PBEWithSHA1AndDESede/112,168/168
 * 4.PBEWithSHA1AndRC2_40/40 to 1024/128
 * mode:	CBC <br/>
 * padding:	PKCS5Padding
 * @author Aub
 * 
 */
public class PBECoder {

	public static final String ALGORITHM = "PBEWITHMD5andDES";
	
	public static final int ITERATION_COUNT = 100;
	
	/**
	 * 初始盐<br/>
	 * 盐的长度必须为8位
	 * @return byte[] 盐 
	 * @throws Exception
	 */
	public static byte[] initSalt() throws Exception{
		//实例化安全随机数
		SecureRandom random = new SecureRandom();
		//产出盐
		return random.generateSeed(8);
	}
	
	/**
	 * 转换密钥
	 * 
	 * @param password	密码
	 * @return Key 密钥
	 */
	private static Key toKey(String password) throws Exception{
		//密钥材料
		PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
		//实例化
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
		//生成密钥
		return keyFactory.generateSecret(keySpec);
	}
	
	/**
	 * 加密
	 * 
	 * @param data	待加密数据
	 * @param key	密钥
	 * @param salt  盐
	 * @return byte[]	加密数据
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data,String password,byte[] salt) throws Exception{
		//转换密钥
		Key key = toKey(password);
		//实例化PBE参数材料
		PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
		//实例化
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		//初始化
		cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
		//执行操作
		return cipher.doFinal(data);
	}
	
	/**
	 * 解密
	 * 
	 * @param data	待机密数据
	 * @param key	密钥
	 * @param salt  盐
	 * @return byte[]	解密数据
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] data,String password,byte[] salt)throws Exception{
		//转换密钥
		Key key = toKey(password);
		//实例化PBE参数材料
		PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
		//实例化
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		//初始化
		cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
		//执行操作
		return cipher.doFinal(data);
	}
	
	private static String  showByteArray(byte[] data){
		if(null == data){
			return null;
		}
		StringBuilder sb = new StringBuilder("{");
		for(byte b:data){
			sb.append(b).append(",");
		}
		sb.deleteCharAt(sb.length()-1);
		sb.append("}");
		return sb.toString();
	}
	
	public static void main(String[] args) throws Exception {
		byte[] salt = initSalt();
		System.out.println("salt:"+showByteArray(salt));
		//这里的password需要是ASCII码,不然会报异常
		String password = "1111";
		System.out.println("口令:"+password);
		
		String data ="PBE数据";
		System.out.println("加密前数据: string:"+data);
		System.out.println("加密前数据: byte[]:"+showByteArray(data.getBytes()));
		System.out.println();
		byte[] encryptData = encrypt(data.getBytes(), password,salt);
		System.out.println("加密后数据: byte[]:"+showByteArray(encryptData));
		System.out.println("加密后数据: hexStr:"+Hex.encodeHexStr(encryptData));
		System.out.println();
		byte[] decryptData = decrypt(encryptData, password,salt);
		System.out.println("解密后数据: byte[]:"+showByteArray(decryptData));
		System.out.println("解密后数据: string:"+new String(decryptData));
		
	}
}

 参考《java加密与解密的艺术》

分享到:
评论
7 楼 aubdiy 2015-09-21  
huangningren 写道
用户密码只需要md5后就可以存入数据库了吧

如果对安全要求不高,这样做是可以的,
md5已经可以破解,可以采用加盐、多种算法多次加密等方式 提升安全性
6 楼 huangningren 2015-09-09  
用户密码只需要md5后就可以存入数据库了吧
5 楼 aubdiy 2015-03-19  
lqixv 写道
我直接运行这个程序,发现加密时间长达 300 - 500 毫秒!
解密时间大约是 1 - 5 毫秒。
加密时间太长了


System.out.println打印是比较慢的, 去掉控制台打印代码,进行测试试试
4 楼 aubdiy 2015-03-19  
lqixv 写道
我直接运行这个程序,发现加密时间长达 300 - 500 毫秒!
解密时间大约是 1 - 5 毫秒。
加密时间太长了


你好 我测试了一下,加密是慢了些,不过基本上在十几毫秒左右,如果机器好的话更快
将main方法中内容修改如下:再试试
		
public static void main(String[] args) throws Exception {
		byte[] key = initSecretKey();
		System.out.println("key:"+ showByteArray(key));
		
		String data ="DES数据";
		long t1 = System.currentTimeMillis();
		Key k = toKey(key);
		byte[] encryptData = encrypt(data.getBytes(), k);
		long t2 = System.currentTimeMillis();
		decrypt(encryptData, k);
		long t3 = System.currentTimeMillis();
		System.out.println(t2 - t1);
		System.out.println(t3 - t2);
	}
3 楼 lqixv 2015-03-18  
我直接运行这个程序,发现加密时间长达 300 - 500 毫秒!
解密时间大约是 1 - 5 毫秒。
加密时间太长了
2 楼 aubdiy 2012-01-17  
kadan_james 写道
我在测试PBEWithMD5AndDES这种算法时,发现密钥长度超过8个字节(64位,有效位56位)时任然可以加密,而且不存在超过8字节的部分截取的问题,请问能否说下有关密钥长度问题?



现在我在火车上呢,等我到家测一下。 
1 楼 kadan_james 2012-01-13  
我在测试PBEWithMD5AndDES这种算法时,发现密钥长度超过8个字节(64位,有效位56位)时任然可以加密,而且不存在超过8字节的部分截取的问题,请问能否说下有关密钥长度问题?

相关推荐

Global site tag (gtag.js) - Google Analytics