定义
对称加密的定义引用百度百科:
采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。
需要对加密和解密使用相同密钥的加密算法。由于其速度快,对称性加密通常在消息发送方需要加密大量数据时使用。对称性加密也称为密钥加密.
在使用加密算法时,复习下前面提到的java加密常用的类:
keyGenerator:秘钥生成器,也就是根据算法类型随机生成一个秘钥,例如HMAC,所以这个大部分用在非可逆的算法中
SecretKeyFactory:秘密秘钥工厂,言外之意就是需要根据一个秘密(password)去生成一个秘钥,例如DES,PBE,所以大部分使用在对称加密中
KeyPairGenerator:秘钥对生成器,也就是可以生成一对秘钥,也就是公钥和私钥,所以大部分使用在非对称加密中
种类
1.DES(Data Encryption Standard) 数据加密标准
由于DES发明比较早且长度为56位,以目前的计算机运算能力存在被破解的风险,一般这种算法不常用只作为学习加密算法的案例.
code:
/**
* jdk提供的DES算法实现
*/
public static void jdkDES(String content){
try {
//生成密钥生成器
KeyGenerator keyGenerator=KeyGenerator.getInstance("DES");
keyGenerator.init(56);
// 密钥生成器生成key
SecretKey secretKey=keyGenerator.generateKey();
byte[] encoded = secretKey.getEncoded();
// DESKeySpec对象 DESKeySpec(byte[] key)
// key可以使用密钥生成生成的key或者自定义密码password(密码,长度要是8的倍数)
DESKeySpec desKeySpec=new DESKeySpec("12345678".getBytes());
// DESKeySpec desKeySpec=new DESKeySpec(encoded);
SecretKeyFactory secretKeyFactory=SecretKeyFactory.getInstance("DES");
Key key = secretKeyFactory.generateSecret(desKeySpec);
// 加密
// Cipher.getInstance("DES/ECB/PKCS5Padding"); 参数为 算法/工作模式/填充方式
// Cipher cipher=Cipher.getInstance("DES"); //默认的工作模式/填充方式
Cipher cipher=Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypt = cipher.doFinal(content.getBytes());
System.out.println("jdk DES encrypt:"+new BASE64Encoder().encode(encrypt));
// 解密
// 使用同一密钥key
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypt = cipher.doFinal(encrypt);
System.out.println("jdk DES decrypt:"+ new String(decrypt));
} catch (Exception e) {
e.printStackTrace();
}
}
如果要使用BC 第三方提供的DES算法,主要在第一行 加入
Security.addProvider(new BouncyCastleProvider());
//生成密钥生成器
KeyGenerator keyGenerator=KeyGenerator.getInstance("DES","BC");
即可,在此不赘述.
2. 3DES(3重DES,又称DESede)
增加了密钥长度和迭代次数,安全性更高.
code:
/**
* jdk提供的DES算法实现
*/
public static void jdk3DES(String content){
try {
Security.addProvider(new BouncyCastleProvider());
//生成密钥生成器
KeyGenerator keyGenerator=KeyGenerator.getInstance("DESede","BC");//bc 提供
keyGenerator.init(168);//112 or 168
SecretKey secretKey=keyGenerator.generateKey();
byte[] encoded = secretKey.getEncoded();
// DESKeySpec对象 DESKeySpec(byte[] key) key可以使用密钥生成器或者自定义密码password(密码,长度要是8的倍数)
// DESKeySpec desKeySpec=new DESKeySpec("12345678".getBytes());
DESedeKeySpec desKeySpec=new DESedeKeySpec(encoded);
SecretKeyFactory secretKeyFactory=SecretKeyFactory.getInstance("DESede");
Key key = secretKeyFactory.generateSecret(desKeySpec);
// 加密
// Cipher.getInstance("DES/ECB/PKCS5Padding"); 参数为 算法/工作模式/填充方式
// Cipher cipher=Cipher.getInstance("DES"); //默认的工作模式/填充方式
Cipher cipher=Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypt = cipher.doFinal(content.getBytes());
System.out.println("jdk DESede encrypt:"+new BASE64Encoder().encode(encrypt));
// 解密
// 使用同一密钥key
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypt = cipher.doFinal(encrypt);
System.out.println("jdk DESede decrypt:"+ new String(decrypt));
} catch (Exception e) {
e.printStackTrace();
}
}
大致上与DES相同 ,只是密钥长度必须112或者168
3.AES(目前使用比较广泛的对称加密算法)
code:
/**
* JDK 提供的AES 实现
*/
public static void jdkAES(String content){
//创建密钥生成器
try {
KeyGenerator keyGenerator=KeyGenerator.getInstance("AES");
keyGenerator.init(128);
// keyGenerator.init(128,new SecureRandom("123456".getBytes("UTF-8")));//或者加上自定义的密码
//生成器生成key
SecretKey generateKey = keyGenerator.generateKey();
byte[] keyBytes = generateKey.getEncoded();
//根据算法转换相应的Key
Key key=new SecretKeySpec(keyBytes, "AES");
//加密
Cipher cipher=Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypt = cipher.doFinal(content.getBytes());
System.out.println("JDK AES encrypt:"+Hex.encodeHexString(encrypt));
//解密
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypt = cipher.doFinal(encrypt);
System.out.println("JDK AES decrypt:"+new String(decrypt));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
4. PBE(Password Base Encryption,基于口令加密)
4.1 PBE算法(Password Base Encryption,基于口令加密)算法是一种基于口令的加密算法。特点在于口令由用户自己掌握,采用随机数(我们这里叫做 盐)杂凑多重加密等方法保证数据的安全性。
PBE算法没有密钥的概念,把口令当做密钥了。因为密钥长短影响算法安全性,还不方便记忆,这里我们直接换成我们自己常用的口令就大大不同了,便于我们的记忆。但是单纯的口令很容易被字典法给穷举出来,所以我们这里给口令加了点“盐”,这个盐和口令组合,想破解就难了。
4.2 模型分析
这里我们还是假设甲乙双发要传递消息,需要口令和盐还有算法
传统的对称加密算法就是,构建密钥,指定算法,然后发送数据前用密钥加密数据,密钥和加密后的数据一起发送给对方,对方拿着密钥对数据进行解密。
现在是密钥没有了,我们就用“口令+盐”构造出一个密钥,然后对数据进行加密
这里“口令”我们可以随便设置,都可以设置成我们开自己电脑的密码
这里“盐”的设置可以采用随机数,可以是甲乙双方约定的数据
最终我们的口令和盐都要公布给双方
1、消息传递双方约定口令,这里甲方构建口令
2、甲方构建口令后,公布给乙方
3、由口令构建方(甲方)构建本次消息传递使用的盐,其实也可以双方约定一个数据,例如硬盘号,今天的日期等等,不一定非要写个安全算法计算出来,只要双方一致就行
4、甲方使用口令、盐对数据加密
5、甲方将盐、加密数据发送给消息接收者(乙方)
6、乙方用收到的口令、盐(可以是约定的数据)对数据进行解密
图解:
总体看来口令和盐两边都需要知道。消息传递过程还是需要指定双方的统一算法进行。而这些算法其实还是用的那些常见的对称加密算法.
4.3: code:
package com.fitc.soldier.service.common;
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;
import org.apache.commons.codec.binary.Base64;
public class PBEdemo {
/**
* 实例算法
*/
public static final String ALGORITHM="PBEWITHMD5andDES";
/**
* 迭代次数
* */
public static final int ITERATION_COUNT=100;
/**
* 使用PBE算法对数据进行加解密
* @throws Exception
*
*/
public static void main(String[] args) throws Exception {
//待加密数据
String str="这是测试数据!!!";
//设定的口令密码
String password="azsxdc";
System.out.println("原文:\t"+str);
System.out.println("密码:\t"+password);
//初始化盐
byte[] salt=PBEdemo.initSalt();
System.out.println("盐:\t"+Base64.encodeBase64String(salt));
//加密数据
byte[] data=PBEdemo.encrypt(str.getBytes(), password, salt);
System.out.println("加密后:\t"+Base64.encodeBase64String(data));
//解密数据
data=PBEdemo.decrypt(data, password, salt);
System.out.println("解密后:"+new String(data));
}
/**
* 盐初始化
* 盐长度必须为8字节
* @return byte[] 盐
* */
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);
//生成密钥
SecretKey secretKey=keyFactory.generateSecret(keySpec);
return secretKey;
}
/**
* 加密
* @param data 待加密数据
* @param password 密码
* @param salt 盐
* @return byte[] 加密数据
*
* */
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 password 密码
* @param salt 盐
* @return byte[] 解密数据
*
* */
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);
}
}
输出结果: