对称加密的定义引用百度百科:java
采用单钥密码系统的加密方法,同一个密钥能够同时用做信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。算法
须要对加密和解密使用相同密钥的加密算法。因为其速度快,对称性加密一般在消息发送方须要加密大量数据时使用。对称性加密也称为密钥加密.apache
在使用加密算法时,复习下前面提到的java加密经常使用的类:安全
keyGenerator:秘钥生成器,也就是根据算法类型随机生成一个秘钥,例如HMAC,因此这个大部分用在非可逆的算法中dom
SecretKeyFactory:秘密秘钥工厂,言外之意就是须要根据一个秘密(password)去生成一个秘钥,例如DES,PBE,因此大部分使用在对称加密中ide
KeyPairGenerator:秘钥对生成器,也就是能够生成一对秘钥,也就是公钥和私钥,因此大部分使用在非对称加密中学习
因为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算法,主要在第一行 加入spa
Security.addProvider(new BouncyCastleProvider());
//生成密钥生成器
KeyGenerator keyGenerator=KeyGenerator.getInstance("DES","BC");
便可,在此不赘述.
增长了密钥长度和迭代次数,安全性更高.
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
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.1 PBE算法(Password Base Encryption,基于口令加密)算法是一种基于口令的加密算法。特色在于口令由用户本身掌握,采用随机数(咱们这里叫作 盐)杂凑多重加密等方法保证数据的安全性。
PBE算法没有密钥的概念,把口令当作密钥了。由于密钥长短影响算法安全性,还不方便记忆,这里咱们直接换成咱们本身经常使用的口令就大大不一样了,便于咱们的记忆。可是单纯的口令很容易被字典法给穷举出来,因此咱们这里给口令加了点“盐”,这个盐和口令组合,想破解就难了。
4.2 模型分析
这里咱们仍是假设甲乙双发要传递消息,须要口令和盐还有算法
传统的对称加密算法就是,构建密钥,指定算法,而后发送数据前用密钥加密数据,密钥和加密后的数据一块儿发送给对方,对方拿着密钥对数据进行解密。
如今是密钥没有了,咱们就用“口令+盐”构造出一个密钥,而后对数据进行加密
这里“口令”咱们能够随便设置,均可以设置成咱们开本身电脑的密码
这里“盐”的设置能够采用随机数,能够是甲乙双方约定的数据
最终咱们的口令和盐都要公布给双方
一、消息传递双方约定口令,这里甲方构建口令
二、甲方构建口令后,公布给乙方
三、由口令构建方(甲方)构建本次消息传递使用的盐,其实也能够双方约定一个数据,例如硬盘号,今天的日期等等,不必定非要写个安全算法计算出来,只要双方一致就行
四、甲方使用口令、盐对数据加密
五、甲方将盐、加密数据发送给消息接收者(乙方)
六、乙方用收到的口令、盐(能够是约定的数据)对数据进行解密
图解:
整体看来口令和盐两边都须要知道。消息传递过程仍是须要指定双方的统一算法进行。而这些算法其实仍是用的那些常见的对称加密算法.
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); } }
输出结果: