博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java中密码加密之PBE算法
阅读量:4287 次
发布时间:2019-05-27

本文共 10194 字,大约阅读时间需要 33 分钟。

一、简述

  PBE算法(Password Base Encryption,基于口令加密)算法是一种基于口令的加密算法。特点在于口令由用户自己掌握,采用随机数(我们这里叫做 盐)杂凑多重加密等方法保证数据的安全性。

  PBE算法没有密钥的概念,把口令当做密钥了。因为密钥长短影响算法安全性,还不方便记忆,这里我们直接换成我们自己常用的口令就大大不同了,便于我们的记忆。但是单纯的口令很容易被字典法给穷举出来,所以我们这里给口令加了点“盐”,这个盐和口令组合,想破解就难了。

同时我们将盐和口令合并后用消息摘要算法进行迭代很多次来构建密钥初始化向量的基本材料,使破译更加难了。

  PBE算法没构建新的加密算法,就是用了我们常用的对称加密算法,例如AES,DES等算法。

 

 

二、模型分析

这里我们还是假设甲乙双发要传递消息,需要口令和盐还有算法

传统的对称加密算法就是,构建密钥,指定算法,然后发送数据前用密钥加密数据,密钥和加密后的数据一起发送给对方,对方拿着密钥对数据进行解密。

 现在是密钥没有了,我们就用“口令+盐”构造出一个密钥,然后对数据进行加密

 这里“口令”我们可以随便设置,都可以设置成我们开自己电脑的密码

 这里“盐”的设置可以采用随机数,可以是甲乙双方约定的数据

 最终我们的口令和盐都要公布给双方

1、消息传递双方约定口令,这里甲方构建口令

2、甲方构建口令后,公布给乙方

3、由口令构建方(甲方)构建本次消息传递使用的盐,其实也可以双方约定一个数据,例如硬盘号,今天的日期等等,不一定非要写个安全算法计算出来,只要双方一致就行

4、甲方使用口令、盐对数据加密

5、甲方将盐、加密数据发送给消息接收者(乙方)

6、乙方用收到的口令、盐(可以是约定的数据)对数据进行解密

 

总体看来口令和盐两边都需要知道。消息传递过程还是需要指定双方的统一算法进行。而这些算法其实还是用的那些常见的对称加密算法

 

三、java6和bouncycastle支持的算法列表

 

算法 密钥长度 密钥长度默认值 工作模式 填充方式 备注
PBEWithMD5AndDES 56 56 CBC PKCS5Padding java6实现
PBEWithMD5AndTripeDES 112、168 168 CBC PKCS6Padding java7实现
PBEWithSHA1AndDESede 112、168 168 CBC PKCS7Padding java8实现
PBEWithSHA1AndRC2_40 40至1024 128 CBC PKCS8Padding java9实现
           
PBEWithMD5AndDES 64 64 CBC PKCS5Padding/PKCS7Padding/ISO10126Padding/ZeroBytePadding BouncyCastle实现
PBEWithMD5AndRC2 128 128 CBC PKCS5Padding/PKCS7Padding/ISO10127Padding/ZeroBytePadding BouncyCastle实现
PBEWithSHA1AndDES 64 64 CBC PKCS5Padding/PKCS7Padding/ISO10128Padding/ZeroBytePadding BouncyCastle实现
PBEWithSHA1AndRC2 128 128 CBC PKCS5Padding/PKCS7Padding/ISO10129Padding/ZeroBytePadding BouncyCastle实现
PBEWithSHAAndIDEA-CBC 128 128 CBC PKCS5Padding/PKCS7Padding/ISO10130Padding/ZeroBytePadding BouncyCastle实现
PBEWithSHAAnd2-KeyTripleDES-CBC 128 128 CBC PKCS5Padding/PKCS7Padding/ISO10131Padding/ZeroBytePadding BouncyCastle实现
PBEWithSHAAnd3-KeyTripleDES-CBC 192 192 CBC PKCS5Padding/PKCS7Padding/ISO10132Padding/ZeroBytePadding BouncyCastle实现
PBEWithSHAAnd128BitRC2-CBC 128 128 CBC PKCS5Padding/PKCS7Padding/ISO10133Padding/ZeroBytePadding BouncyCastle实现
PBEWithSHAAnd40BitRC2-CBC 40 40 CBC PKCS5Padding/PKCS7Padding/ISO10134Padding/ZeroBytePadding BouncyCastle实现
PBEWithSHAAnd128BitRC4 128 128 CBC PKCS5Padding/PKCS7Padding/ISO10135Padding/ZeroBytePadding BouncyCastle实现
PBEWithSHAAnd40BitRC4 40 40 CBC PKCS5Padding/PKCS7Padding/ISO10136Padding/ZeroBytePadding BouncyCastle实现
PBEWithSHAAndTwofish-CBC 256 256 CBC PKCS5Padding/PKCS7Padding/ISO10137Padding/ZeroBytePadding BouncyCastle实现

四、程序展示

[java] 
  1. package com.ca.test;  
  2. import java.security.Key;  
  3. import java.security.SecureRandom;  
  4. import javax.crypto.Cipher;  
  5. import javax.crypto.SecretKey;  
  6. import javax.crypto.SecretKeyFactory;  
  7. import javax.crypto.spec.PBEKeySpec;  
  8. import javax.crypto.spec.PBEParameterSpec;  
  9. import org.apache.commons.codec.binary.Base64;  
  10. /** 
  11.  * 对称加密算法:基于口令加密-PBE算法实现 
  12.  * 使用java6提供的PBEWITHMD5andDES算法进行展示 
  13.  * @author kongqz 
  14.  * */  
  15. public class PBECoder {  
  16.       
  17.     /** 
  18.      * JAVA6支持以下任意一种算法 
  19.      * PBEWITHMD5ANDDES 
  20.      * PBEWITHMD5ANDTRIPLEDES 
  21.      * PBEWITHSHAANDDESEDE 
  22.      * PBEWITHSHA1ANDRC2_40 
  23.      * PBKDF2WITHHMACSHA1 
  24.      * */  
  25.     public static final String ALGORITHM="PBEWITHMD5andDES";  
  26.       
  27.     /** 
  28.      * 迭代次数 
  29.      * */  
  30.     public static final int ITERATION_COUNT=100;  
  31.       
  32.     /** 
  33.      * 盐初始化 
  34.      * 盐长度必须为8字节 
  35.      * @return byte[] 盐 
  36.      * */  
  37.     public static byte[] initSalt() throws Exception{  
  38.         //实例化安全随机数  
  39.         SecureRandom random=new SecureRandom();  
  40.         //产出盐  
  41.         return random.generateSeed(8);  
  42.     }  
  43.       
  44.     /** 
  45.      * 转换密钥 
  46.      * @param password 密码 
  47.      * @return Key 密钥 
  48.      * */  
  49.     private static Key toKey(String password) throws Exception{  
  50.         //密钥彩礼转换  
  51.         PBEKeySpec keySpec=new PBEKeySpec(password.toCharArray());  
  52.         //实例化  
  53.         SecretKeyFactory keyFactory=SecretKeyFactory.getInstance(ALGORITHM);  
  54.         //生成密钥  
  55.         SecretKey secretKey=keyFactory.generateSecret(keySpec);  
  56.           
  57.         return secretKey;  
  58.     }  
  59.     /** 
  60.      * 加密 
  61.      * @param data 待加密数据 
  62.      * @param password 密码 
  63.      * @param salt 盐 
  64.      * @return byte[] 加密数据 
  65.      *  
  66.      * */  
  67.     public static byte[] encrypt(byte[] data,String password,byte[] salt) throws Exception{  
  68.         //转换密钥  
  69.         Key key=toKey(password);  
  70.         //实例化PBE参数材料  
  71.         PBEParameterSpec paramSpec=new PBEParameterSpec(salt,ITERATION_COUNT);  
  72.         //实例化  
  73.         Cipher cipher=Cipher.getInstance(ALGORITHM);  
  74.         //初始化  
  75.         cipher.init(Cipher.ENCRYPT_MODE, key,paramSpec);  
  76.         //执行操作  
  77.         return cipher.doFinal(data);  
  78.     }  
  79.     /** 
  80.      * 解密 
  81.      * @param data 待解密数据 
  82.      * @param password 密码 
  83.      * @param salt 盐 
  84.      * @return byte[] 解密数据 
  85.      *  
  86.      * */  
  87.     public static byte[] decrypt(byte[] data,String password,byte[] salt) throws Exception{  
  88.         //转换密钥  
  89.         Key key=toKey(password);  
  90.         //实例化PBE参数材料  
  91.         PBEParameterSpec paramSpec=new PBEParameterSpec(salt,ITERATION_COUNT);  
  92.         //实例化  
  93.         Cipher cipher=Cipher.getInstance(ALGORITHM);  
  94.         //初始化  
  95.         cipher.init(Cipher.DECRYPT_MODE, key,paramSpec);  
  96.         //执行操作  
  97.         return cipher.doFinal(data);  
  98.     }  
  99.     /** 
  100.      * 使用PBE算法对数据进行加解密 
  101.      * @throws Exception  
  102.      *  
  103.      */  
  104.     public static void main(String[] args) throws Exception {  
  105.         //待加密数据  
  106.         String str="PBE";  
  107.         //设定的口令密码  
  108.         String password="azsxdc";  
  109.           
  110.         System.out.println("原文:/t"+str);  
  111.         System.out.println("密码:/t"+password);  
  112.           
  113.         //初始化盐  
  114.         byte[] salt=PBECoder.initSalt();  
  115.         System.out.println("盐:/t"+Base64.encodeBase64String(salt));  
  116.         //加密数据  
  117.         byte[] data=PBECoder.encrypt(str.getBytes(), password, salt);  
  118.         System.out.println("加密后:/t"+Base64.encodeBase64String(data));  
  119.         //解密数据  
  120.         data=PBECoder.decrypt(data, password, salt);  
  121.         System.out.println("解密后:"+new String(data));  
  122.     }  
  123. }  
  124. 控制台结果输出:  
  125. 原文: PBE  
  126. 密码: azsxdc  
  127. 盐:  VeEQqRzOw2Y=  
  128. 加密后:    7bQTon5WD04=  
  129. 解密后:PBE  

五、总结

 

PBE不是一个新构建的算法,就是将密钥的概念转成 “口令+盐” 的方式,将不便于记忆的密钥转成便于记忆的口令

算法还是用的基本的对称加密算法,从上边的支持表中就能看到。

 

这个是不是和我们到银行开的U盾有些像呢?

就拿民生银行的U盾来说,我们插上U盾,还需要我们去输入口令。然后才能到网上银行去登陆操作,付款的时候还是需要我们去输入口令。

1、U盾的盐从何来?:应该是那个闪盘的序列编号经过一定的处理得出的一个值,因为我们想要U盾生效,在民生的大厅中需要找一个机器激活的。那个激活的动作应该是将我们U盾这个闪盘中的数据写入到我们个人的账户中,相当于做了一次盐的公布

2、口令何来?:就是我们设定的登陆密码呀。这个在窗口办理的时候需要我们设定U盾的密码。并且我们在激活的时候可以改我们的密码

 

有了上边两个,我们再进行操作,就可以进行我们的身份发送数据的安全性了。网银的数据交换真的安全了...

----例如:项目中真正使用的Util

    

package org.jeecgframework.core.util;import java.security.Key;import java.security.SecureRandom;import javax.crypto.Cipher;import javax.crypto.SecretKey;import javax.crypto.SecretKeyFactory;import javax.crypto.spec.PBEKeySpec;import javax.crypto.spec.PBEParameterSpec;public class PasswordUtil {	/**	 * JAVA6支持以下任意一种算法 PBEWITHMD5ANDDES PBEWITHMD5ANDTRIPLEDES	 * PBEWITHSHAANDDESEDE PBEWITHSHA1ANDRC2_40 PBKDF2WITHHMACSHA1	 * */	/**	 * 定义使用的算法为:PBEWITHMD5andDES算法	 */	public static final String ALGORITHM = "PBEWithMD5AndDES";//加密算法	public static final String Salt = "63293188";//密钥	/**	 * 定义迭代次数为1000次	 */	private static final int ITERATIONCOUNT = 1000;	/**	 * 获取加密算法中使用的盐值,解密中使用的盐值必须与加密中使用的相同才能完成操作. 盐长度必须为8字节	 * 	 * @return byte[] 盐值	 * */	public static byte[] getSalt() throws Exception {		// 实例化安全随机数		SecureRandom random = new SecureRandom();		// 产出盐		return random.generateSeed(8);	}	public static byte[] getStaticSalt() {		// 产出盐		return Salt.getBytes();	}	/**	 * 根据PBE密码生成一把密钥	 * 	 * @param password	 *            生成密钥时所使用的密码	 * @return Key PBE算法密钥	 * */	private static Key getPBEKey(String password) {		// 实例化使用的算法		SecretKeyFactory keyFactory;		SecretKey secretKey = null;		try {			keyFactory = SecretKeyFactory.getInstance(ALGORITHM);			// 设置PBE密钥参数			PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());			// 生成密钥			secretKey = keyFactory.generateSecret(keySpec);		} catch (Exception e) {			// TODO Auto-generated catch block			e.printStackTrace();		}		return secretKey;	}	/**	 * 加密明文字符串	 * 	 * @param plaintext	 *            待加密的明文字符串	 * @param password	 *            生成密钥时所使用的密码	 * @param salt	 *            盐值	 * @return 加密后的密文字符串	 * @throws Exception	 */	public static String encrypt(String plaintext, String password, byte[] salt) {		Key key = getPBEKey(password);		byte[] encipheredData = null;		PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, ITERATIONCOUNT);		try {			Cipher cipher = Cipher.getInstance(ALGORITHM);			cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);			encipheredData = cipher.doFinal(plaintext.getBytes());		} catch (Exception e) {		}		return bytesToHexString(encipheredData);	}	/**	 * 解密密文字符串	 * 	 * @param ciphertext	 *            待解密的密文字符串	 * @param password	 *            生成密钥时所使用的密码(如需解密,该参数需要与加密时使用的一致)	 * @param salt	 *            盐值(如需解密,该参数需要与加密时使用的一致)	 * @return 解密后的明文字符串	 * @throws Exception	 */	public static String decrypt(String ciphertext, String password, byte[] salt) {		Key key = getPBEKey(password);		byte[] passDec = null;		PBEParameterSpec parameterSpec = new PBEParameterSpec(getStaticSalt(), ITERATIONCOUNT);		try {			Cipher cipher = Cipher.getInstance(ALGORITHM);			cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec);			passDec = cipher.doFinal(hexStringToBytes(ciphertext));		}		catch (Exception e) {			// TODO: handle exception		}		return new String(passDec);	}	/**	 * 将字节数组转换为十六进制字符串	 * 	 * @param src	 *            字节数组	 * @return	 */	public static String bytesToHexString(byte[] src) {		StringBuilder stringBuilder = new StringBuilder("");		if (src == null || src.length <= 0) {			return null;		}		for (int i = 0; i < src.length; i++) {			int v = src[i] & 0xFF;			String hv = Integer.toHexString(v);			if (hv.length() < 2) {				stringBuilder.append(0);			}			stringBuilder.append(hv);		}		return stringBuilder.toString();	}	/**	 * 将十六进制字符串转换为字节数组	 * 	 * @param hexString	 *            十六进制字符串	 * @return	 */	public static byte[] hexStringToBytes(String hexString) {		if (hexString == null || hexString.equals("")) {			return null;		}		hexString = hexString.toUpperCase();		int length = hexString.length() / 2;		char[] hexChars = hexString.toCharArray();		byte[] d = new byte[length];		for (int i = 0; i < length; i++) {			int pos = i * 2;			d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));		}		return d;	}	private static byte charToByte(char c) {		return (byte) "0123456789ABCDEF".indexOf(c);	}	public static void main(String[] args) {		int i=10;		for (int j = 0; j < i; j++) {			if((j)%3==0){				System.out.print("
"); }else { System.out.print(j); } } System.out.print(-1%2==0); String str = "admin"; String password = "123456"; org.jeecgframework.core.util.LogUtil.info("明文:" + str); org.jeecgframework.core.util.LogUtil.info("密码:" + password); try { byte[] salt = PasswordUtil.getStaticSalt(); //加密 String ciphertext = PasswordUtil.encrypt(str, password, salt); org.jeecgframework.core.util.LogUtil.info("密文:" + ciphertext); //解密 String plaintext = PasswordUtil.decrypt(ciphertext, password, salt); org.jeecgframework.core.util.LogUtil.info("明文:" + plaintext); } catch (Exception e) { e.printStackTrace(); } }}

转载地址:http://tdagi.baihongyu.com/

你可能感兴趣的文章
【主题世界】阿狸对着你卖萌桌面主题
查看>>
【加密桌面便签】V1.1正式版简体中文
查看>>
【Windows7系统装什么浏览器好用】
查看>>
看图纸V3.2.1正式版[看图纸正式版下载]
查看>>
【图文解决win7系统C盘空间不够用】
查看>>
【win7系统怎样进去登陆界面】
查看>>
【win7无法识别u盘的解决办法】
查看>>
【布谷鸟来客提醒V4.0 官方版】淘宝店铺监控软件
查看>>
【教你修复win7下IE8主页被篡改的方法】
查看>>
【维护和保养电脑主机需12点注意】
查看>>
【幸福小助手V3.1绿色版】生活提醒软件
查看>>
【C#如何判断字符串是否为空串】
查看>>
【Linux编译安装httpsqs】
查看>>
【用C#实现启动另一程序的方法】
查看>>
【Android读写文件方法汇总】
查看>>
网线接法大全(RJ45型网线插头)
查看>>
【WinXP自我修复故障功能详解】
查看>>
【23招实用技巧让XP运行更快捷更可靠】
查看>>
【Wn8中如何关闭或开启自动播放功能】
查看>>
【Win7上装双系统完美体验Windows8】
查看>>