编写支持加密属性文件的实现类
通过以上分析,我们设计一个支持加密属性文件的增强型PropertyPlaceholderConfigurer,其代码如所示:
代码清单 2
对locations指定的属性文件流数据进行额外的解密工作,解密后再装载到props中。比起PropertyPlaceholderConfigurer,我们只做了额外的一件事:装载前对属性资源进行解密。
在代码清单 2的③和④处,我们使用了一个DES解密的工具类对加密的属性文件流进行解密。
对文件进行对称加密的算法很多,一般使用DES对称加密算法,因为它速度很快,破解困难,DESEncryptUtil不但提供了DES解密功能,还提供了DES加密的功能,因为属性文件在部署前必须经常加密:
代码清单 3 加密解密工具类
解密工作主要涉及到两个类Cipher和Key,前者是加密器,可以通过init()方法设置工作模式和密钥,在这里,我们设置为解密工作模式:Cipher.DECRYPT_MODE。Cipher通过doFinal()方法对字节数组进行加密或解密。
通过以上分析,我们设计一个支持加密属性文件的增强型PropertyPlaceholderConfigurer,其代码如所示:
代码清单 2
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.security.Key;
- import java.util.Properties;
- import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
- import org.springframework.core.io.Resource;
- import org.springframework.util.DefaultPropertiesPersister;
- import org.springframework.util.PropertiesPersister;
- public class DecryptPropertyPlaceholderConfigurer
- extends PropertyPlaceholderConfigurer ...{
- private Resource[] locations; //① 重新定义父类中的这个同名属性
- private Resource keyLocation; //② 用于指定密钥文件
- public void setKeyLocation(Resource keyLocation) ...{
- this.keyLocation = keyLocation;
- }
- public void setLocations(Resource[] locations) ...{
- this.locations = locations;
- }
- public void loadProperties(Properties props) throws IOException ...{
- if (this.locations != null) ...{
- PropertiesPersister propertiesPersister = new DefaultPropertiesPersister();
- for (int i = 0; i < this.locations.length; i++) ...{
- Resource location = this.locations[i];
- if (logger.isInfoEnabled()) ...{
- logger.info("Loading properties file from " + location);
- }
- InputStream is = null;
- try ...{
- is = location.getInputStream();
- //③ 加载密钥
- Key key = DESEncryptUtil.getKey(keyLocation.getInputStream());
- //④ 对属性文件进行解密
- is = DESEncryptUtil.doDecrypt(key, is);
- //⑤ 将解密后的属性流装载到props中
- if(fileEncoding != null)...{
- propertiesPersister.load(props,
- new InputStreamReader(is,fileEncoding));
- }else...{
- propertiesPersister.load(props ,is);
- }
- } finally ...{
- if (is != null)
- is.close();
- }
- }
- }
- }
- }
- }
在代码清单 2的③和④处,我们使用了一个DES解密的工具类对加密的属性文件流进行解密。
对文件进行对称加密的算法很多,一般使用DES对称加密算法,因为它速度很快,破解困难,DESEncryptUtil不但提供了DES解密功能,还提供了DES加密的功能,因为属性文件在部署前必须经常加密:
代码清单 3 加密解密工具类
- public class DESEncryptUtil ...{
- public static Key createKey() throws NoSuchAlgorithmException {//创建一个密钥
- Security.insertProviderAt(new com.sun.crypto.provider.SunJCE(), 1);
- KeyGenerator generator = KeyGenerator.getInstance("DES");
- generator.init(new SecureRandom());
- Key key = generator.generateKey();
- return key;
- }
- public static Key getKey(InputStream is) {
- try ...{
- ObjectInputStream ois = new ObjectInputStream(is);
- return (Key) ois.readObject();
- } catch (Exception e) ...{
- e.printStackTrace();
- throw new RuntimeException(e);
- }
- }
- private static byte[] doEncrypt(Key key, byte[] data) {//对数据进行加密
- try {
- Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
- cipher.init(Cipher.ENCRYPT_MODE, key);
- byte[] raw = cipher.doFinal(data);
- return raw;
- } catch (Exception e) {
- e.printStackTrace();
- throw new RuntimeException(e);
- }
- }
- public static InputStream doDecrypt(Key key, InputStream in) {//对数据进行解密
- try {
- Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
- cipher.init(Cipher.DECRYPT_MODE, key);
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- byte[] tmpbuf = new byte[1024];
- int count = 0;
- while ((count = in.read(tmpbuf)) != -1) {
- bout.write(tmpbuf, 0, count);
- tmpbuf = new byte[1024];
- }
- in.close();
- byte[] orgData = bout.toByteArray();
- byte[] raw = cipher.doFinal(orgData);
- ByteArrayInputStream bin = new ByteArrayInputStream(raw);
- return bin;
- } catch (Exception e) {
- e.printStackTrace();
- throw new RuntimeException(e);
- }
- }
- public static void main(String[] args) throws Exception {//提供了Java命令使用该工具的功能
- if (args.length == 2 && args[0].equals("key")) {// 生成密钥文件
- Key key = DESEncryptUtil.createKey();
- ObjectOutputStream oos = new ObjectOutputStream(
- new FileOutputStream(args[1]));
- oos.writeObject(key);
- oos.close();
- System.out.println("成功生成密钥文件。");
- } else if (args.length == 3 && args[0].equals("encrypt")) {//对文件进行加密
- File file = new File(args[1]);
- FileInputStream in = new FileInputStream(file);
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- byte[] tmpbuf = new byte[1024];
- int count = 0;
- while ((count = in.read(tmpbuf)) != -1) {
- bout.write(tmpbuf, 0, count);
- tmpbuf = new byte[1024];
- }
- in.close();
- byte[] orgData = bout.toByteArray();
- Key key = getKey(new FileInputStream(args[2]));
- byte[] raw = DESEncryptUtil.doEncrypt(key, orgData);
- file = new File(file.getParent() + "//en_" + file.getName());
- FileOutputStream out = new FileOutputStream(file);
- out.write(raw);
- out.close();
- System.out.println("成功加密,加密文件位于:"+file.getAbsolutePath());
- } else if (args.length == 3 && args[0].equals("decrypt")) {//对文件进行解密
- File file = new File(args[1]);
- FileInputStream fis = new FileInputStream(file);
- Key key = getKey(new FileInputStream(args[2]));
- InputStream raw = DESEncryptUtil.doDecrypt(key, fis);
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- byte[] tmpbuf = new byte[1024];
- int count = 0;
- while ((count = raw.read(tmpbuf)) != -1) {
- bout.write(tmpbuf, 0, count);
- tmpbuf = new byte[1024];
- }
- raw.close();
- byte[] orgData = bout.toByteArray();
- file = new File(file.getParent() + "//rs_" + file.getName());
- FileOutputStream fos = new FileOutputStream(file);
- fos.write(orgData);
- System.out.println("成功解密,解密文件位于:"+file.getAbsolutePath());
- }
- }
- }
解密工作主要涉及到两个类Cipher和Key,前者是加密器,可以通过init()方法设置工作模式和密钥,在这里,我们设置为解密工作模式:Cipher.DECRYPT_MODE。Cipher通过doFinal()方法对字节数组进行加密或解密。