给hibernate配置文件加密 解密的方案

转自:http://www.javaeye.com/topic/70663

如何给工程中的配置文件加密 解密
之前有人问过hibernate密码问题,大家都没有给出一个具体的解决方案,所以我就看了一下代码,把我的想法和实现拿出来和大家讨论一下。

我现在的环境是spring+hibernate,但是这并不影响这个加密解密的问题,其他环境应该是略有不同,但是思路肯定是一样的。

总体思路:在工程的配置文件中填写数据库密码的密文,在应用程序使用datasource的时候解密成明文以创建连接。
步骤1
使用java的中cipher类并使用DES(对称加密算法)算法对明文进行加密
````````````````这里如何使用cipher类和DES算法的原理可以上网查找,我懒得写了,如果大家真的也怕麻烦自己去找的话我再写一个贴出来吧


修改:我随便写了一个类,大家看着改吧,我没有测试过

Java代码 复制代码
  1. public class DESUtil {   
  2.        
  3.     public static void main(String[] args){   
  4.         try {   
  5.             if(args[0].equals("-genKey")){   
  6.                  generateKey(args[1]);   
  7.              }else{   
  8.                    
  9.                 //if (args[0].equals("-encrypt"))encrypt();   
  10.                        
  11.                 //else decrypt();      
  12.              }   
  13.          }catch (Exception e) {   
  14.             // TODO: handle exception   
  15.          }   
  16.      }   
  17.        
  18.     public static String encrypt(String plainText, String encryptString, File keyFile)throws IOException, ClassNotFoundException,GeneralSecurityException{   
  19.          ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(keyFile));   
  20.         int mode = Cipher.ENCRYPT_MODE;   
  21.          Key key = (Key)keyIn.readObject();     
  22.          keyIn.close();   
  23.            
  24.          InputStream in = new FileInputStream(plainText);   
  25.          OutputStream out = new FileOutputStream(encryptString);   
  26.            
  27.          Cipher cipher = Cipher.getInstance("DES");   
  28.          cipher.init(mode, key);   
  29.            
  30.          doEncryptAndDecrypt(in, out, cipher);   
  31.            
  32.          String result = out.toString();   
  33.          System.out.print(result);   
  34.          in.close();   
  35.          out.close();   
  36.         return result;   
  37.      }   
  38.        
  39.     public static String decrypt(String encryptString, String plainText, File keyFile)throws IOException, ClassNotFoundException,GeneralSecurityException{   
  40.          ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(keyFile));   
  41.         int mode = Cipher.DECRYPT_MODE;   
  42.          Key key = (Key)keyIn.readObject();     
  43.          keyIn.close();   
  44.            
  45.          InputStream in = new FileInputStream(encryptString);   
  46.          OutputStream out = new FileOutputStream(plainText);   
  47.            
  48.          Cipher cipher = Cipher.getInstance("DES");   
  49.          cipher.init(mode, key);   
  50.            
  51.          doEncryptAndDecrypt(in, out, cipher);   
  52.            
  53.          String result = out.toString();   
  54.          System.out.print(result);   
  55.          in.close();   
  56.          out.close();   
  57.         return result;   
  58.      }   
  59.        
  60.     public static void doEncryptAndDecrypt(InputStream in, OutputStream out, Cipher cipher)throws IOException, GeneralSecurityException{   
  61.         int blockSize = cipher.getBlockSize();   
  62.         int outputSize = cipher.getOutputSize(blockSize);   
  63.            
  64.         byte[] inBytes = new byte[blockSize];   
  65.         byte[]   outBytes = new byte[outputSize];   
  66.            
  67.         int inLength = 0;   
  68.         boolean more = true;   
  69.            
  70.         while(more){   
  71.              inLength = in.read(inBytes);   
  72.             if(inLength == blockSize){   
  73.                 int outLength = cipher.update(inBytes, 0, blockSize, outBytes);   
  74.                  out.write(outBytes,0,outLength);   
  75.              }   
  76.             else more = false;   
  77.          }   
  78.            
  79.         if(inLength>0) outBytes = cipher.doFinal(inBytes, 0, inLength);   
  80.         else outBytes = cipher.doFinal();   
  81.            
  82.          out.write(outBytes);   
  83.            
  84.      }   
  85.        
  86.     public static void generateKey(String path) throws Exception{   
  87.          KeyGenerator keygen = KeyGenerator.getInstance("DES");   
  88.          SecureRandom random = new SecureRandom();   
  89.            
  90.          keygen.init(random);   
  91.          SecretKey key = keygen.generateKey();   
  92.            
  93.          ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream(path));   
  94.          out.writeObject(key);   
  95.          out.close();   
  96.      }   
  97.   
  98. }  
public class DESUtil {
 
 public static void main(String[] args){
  try {
   if(args[0].equals("-genKey")){
    generateKey(args[1]);
   }else{
    
    //if (args[0].equals("-encrypt"))encrypt();
     
    //else decrypt(); 
   }
  }catch (Exception e) {
   // TODO: handle exception
  }
 }
 
 public static String encrypt(String plainText, String encryptString, File keyFile)throws IOException, ClassNotFoundException,GeneralSecurityException{
  ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(keyFile));
  int mode = Cipher.ENCRYPT_MODE;
  Key key = (Key)keyIn.readObject(); 
  keyIn.close();
  
  InputStream in = new FileInputStream(plainText);
  OutputStream out = new FileOutputStream(encryptString);
  
  Cipher cipher = Cipher.getInstance("DES");
  cipher.init(mode, key);
  
  doEncryptAndDecrypt(in, out, cipher);
  
  String result = out.toString();
  System.out.print(result);
  in.close();
  out.close();
  return result;
 }
 
 public static String decrypt(String encryptString, String plainText, File keyFile)throws IOException, ClassNotFoundException,GeneralSecurityException{
  ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(keyFile));
  int mode = Cipher.DECRYPT_MODE;
  Key key = (Key)keyIn.readObject(); 
  keyIn.close();
  
  InputStream in = new FileInputStream(encryptString);
  OutputStream out = new FileOutputStream(plainText);
  
  Cipher cipher = Cipher.getInstance("DES");
  cipher.init(mode, key);
  
  doEncryptAndDecrypt(in, out, cipher);
  
  String result = out.toString();
  System.out.print(result);
  in.close();
  out.close();
  return result;
 }
 
 public static void doEncryptAndDecrypt(InputStream in, OutputStream out, Cipher cipher)throws IOException, GeneralSecurityException{
  int blockSize = cipher.getBlockSize();
  int outputSize = cipher.getOutputSize(blockSize);
  
  byte[] inBytes = new byte[blockSize];
  byte[] outBytes = new byte[outputSize];
  
  int inLength = 0;
  boolean more = true;
  
  while(more){
   inLength = in.read(inBytes);
   if(inLength == blockSize){
    int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
    out.write(outBytes,0,outLength);
   }
   else more = false;
  }
  
  if(inLength>0) outBytes = cipher.doFinal(inBytes, 0, inLength);
  else outBytes = cipher.doFinal();
  
  out.write(outBytes);
  
 }
 
 public static void generateKey(String path) throws Exception{
  KeyGenerator keygen = KeyGenerator.getInstance("DES");
  SecureRandom random = new SecureRandom();
  
  keygen.init(random);
  SecretKey key = keygen.generateKey();
  
  ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream(path));
  out.writeObject(key);
  out.close();
 }

}



通过以上的encrypt方法得到一个密码的密文(一般的密码是明文,作为参数传进去可以得到对应的密文),比如说21sadf25

步骤2
将加密后的密文添加到配置文件中

Java代码 复制代码
  1. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">   
  2.          <property name="driverClassName" value="org.gjt.mm.mysql.Driver"/>   
  3.          <property name="url" value="jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=utf-8&autoReconnect=true"/>   
  4.          <property name="username" value="root"/>   
  5.          <property name="password" value="21sadf25"/>   
  6.          <property name="maxActive" value="100"/>   
  7.          <property name="whenExhaustedAction" value="1"/>   
  8.          <property name="maxWait" value="120000"/>   
  9.          <property name="maxIdle" value="30"/>   
  10.          <property name="defaultAutoCommit" value="true"/>   
  11.      </bean>    
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="org.gjt.mm.mysql.Driver"/>
        <property name="url" value="jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=utf-8&autoReconnect=true"/>
        <property name="username" value="root"/>
        <property name="password" value="21sadf25"/>
        <property name="maxActive" value="100"/>
        <property name="whenExhaustedAction" value="1"/>
        <property name="maxWait" value="120000"/>
        <property name="maxIdle" value="30"/>
        <property name="defaultAutoCommit" value="true"/>
    </bean>



步骤3
继承spring的LocalSessionFactoryBean类,override其setDataSource方法,将dataSource的password取出,解密后再赋值。
为什么要这么做呢,因为datasource是localsessionFactoryBean的一个属性,在注入dataSource时将其密码解密是比较恰当的。所以选择这个setDataSource方法进行override。假设我们使用的dbcp连接池
代码如下:(类名是AhuaXuanLocalSessionFactoryBean)

Java代码 复制代码
  1. public void setDataSource(DataSource dataSource) {   
  2. String password = (BasicDataSource)dataSource.getPassword();   
  3. //通过cipher类进行解密   
  4. String decryPassword = DESUtil.decrypt(password);   
  5. dataSource.setPassword(decryPassword);   
  6.         this.dataSource = dataSource;   
  7.      }  
public void setDataSource(DataSource dataSource) {
String password = (BasicDataSource)dataSource.getPassword();
//通过cipher类进行解密
String decryPassword = DESUtil.decrypt(password);
dataSource.setPassword(decryPassword);
  this.dataSource = dataSource;
 }

配置如下:

Java代码 复制代码
  1. <bean id="sessionFactory" class="org.springframework.orm.hibernate.AhuaXuanLocalSessionFactoryBean">   
  2.                      <property name="dataSource">   
  3.              <ref bean="dataSource"/>   
  4.          </property>   
  5. </bean>  
<bean id="sessionFactory" class="org.springframework.orm.hibernate.AhuaXuanLocalSessionFactoryBean">
                    <property name="dataSource">
            <ref bean="dataSource"/>
        </property>
</bean>

之前robbin说的DataSourceFactoryBean那个类我在spring1.2.8中没有找到,但是我觉得改造LocalSessionFactoryBean也不错

这样就完成了一个我们的目标,以上代码是随便写的,没有经过测试,有兴趣的同学可以试一下

补充:此方式我测试过,可行。

 

 

---------------------------------------------分割线----------------------------------------------------------------

 

 

 

 

最后的解决方案实际上我是直接在spring源码里改了LocalSessionFactoryBean.java,重新打包。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值