按:以下文字涉及RSA對WebService傳遞的數據的加密解密,如果您已經熟知RSA或是有其它更好的方法請不要往下看以免浪費時間.
WebService采用的協(xié)議是SOAP,它基于HTTP,而HTTP是明文方式,也就是說,采用WebService傳遞的數據是明文的。如果是天氣預報這種公開的只讀信息的WebService無所謂,如果涉及寫入或是和私密數據相關,那么明文傳遞就有很大的潛在危險性,必須加以遏止。
一般來說有兩種方法,一是采用https加密的方式,另一種是用非對稱加密算法對數據加密,下文提到的RSA就是第二種。
使用RSA對WebService傳遞的信息加密解密的基本思想是:服務器端提供一個WebService方法byte[] getServerPublicKey(),客戶端可以以此得到服務器端的公鑰,然后使用服務器端的公鑰對要傳出去的數據進行RSA加密,并附帶以自己的公鑰;服務器端得到客戶端的請求后,先用自己的私鑰解密客戶端送來的數據,得到處理結果后用客戶端提供的公鑰加密,然后傳回;客戶端得到服務器端的返回數據后,用自己的私鑰進行解密,最終得到了服務器端的真實數據。服務器端和客戶端各自保存自己的RSA私鑰用于解密,提供給對方RSA公鑰進行加密,這樣中間傳遞的信息就安全了。
加密解密示意順序圖:
下面是服務器端實現類的代碼:
package com.heyang;
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();
}
}
客戶端調用服務器端的代碼:
package com.heyang;
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();
}
}
}
輸出的結果為:
從服務器端得到的公鑰為:48-127-9748136942-12272-122-913111503-127-115048-127-1192-127-1270-575108-121578675121-687-32-1165359-2586-50-127114-24-6769-17-128115114982868-11550-121-111-69-494021-48-22-5844-37-8645-115-125-984651-344761-117-7875-34115-101-119164666123-4211-13-103-62-30-587926842-12338-32-91-24-75-1177128103-12-71108-121-122112-712-1089753-2691-7863-6385-41-10210782-8784120344-69-90474108-3661-47089-1261812510046-123-3910723101
從服務器端返回的字符串結果是:你好!世界
服務器端和客戶端使用的RSA加密解密類代碼:
package com.heyang;
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)
* 創(chuàng)建時間: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
* 創(chuàng)建時間: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
* 創(chuàng)建時間: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類代碼:
package com.heyang;
/**
* 信息安全實用類
* 說明:
* 作者:何楊(heyang78@gmail.com)
* 創(chuàng)建時間:2010-12-2 上午10:57:49
* 修改時間:2010-12-2 上午10:57:49
*/
public class SecurityUtil{
// 用于加密解密的RSA編碼類
private static RSASecurityCoder coder;
/**
* 初始化coder的靜態(tài)構造子
*/
static{
try {
coder=new RSASecurityCoder();
} catch (Exception e) {
e.printStackTrace();
}
}
public static RSASecurityCoder getCoder() {
return coder;
}
}
您可以從
http://www.box.net/shared/cyg98xgz78 獲得上述代碼涉及到的兩個實例工程。
好了,感謝您看到這里,希望此文字沒有耽誤您太多寶貴時間。