PBE加密算法

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

PBE加密算法
这是我参加全国信息安全⼤赛的设计的加密系统中的⼀个加密算法,虽然⽐赛的结果不是⾮常理想但是,我还是学到了很多东西,现在和⼤家分享⼀下,⽐赛收获的东西。

基于⼝令加密
PBE(Password Based Encryption,基于⼝令加密)算法是⼀种基于⼝令的加密算法,其特点在于⼝令是由⽤户⾃⼰掌握的,采⽤随机数杂凑多重加密等⽅法保证数据的安全性。

PBE算法没有密钥的概念,密钥在其它对称加密算法中是经过算法计算得出来的,PBE算法则是使⽤⼝令替代了密钥。

密钥的长短直接影响了算法的安全性,但不⽅便记忆。

即便是我们将密钥经过Base64编码转换为⼀个可见字符,长密钥⼀样不容易记忆。

因此,在这种情况下密钥是需要存储的,但是⼝令则不然。

⽐如⼀般⼈天天开关电脑,进⼊操作系统的唯⼀途径就是输⼊⼝令。

⼝令是我们便于记忆的⼀种凭证,基于这⼀点,PBE算法使⽤⼝令替代了密钥。

PBE算法并没有真正构建新的加密/解密算法,⽽是对我们已经知道的对称加密算法(如DES算法)做了包装。

使⽤PBE算法对数据做加密/解密操作的时候,其实是使⽤了DES或者是AES等其它对称加密算法做了相应的操作。

既然PBE算法使⽤我们较为常⽤的对称加密算法,那就⽆法回避密钥的问题。

⼝令并不能替代密钥,密钥是经过加密算法计算得来的,但是⼝令本⾝不可能很长看,单纯的⼝令很容易通过穷举攻击⽅式破译,这就引⼊了“盐”。

盐能阻⽌字典攻击或预先计算的攻击,它本⾝是⼀个随机信息,相同的随机信息极不可能使⽤两次。

将盐附加在⼝令上,通过消息摘要算法经过迭代计算获得构建密钥/初始化向量的基本材料,使得破译的难度加⼤。

基于PBE算法的消息传递模型如下图3-13所⽰:甲⼄双⽅作为消息传递双⽅(甲⽅为发送⽅,也就是甲⽅是本系统的服务器,⼄⽅作为接收⽅,也就是本系统客户端的使⽤者),假定甲⼄双⽅在消息传递前已经商定加密算法迭代的次数,与完成⼀次消息传递需要经过如下步骤:
1) 由消息传递双⽅约定⼝令,这⾥由甲⽅构建⼝令。

2) 由⼝令构建者发布⼝令,即本系统的服务器将⼝令发送给系统的客户端使⽤者
3) 由⼝令构建者构建本次消息传递使⽤的盐,这⾥由甲⽅(本系统)构建盐
4) 由消息发送⽅使⽤⼝令、盐对数据加密,这⾥由甲⽅对数据加密
5) 由消息发送者将盐、加密数据放松给消息接收者,这⾥由甲⽅将盐、加密数据发送给⼄⽅
6) 由消息接收⽅使⽤盐、⼝令对加密数据解密,这⾥由⼄⽅完成数据解密
图3-13 基于PBE算法的消息通讯模型
基于PBE算法的消息传递模型理解起来并不是⼗分复杂。

对于上述单项消息传递⽽⾔,如果⼄⽅想要恢复甲⽅消息,甲⽅并不需要重复步骤1、2,仅仅想要由⼄⽅执⾏3、4、5,由甲⽅执⾏步骤6即可。

同时,甲⼄双⽅也可以在消息传递过程中传递迭代次数。

“盐”本⾝就是⼀种可以由消息传递双⽅按⼀定规律约定的消息,⽐如时间。

也可以是某个不可变物理硬件的编号,⽐如U盘的⾃⾝唯⼀标识,⽽本系统则采⽤“⼿机的唯⼀标识”,WIM 是⼀个防篡改硬件,在安全层和应⽤层执⾏安全功能,保存处理⽤户的ID 和权限等功能。

甲⼄双⽅可以通过约定消息传递的时间,这⾥是由本系统直接决定时间,并将其作为基本消息,根据预定的算法(如MD5算法)对其处理,最终获取真正的“盐”,这样⼀来,“盐”就⽆需传递,提⾼了安全性。

假设⼀个场景:由这样的⼀个系统,⽤户使⽤者需要通过⼿机访问⼀个系统,同同时需要输⼊⼝令⽅能登录系统,那么⼿机本⾝就
是“盐”的提供者!即使⼿机丢失,加密的信息也未必能被窃取!即“盐”与⼝令就像两把不可分离的钥匙。

PBE实现⽅案:
Java 6 和Bouncy Castle都提供了PBE系列算法的相关实现,差别在于对各种消息摘要算法和对称加密算法的组合。

常⽤的消息摘要算法包括MD5和SHA算法,常⽤的对称加密算法包括DES、RC2等。

PBE系列算法就死将这些算法进⾏合理组合,其密钥长度均以PBE具体的算法中的对称加密算法为准。

有关PBE算法的Java6 和Bouncy Castle实现细节如下表3-11。

表3-11 PBE算法
总体看来⼝令和盐两边都需要知道。

消息传递过程还是需要指定双⽅的统⼀算法进⾏。

⽽这些算法其实还是⽤的那些常见的对称加密算法
三、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实现
PBE实现代码:
PBECoder.java
package com.wecode.database.secure;
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;
/**
* PBE安全编码组件
*
* @author WeCode ( ydonghao2 )
* @version 1.0
*/
public class PBECoder {
public static final String ALGORUTHM = "PBEWITHMD5andDES";
/**
* 迭代次数
*/
public static final int ITERATION_COUN = 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密钥
* @throws Exception
*
*/
private static Key toKey(String password) throws Exception {
//密钥材料转换
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
//实例化
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORUTHM);
//⽣成密钥
SecretKey secretkey = keyFactory.generateSecret(keySpec);
return secretkey;
}
/**
* 加密
* @param data 数据
* @param password 密钥
* @param salt 盐
* @return byte[] 加密数据
* @throws Exception
*/
public static byte[] encrypt(byte[] data, String password, byte[] salt) throws Exception{
//转换密钥
Key key = toKey(password);
//实例化PBE参考数据
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, ITERATION_COUN);
//实例化
Cipher cipher = Cipher.getInstance(ALGORUTHM);
//初始化
cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);
//执⾏操作
return cipher.doFinal(data);
}
/**
* 解密
* @param data 数据
* @param password 密码
* @param salt 盐
* @return byte[] 解密数据
* @throws Exception
*/
public static byte[] decrypt(byte[] data, String password, byte[] salt) throws Exception{
//转换密钥
Key key = toKey(password);
//实例化PBE参数材料
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, ITERATION_COUN);
//实例化
Cipher cipher = Cipher.getInstance(ALGORUTHM);
//初始化
cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec);
//执⾏操作
return cipher.doFinal(data);
}
}
PBE算法是实现过程中需要关注的环节,包括“盐”的初始化,密钥材料的转化和加密/解密的时间。

在初始化“盐”时,必须使⽤随机的⽅式构造“盐”,最终要得到⼀个8字节的字节数组。

鉴于安全性的要求,这⾥的随机数⽣成器只能使⽤SecureRandom类,如下所⽰:
//实例化安全性随机数
SecureRandomrandom = new SecureRandom();
//产出“盐”
byte[]b = random.generateSeed(8);
字节数组b[]就是我们要的“盐”。

密钥材料转换部分不同于其他对称加密算法,这⾥使⽤的是PBEKeySpec类,如下所⽰:
//密钥材料转换
PBEKeySpeckeySpec = new PBEKeySpec(password.toChatArray());
其他对称加密算法的密钥材料实现类的构造⽅法要求输⼊字节数组形式的变量,⽽PBEKeySpec类构造⽅法则要求输⼊字符数组变量。

为什么不是字符串(String)⽽是字符数组(char[])呢?这是因为字符串是可序列化的封装类,可在程序调⽤时被序列化到⽂件中,⽽字符数组只能以内存变量的形式保留在内存中。

在加密/解密实现时,需要注意使⽤参数材料PBEParameterSpec类,同时注意迭代次数。

构建PBE参数材料后就可以转交给Cipher类完成加密/解密操作,如下所⽰:
//实例化PBE参数材料
PBEParameterSpecparamSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
//实例化
Cipher= cipher = Cipher.getInstance(ALGORITHM);
//初始化
cipher.init(Cipher.DECRYPT_MODE,key, paramSpec);
- KEY_ALGORITHM 指明加密算法,这⾥是PBEWITHMD5andDES加密算法。

- ITERATION_COUN迭代的次数。

+initSalt()PBE加密⽅式的初始化盐返回的是byte[] 盐,盐长度必须为8字节。

+ toKey(Stringpassword) 转换密钥,password是密码,返回Key类型密钥。

+encrypt(byte[]data, String password, byte[] salt) 加密⽅法。

Data是数据,password是密钥,salt是盐,返回byte[]类型,是加密以后的数据。

+decrypt(byte[]data, String password, byte[] salt)解密⽅法,data是数据,password的密码,salt是盐,返回byte[]类型,是解以后的数据。

PBE算法实现和AES算法有很多类似的地⽅,相似的地⽅下⾯代码不具体介绍。

PBE的主要代码如下:
本系统在这⾥采⽤的是PBEWITHMD5andDES算法。

public static final String ALGORUTHM ="PBEWITHMD5andDES";
迭代次数
public static final int ITERATION_COUN = 100;
"盐"初始化
盐长度必须为8字节
返回:
byte[]盐
抛出:
ng.Exception
public static byte[] initSalt() throws Exception {
//实例化安全随机数
SecureRandom random = new SecureRandom();
//产出盐
return random.generateSeed(8);
}
转换密钥
参数:
password-密码
返回:
Key密钥
抛出:
ng.Exception
PBE算法定义并继承了SecretKey接⼝。

private static Key toKey(String password) throws Exception {
//密钥材料转换
PBEKeySpec keySpec = newPBEKeySpec(password.toCharArray());
//实例化
SecretKeyFactory keyFactory =SecretKeyFactory.getInstance(ALGORUTHM);
//⽣成密钥
SecretKey secretkey =keyFactory.generateSecret(keySpec);
return secretkey;
}
加密⽅法
参数:
data- 数据
password- 密钥
salt- 盐
返回:
byte[]加密数据
抛出:
ng.Exception
public static byte[] encrypt(byte[] data, String password, byte[] salt) throws Exception{ //转换密钥
Key key = toKey(password);
//实例化PBE参考数据
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt,ITERATION_COUN);
//实例化
Cipher cipher = Cipher.getInstance(ALGORUTHM);
//初始化
cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);
//执⾏操作
return cipher.doFinal(data);
}
解密⽅法
参数:
data- 数据
password- 密码
salt- 盐
返回:
byte[]解密数据
抛出:
ng.Exception
public static byte[] decrypt(byte[] data, String password,byte[] salt) throws Exception{ //转换密钥
Key key = toKey(password);
//实例化PBE参数材料
PBEParameterSpec parameterSpec = newPBEParameterSpec(salt, ITERATION_COUN);
//实例化
Cipher cipher = Cipher.getInstance(ALGORUTHM);
//初始化
cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec);
//执⾏操作
return cipher.doFinal(data);
}
PBE算法实例验证PBECoder.java:
PBECoderTest.java
package com.wecode.database.secure;
import mons.codec.binary.Base64;
import org.junit.Test;
/**
* PBE 检验
*
* @author WeCode ydonghao2
* @version 1.0
*/
public class PBECoderTest {
/**
* 测试
*
* @throws Exception
*/
/**
* 测试的时候⼈⼯可以引⼊junit.jar包
* @throws Exception
*/
//@Test
public static void main(String[] args) throws Exception {
String inputStr = "PBE";
System.err.println("原⽂:\t" + inputStr);
byte[] input = inputStr.getBytes();
String pwd = "ydonghao";
System.err.println("密码:\t" + pwd);
// 初始化盐
byte[] salt = PBECoder.initSalt();
System.err.println("盐:\t" + Base64.encodeBase64String(salt));
// 加密
byte[] data = PBECoder.encrypt(input, pwd, salt);
System.err.println("加密后\t" + Base64.encodeBase64String(data));
// 解密
byte[] output = PBECoder.decrypt(data, pwd, salt);
String outputStr = new String(output);
System.err.println("解密后\t" + outputStr);
}
}。

相关文档
最新文档