http://www.blogjava.net/heyang/archive/2010/12/02/339589.html
按:以下文字涉及RSA对WebService传递的数据的加密解密,如果您已经熟知RSA或是有其它更好的方法请不要往下看以免浪费时间.
WebService采用的协议是SOAP,它基于HTTP,而HTTP是明文方式,也就是说,采用WebService传递的数据是明文的。如果是天气预报这种公开的只读信息的WebService无所谓,如果涉及写入或是和私密数据相关,那么明文传递就有很大的潜在危险性,必须加以遏止。
一般来说有两种方法,一是采用https加密的方式,另一种是用非对称加密算法对数据加密,下文提到的RSA就是第二种。
使用RSA对WebService传递的信息加密解密的基本思想是:服务器端提供一个WebService方法byte[] getServerPublicKey(),客户端可以以此得到服务器端的公钥,然后使用服务器端的公钥对要传出去的数据进行RSA加密,并附带以自己的公钥;服务器端得到客户端的请求后,先用自己的私钥解密客户端送来的数据,得到处理结果后用客户端提供的公钥加密,然后传回;客户端得到服务器端的返回数据后,用自己的私钥进行解密,最终得到了服务器端的真实数据。服务器端和客户端各自保存自己的RSA私钥用于解密,提供给对方RSA公钥进行加密,这样中间传递的信息就安全了。
加密解密示意顺序图:
下面是服务器端实现类的代码:
下面是服务器端实现类的代码:
public class ServiceImpl implements IService{
@Override
public byte [] getResonse( byte [] params, byte [] clientPublicKey) {
try {
// 使用自己的私钥解密客户端用服务器端公钥加密的数据
String decryptString = SecurityUtil.getCoder().getDecryptString(params);
// 要返回的结果
String response = " 你好! " + decryptString;
// 使用客户端提供的公钥对返回的数据进行加密
byte [] retval = SecurityUtil.getCoder().getEncryptArray(response, clientPublicKey);
return retval;
} catch (Exception e) {
e.printStackTrace();
return null ;
}
}
@Override
public byte [] getServerPublicKey() {
return SecurityUtil.getCoder().getPublicKey();
}
}
客户端调用服务器端的代码:
import org.codehaus.xfire.XFireFactory;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;
public class Test {
public static void main(String[] args) {
Service srvcModel = new ObjectServiceFactory().create(IService. class );
XFireProxyFactory factory = new XFireProxyFactory(XFireFactory
.newInstance().getXFire());
String helloWorldURL = " http://localhost:8080/XfireSample/services/hello " ;
try {
IService srvc = (IService) factory.create(srvcModel, helloWorldURL);
// 得到服务器端的公钥
byte [] serverPublicKey = srvc.getServerPublicKey();
System.out.print( " 从服务器端得到的公钥为: " );
for ( byte b:serverPublicKey){
System.out.print(b);
}
System.out.println();
RSASecurityCoder coder = SecurityUtil.getCoder();
String requestString = " 世界 " ;
// 使用服务器端的公钥对要传出去的数据进行加密
byte [] params = coder.getEncryptArray(requestString, serverPublicKey);
// 得到服务器端的返回结果
byte [] responseArray = srvc.getResonse(params, coder.getPublicKey());
// 使用自己的私钥进行解密
String responseString = coder.getDecryptString(responseArray);
System.out.println( " 从服务器端返回的字符串结果是: " + responseString);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出的结果为:
从服务器端返回的字符串结果是:你好!世界
服务器端和客户端使用的RSA加密解密类代码:
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
/**
* RSA加密解密类
* 说明:
* 作者:何杨(heyang78@gmail.com)
* 创建时间:2010-12-1 下午06:14:38
* 修改时间:2010-12-1 下午06:14:38
*/
public class RSASecurityCoder{
// 非对称加密密钥算法
private static final String Algorithm = " RSA " ;
// 密钥长度,用来初始化
private static final int Key_Size = 1024 ;
// 公钥
private final byte [] publicKey;
// 私钥
private final byte [] privateKey;
/**
* 构造函数,在其中生成公钥和私钥
* @throws Exception
*/
public RSASecurityCoder() throws Exception{
// 得到密钥对生成器
KeyPairGenerator kpg = KeyPairGenerator.getInstance(Algorithm);
kpg.initialize(Key_Size);
// 得到密钥对
KeyPair kp = kpg.generateKeyPair();
// 得到公钥
RSAPublicKey keyPublic = (RSAPublicKey)kp.getPublic();
publicKey = keyPublic.getEncoded();
// 得到私钥
RSAPrivateKey keyPrivate = (RSAPrivateKey)kp.getPrivate();
privateKey = keyPrivate.getEncoded();
}
/**
* 用公钥对字符串进行加密
*
* 说明:
* @param originalString
* @param publicKeyArray
* @return
* @throws Exception
* 创建时间:2010-12-1 下午06:29:51
*/
public byte [] getEncryptArray(String originalString, byte [] publicKeyArray) throws Exception{
// 得到公钥
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyArray);
KeyFactory kf = KeyFactory.getInstance(Algorithm);
PublicKey keyPublic = kf.generatePublic(keySpec);
// 加密数据
Cipher cp = Cipher.getInstance(Algorithm);
cp.init(Cipher.ENCRYPT_MODE, keyPublic);
return cp.doFinal(originalString.getBytes());
}
/**
* 使用私钥进行解密
*
* 说明:
* @param encryptedDataArray
* @return
* @throws Exception
* 创建时间:2010-12-1 下午06:35:28
*/
public String getDecryptString( byte [] encryptedDataArray) throws Exception{
// 得到私钥
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory kf = KeyFactory.getInstance(Algorithm);
PrivateKey keyPrivate = kf.generatePrivate(keySpec);
// 解密数据
Cipher cp = Cipher.getInstance(Algorithm);
cp.init(Cipher.DECRYPT_MODE, keyPrivate);
byte [] arr = cp.doFinal(encryptedDataArray);
// 得到解密后的字符串
return new String(arr);
}
public byte [] getPublicKey() {
return publicKey;
}
public static void main(String[] arr) throws Exception{
String str = " 你好,世界! Hello,world! " ;
System.out.println( " 准备用公钥加密的字符串为: " + str);
// 用公钥加密
RSASecurityCoder rsaCoder = new RSASecurityCoder();
byte [] publicKey = rsaCoder.getPublicKey();
byte [] encryptArray = rsaCoder.getEncryptArray(str, publicKey);
System.out.print( " 用公钥加密后的结果为: " );
for ( byte b:encryptArray){
System.out.print(b);
}
System.out.println();
// 用私钥解密
String str1 = rsaCoder.getDecryptString(encryptArray);
System.out.println( " 用私钥解密后的字符串为: " + str1);
}
}
用于初始化RSASecurityCoder实例的SecurityUtil类代码:
/**
* 信息安全实用类
* 说明:
* 作者:何杨(heyang78@gmail.com)
* 创建时间:2010-12-2 上午10:57:49
* 修改时间:2010-12-2 上午10:57:49
*/
public class SecurityUtil{
// 用于加密解密的RSA编码类
private static RSASecurityCoder coder;
/**
* 初始化coder的静态构造子
*/
static {
try {
coder = new RSASecurityCoder();
} catch (Exception e) {
e.printStackTrace();
}
}
public static RSASecurityCoder getCoder() {
return coder;
}
}
您可以从 http://www.box.net/shared/cyg98xgz78 获得上述代码涉及到的两个实例工程。
好了,感谢您看到这里,希望此文字没有耽误您太多宝贵时间。