當柳上原的風吹向天際的時候...

          真正的快樂來源于創造

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks
          按:以下文字涉及RSA對WebService傳遞的數據的加密解密,如果您已經熟知RSA或是有其它更好的方法請不要往下看以免浪費時間.

          WebService采用的協議是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)
           * 創建時間: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類代碼:
          package com.heyang;

          /**
           * 信息安全實用類
           * 說明:
           * 作者:何楊(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 獲得上述代碼涉及到的兩個實例工程。

          好了,感謝您看到這里,希望此文字沒有耽誤您太多寶貴時間。
          posted on 2010-12-02 11:44 何楊 閱讀(11038) 評論(16)  編輯  收藏

          Feedback

          # re: 使用RSA進行信息加密解密的WebService示例[未登錄] 2010-12-02 13:22 zz
          支持一下,幸苦了  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例 2010-12-09 09:59 mashiguang
          謝謝,先收藏再細讀。  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例 2010-12-09 10:06 mashiguang
          學習了。我感覺這樣做解決了明文的問題,是不是還不能解決假冒客戶端的問題?  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例 2010-12-09 14:12 何楊
          @mashiguang

          是的,還需要用數字證書等。  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例[未登錄] 2010-12-10 09:41 mashiguang
          @何楊
          謝謝
          期待你出一篇https加密的方式的文章。  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例 2010-12-10 09:55 何楊
          @mashiguang

          客氣了,我也是初學。盡力吧!  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例[未登錄] 2011-03-06 15:13 s
          客戶端的密鑰怎么產生的?是不是也在服務器端產生然后返回到了客戶端?那傳輸過程中被人截取了私鑰怎么辦?再說你定義的方法都是在服務器端執行,加密也是先把明文發送到服務器加密 ,然后返回加密的數據,再發送到服務器  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例[未登錄] 2011-03-07 23:04 何楊
          @s

          服務器和客戶端都是各自產生自己的私鑰和公鑰,公鑰用于發給對方來給要發給自己的數據加密,收到數據后再用自己這邊的私鑰解密。  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例 2011-04-18 08:41 柳寄悠
          你好,我是一名大四的學生,現在正在做畢業設計,你的文章“使用RSA進行信息加密解密的WebService示例 ”對我很有幫助,我還有問題要問你,希望加qq:912614339  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例[未登錄] 2011-12-09 23:13 Ruby
          @mashiguang
          @何楊
          不僅客戶端,服務端也有被假冒的危險。
          公鑰傳輸過程不可靠。
          使用RSA進行常規通訊還有低效問題。
          直接上有可信數字證書的HTTPS更靠譜。
            回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例 2011-12-10 09:05 何楊
          @Ruby

          說的沒錯,這篇文章只是學習過程中的一步,還會前進的。  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例 2012-02-08 16:13 ss
          您好,我想問一下那個XfireSample導進去怎么會有錯的,我的QQ:414038013,希望您能加我,你這篇文章對我非常有幫助,謝謝  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例 2012-02-13 11:06 何楊
          @ss

          庫導入進去了?  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例 2012-09-04 18:21 魏燕
          這個是java的 有.net的嗎?有的話 麻煩解答一下~  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例 2012-09-05 09:09 何楊
          @魏燕

          沒。  回復  更多評論
            

          # re: 使用RSA進行信息加密解密的WebService示例 2014-05-08 09:57 tanjun
          實例怎么下載不了  回復  更多評論
            


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 泉州市| 勐海县| 沈丘县| 湖南省| 天柱县| 昌江| 凌源市| 宽甸| 新建县| 定远县| 尤溪县| 武胜县| 盈江县| 卢氏县| 廉江市| 榆社县| 类乌齐县| 阆中市| 盐边县| 综艺| 祁东县| 花莲县| 开平市| 格尔木市| 正宁县| 抚顺市| 龙川县| 灵武市| 高阳县| 邹平县| 水城县| 马尔康县| 专栏| 成安县| 盘锦市| 南宫市| 安多县| 金沙县| 江永县| 商都县| 张家川|