1 分组加密
首先了解下什么是分组加密:分组密码是将明文消息编码表示后的数字(简称明文数字)序列,划分成长度为n的组(可看成长度为n的矢量),每组分别在密钥的控制下变换成等长的输出数字(简称密文数字)序列。
电码本模式:这种模式是将整个明文分成若干段相同的小段,然后对每一小段进行加密
将明文的各个分组独立的使用相同的密钥进行加密,这种方式加密时各分组的加密独立进行互不干涉,因而可并行进行。同样因为各分组独立加密的缘故,相同的明文分组加密之后具有相同的密文。该模式容易暴露明文分组的统计规律和结构特征。不能防范替换攻击。
优点:
1.简单;
2.有利于并行计算;
3.误差不会被传送;
缺点:
1.不能隐藏明文的模式;
2.可能对明文进行主动攻击;
2 CBC加密模式
密码分组链接模式:这种模式是先将明文切分成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再与密钥进行加密;
优点:
1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
缺点:
1.不利于并行计算;
2.误差传递;
3.需要初始化向量IV
3 编程实现
package com.zhy.concurrency.cyclic;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesEncryption {
// 使用CBC加密需要使用添加一个向量
// 此处不符合安全规范:分组密码算法使用到的IV值,必须不可预测;推荐使用安全的随机数
public static void main(String[] args) {
// TODO Auto-generated method stub
String aes_key = "0123456789abcdef";
// 此处密钥硬编码
String strSrc = "0123456789abcdefadmin";
// 数据明文,敏感信息泄露
System.out.println(strSrc);
String encrypt_code = AesEncrypt_test(strSrc, aes_key);
System.out.println(encrypt_code);
String decrypt_code = AesDncrypt_test(encrypt_code, aes_key);
System.out.println(decrypt_code);
// log打印,敏感信息泄露
}
// 使用CBC的加密算法,要求密钥为16byte
public static String AesEncrypt_test(String content, String aes_key) {
try {
byte[] raw = aes_key.getBytes();
SecretKeySpec secretkey = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecureRandom random = new SecureRandom();
byte ivParameter[] = new byte[16];
random.nextBytes(ivParameter);
System.out.println(parseByte2HexStr(ivParameter));
IvParameterSpec ivparam = new IvParameterSpec(ivParameter);
cipher.init(Cipher.ENCRYPT_MODE, secretkey, ivparam);
byte[] encrypted = cipher.doFinal(content.getBytes());
return parseByte2HexStr(ivParameter) + parseByte2HexStr(encrypted);
//将IV生成的结果附在加密数据前16bytes,每次都使用不同的iv
} catch (InvalidKeyException | NoSuchAlgorithmException
| NoSuchPaddingException | InvalidAlgorithmParameterException
| IllegalBlockSizeException | BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static String AesDncrypt_test(String content, String aes_key) {
try {
byte[] raw = aes_key.getBytes();
SecretKeySpec secretkey = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
String ivParameter = content.substring(0,32);
//取前16byte作为cbc解密的iv向量
System.out.println(ivParameter);
IvParameterSpec ivparam = new IvParameterSpec(
parseHexStr2Byte(ivParameter));
cipher.init(Cipher.DECRYPT_MODE, secretkey, ivparam);
byte[] decrypted = cipher.doFinal(parseHexStr2Byte(content.substring(32)));
return new String(decrypted);
} catch (InvalidKeyException | NoSuchAlgorithmException
| NoSuchPaddingException | InvalidAlgorithmParameterException
| IllegalBlockSizeException | BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* 将2进制转换为16进制
*
* @param hexStr
* @return
*/
private static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**
* 将16进制转换为二进制
*
* @param hexStr
* @return
*/
private static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1)
return null;
byte[] result = new byte[hexStr.length() / 2];
for (int i = 0; i < hexStr.length() / 2; i++) {
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
}