您的位置:首页 > 其它

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

2009-09-21 15:03 323 查看
转自:http://www.javaeye.com/topic/70663

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

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

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

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

Java代码



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();

}

}

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代码



<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>

<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代码



public void setDataSource(DataSource dataSource) {

String password = (BasicDataSource)dataSource.getPassword();

//通过cipher类进行解密

String decryPassword = DESUtil.decrypt(password);

dataSource.setPassword(decryPassword);

this.dataSource = dataSource;

}

public void setDataSource(DataSource dataSource) {
String password = (BasicDataSource)dataSource.getPassword();
//通过cipher类进行解密
String decryPassword = DESUtil.decrypt(password);
dataSource.setPassword(decryPassword);
this.dataSource = dataSource;
}

配置如下:

Java代码



<bean id="sessionFactory" class="org.springframework.orm.hibernate.AhuaXuanLocalSessionFactoryBean">

<property name="dataSource">

<ref bean="dataSource"/>

</property>

</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,重新打包。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: