12.2.3 安全升级2—加密数据
想要真正加强数据的机密性,对称加密算法是我们的首选。在实际应用中,类似于这样的网络交互系统几乎都采用了对称加密算法对数据进行加密。这些系统通常用于传递聊天消息,甚至是传递对账数据。
本文将使用AES算法对UDPChat交互数据进行加密/解密。
1.增强安全性
我们继续对Security类进行修改,使用AES算法对数据加密。
首先,我们需要构建密钥,如代码清单12-23所示。
代码清单12-23 生成密钥1
/**
*生成密钥
*@return byte[]二进制密钥
*@throws Exception
*/
public static byte[]initKey()throws Exception{
//实例化
KeyGenerator kg=KeyGenerator.getInstance(ALGORITHM);
kg.init(256);
//生成秘密密钥
SecretKey secretKey=kg.generateKey();
//获得密钥的二进制编码形式
return secretKey.getEncoded();
}
这里,我们使用Commons Codec的十六进制编码类Hex将二进制密钥转换为十六进制字符串,使其可见,改进后的密钥生成方法如代码清单12-24所示。
代码清单12-24 生成密钥2
/**
*生成密钥
*@return String十六进制字符串密钥
*@throws Exception
*/
public static String initKeyHex()throws Exception{
return Hex.encodeHexString(initKey());
}
我们将获得密钥(1486c5dc751a54ce3a58701ba537ecc8e257bf66127837e9401acdaceb6023f8),并将该密钥绑定在变量Key中。
反之,我们将十六进制密钥转换获得最终的秘密密钥,如代码清单12-25所示。
代码清单12-25 转换密钥
//省略
/**
*密钥
*/
private static final String KEY="1486c5dc751a54ce3a58701ba
537ecc8e257bf66127837e9401acdaceb6023f8";
//省略
/**
*转换密钥
*@throws Exception
*/
private static Key getKey()throws Exception{
byte[]key=Hex.decodeHex(KEY.toCharArray());
//实例化AES密钥材料
SecretKey secretKey=new SecretKeySpec(key, ALGORITHM);
return secretKey;
}
在不改变原Security类方法的前提下,我们仍使用encrypt()方法对数据加密,使用decrypt()方法对数据解密。
修改后的加密方法实现如代码清单12-26所示。
代码清单12-26 加密方法1
/**
*加密
*@param data待加密数据
*@return byte[]加密数据
*@throws Exception
*/
public static byte[]encrypt(byte[]data){
try{
//实例化
Cipher cipher=Cipher.getInstance(ALGORITHM);
//初始化,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, getKey());
//执行操作
return cipher.doFinal(data);
}catch(Exception e){
return data;
}
}
修改后的解密方法实现如代码清单12-27所示。
代码清单12-27 解密方法1
/**
*解密
*@param data待解密数据
*@return byte[]解密数据
*@throws Exception
*/
public static byte[]decrypt(byte[]data){
try{
//实例化
Cipher cipher=Cipher.getInstance(ALGORITHM);
//初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, getKey());
//执行操作
return cipher.doFinal(data);
}catch(Exception e){
return data;
}
}
完整实现如代码清单12-28所示。
代码清单12-28 Security类2
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
/**
*安全组件
*@author梁栋
*@since 1.0
*/
public abstract class Security{
//密钥算法
public static final String ALGORITHM="AES";
//密钥
private static final String KEY=
"1486c5dc751a54ce3a58701ba537ecc8e257bf66127837e9401acdaceb6023f8";
/**
*转换密钥
*@throws Exception
*/
private static Key getKey()throws Exception{
byte[]key=Hex.decodeHex(KEY.toCharArray());
//实例化AES密钥材料
SecretKey secretKey=new SecretKeySpec(key, ALGORITHM);
return secretKey;
}
/**
*解密
*@param data待解密数据
*@return byte[]解密数据
*@throws Exception
*/
public static byte[]decrypt(byte[]data){
try{
//实例化
Cipher cipher=Cipher.getInstance(ALGORITHM);
//初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, getKey());
//执行操作
return cipher.doFinal(data);
}catch(Exception e){
return data;
}
}
/**
*加密
*@param data待加密数据
*@return byte[]加密数据
*@throws Exception
*/
public static byte[]encrypt(byte[]data){
try{
//实例化
Cipher cipher=Cipher.getInstance(ALGORITHM);
//初始化,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, getKey());
//执行操作
return cipher.doFinal(data);
}catch(Exception e){
return data;
}
}
/**
*生成密钥
*@return byte[]二进制密钥
*@throws Exception
*/
public static byte[]initKey()throws Exception{
//实例化
KeyGenerator kg=KeyGenerator.getInstance(ALGORITHM);
kg.init(256);
//生成秘密密钥
SecretKey secretKey=kg.generateKey();
//获得密钥的二进制编码形式
return secretKey.getEncoded();
}
/**
*生成密钥
*@return String十六进制字符串密钥
*@throws Exception
*/
public static String initKeyHex()throws Exception{
return Hex.encodeHexString(initKey());
}
}
2.网络监测
有了加密算法的庇护,我们可以高枕无忧了,即便是将我们的银行卡号发送给对方,也不必担心,如图12-16所示。
图 12-16 UDP聊天窗口AES算法加密
截获此次交互的数据包,如图12-17所示。
图 12-17 UDP交互内容AES算法加密
如果没有密钥,我们将无法在有效的时间内破译加密内容,也就失去了破译的意义。
如果需要对交互的数据进行验证,我们可以使用消息摘要算法对消息内容做摘要处理,并对解密后的数据做摘要验证。相关内容请读者参考第6章自行实现。