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

          真正的快樂來源于創(chuàng)造

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks
          按:前面(http://www.aygfsteel.com/heyang/archive/2010/12/25/341518.html)已經(jīng)提到過混合加密方式,今天這里再來贅述一下完成的代碼和流程,熟悉者就不用往下看了。完整的IM程序在(http://www.box.net/shared/jcrbps2hk3)可以下載。

          整個流程的UML Sequence圖(Amaterus UML用得還不熟練請見諒,會意就好)


          下面是以上八個步驟中使用到的代碼和信息。

          步驟一
          取得服務(wù)器端RSA公鑰的Socket通信代碼
              public static byte[] getPublicKey() throws Exception{
                  Socket s
          =new Socket("127.0.0.1",8888);
                  
                  InputStream  inStram
          =s.getInputStream();
                  OutputStream outStream
          =s.getOutputStream();
                  
                  
          // 輸出
                  PrintWriter out=new PrintWriter(outStream,true);
                  
                  out.print(
          "getPublicKey");
                  out.flush();

                  s.shutdownOutput();
          // 輸出結(jié)束
                  
                  
          // 輸入
                  Scanner in=new Scanner(inStram);
                  StringBuilder sb
          =new StringBuilder();
                  
          while(in.hasNextLine()){
                      String line
          =in.nextLine();
                      sb.append(line);
                  }
                  String response
          =sb.toString();
                  
                  
          byte[] arr=Base64.decodeBase64(response);
                  
                  s.close();
                  
          return arr;
              }

          步驟二:
          客戶端加密過程代碼:

                  // 待加密的明文
                  StringBuilder sb1=new StringBuilder();
                  sb1.append(
          "<request>");
                  sb1.append(
          "<command>register</command>");
                  sb1.append(
          "<username>趙云</username>");
                  sb1.append(
          "<password>123456</password>");
                  sb1.append(
          "</request>");
                  String plainText
          =sb1.toString();
                  
                  
          // 對明文進行AES加密
                  byte[] aesArr=aesCoder.getEncryptByteArray(plainText); // 對明文進行AES加密
                  String cipherText=Base64.encodeBase64String(aesArr);// 得到AES加密后的密文
                  
                  
          // 使用RSA對AES密鑰進行加密
                  String key=aesCoder.getAesKey();// 取得AES的密鑰
                  byte[] rsaArr=rsaCoder.getEncryptArray(key, serverPublicKey);
                  String encryptedKey
          =Base64.encodeBase64String(rsaArr);

          步驟三:
          將密文,AES密鑰,本地RSA公鑰送到服務(wù)器端的代碼(粗體部分):

                  Socket s=new Socket("127.0.0.1",8888);
                 
                 InputStream  inStram=s.getInputStream();
                 OutputStream outStream=s.getOutputStream();

                 
                  // 輸出
                  PrintWriter out=new PrintWriter(outStream,true);
                 
                  // 待加密的明文
                  StringBuilder sb1=new StringBuilder();
                  sb1.append("<request>");
                  sb1.append("<command>register</command>");
                  sb1.append("<username>趙云</username>");
                  sb1.append("<password>123456</password>");
                  sb1.append("</request>");
                  String plainText=sb1.toString();
                 
                  // 對明文進行AES加密
                  byte[] aesArr=aesCoder.getEncryptByteArray(plainText); // 對明文進行AES加密
                  String cipherText=Base64.encodeBase64String(aesArr);// 得到AES加密后的密文
                 
                  // 使用RSA對AES密鑰進行加密
                  String key=aesCoder.getAesKey();// 取得AES的密鑰
                  byte[] rsaArr=rsaCoder.getEncryptArray(key, serverPublicKey);
                  String encryptedKey=Base64.encodeBase64String(rsaArr);
                 
                  // 在發(fā)出的密文前附帶經(jīng)服務(wù)器RSA公鑰加密的AES密鑰
                  StringBuilder sb3=new StringBuilder();
                  sb3.append("<aeskey>"+encryptedKey+"</aeskey>");
                  sb3.append("<rsakey>"+rsaCoder.getPublicKeyString()+"</rsakey>");
                  sb3.append("<text>"+cipherText+"</text>");
                 
                  // 請求送出前用Base64加密
                  String request=Base64SecurityUtil.getEncryptString(sb3.toString());
               
                  out.print(request);
                 out.flush();
                 s.shutdownOutput();
          // 輸出結(jié)束

          步驟四:
          服務(wù)器端解密過程代碼(變量request中就是客戶端送來的請求文):

                 // 得到請求后先用Base64解密
                  request=Base64SecurityUtil.getDecryptString(request);
                  
                  // 用正則表達式得到密鑰文,客戶端的RSA公鑰和密文
                  String regex="<(\\w+)>((.|\\s)+)</\\1>";

                  Pattern pattern=Pattern.compile(regex);
                  Matcher matcher=pattern.matcher(request);
                      
                  String cipheredAesKey="";// 經(jīng)服務(wù)器RSA公鑰加密的客戶端AES鑰匙密文
                  String clientRsaKey="";// 客戶端的RSA公鑰
                  String cipherText="";// 經(jīng)客戶端AES加密的密文
                  
                  Map<String,String> map=new HashMap<String,String>();
                  while(matcher.find()){
                      map.put(matcher.group(1), matcher.group(2));
                  }
                  
                  if(map.size()==3){
                      cipheredAesKey=map.get("aeskey");
                      clientRsaKey=map.get("rsakey");
                      cipherText=map.get("text");
                  }
                  else{
                      return "無法用正則表達式解析服務(wù)器端請求";
                  }

                  // 得到經(jīng)過服務(wù)器RSA私鑰解密后的AES密鑰
                  String plainAesKey="";
                  try {
                      byte[] cipheredAesKeyArr=Base64.decodeBase64(cipheredAesKey);
                      plainAesKey=model.getRsaCoder().getDecryptString(cipheredAesKeyArr);
                  } catch (Exception e) {
                      e.printStackTrace();
                      return null;
                  }
                  
                  // 使用AES密鑰解密出明文
                  byte[] cipherTextArr=Base64.decodeBase64(cipherText);
                  String plainText=model.getAesCoder().getDecryptString(cipherTextArr, plainAesKey);

          步驟五
          這里的主要操作是根據(jù)看用戶名是否在用戶列表中存在,是則創(chuàng)建用戶,否則告知名稱重復(fù)。這段代碼很簡單常見,故省略之。

          步驟六:
          服務(wù)器端加密過程代碼:

                  // 對明文進行AES加密
                  byte[] aesArr=model.getAesCoder().getEncryptByteArray(retval); // 對明文進行AES加密
                  String cipherRetval=Base64.encodeBase64String(aesArr);// 得到AES加密后的密文
                  
                  
          // 使用RSA對AES密鑰進行加密
                  String key=model.getAesCoder().getAesKey();// 取得AES的密鑰
                  String aesKey="";
                  
          try{
                      
          byte[] clientRsaKeyArr=null;
                      clientRsaKeyArr
          =Base64.decodeBase64(clientRsaKey);
                      
          byte[] rsaArr=model.getRsaCoder().getEncryptArray(key, clientRsaKeyArr);
                      aesKey
          =Base64.encodeBase64String(rsaArr);
                  }
                  
          catch(Exception ex){
                      ex.printStackTrace();
                  }
                  
                  
          // 在發(fā)出的密文前附帶經(jīng)服務(wù)器RSA公鑰加密的AES密鑰
                  StringBuilder sb3=new StringBuilder();
                  sb3.append(
          "<aeskey>"+aesKey+"</aeskey>");
                  sb3.append(cipherRetval);

          步驟七:
          將響應(yīng)發(fā)還給客戶端的代碼(粗體部分):

                      InputStream  inStram=incoming.getInputStream();
                      OutputStream outStream
          =incoming.getOutputStream();
                      
                      Scanner in
          =new Scanner(inStram);
                      PrintWriter out
          =new PrintWriter(outStream,true);
                      
                      
          // 得到客戶端的請求
                      StringBuilder sb=new StringBuilder();
                      
          while(in.hasNextLine()){
                          String line
          =in.nextLine();
                          sb.append(line);
                      }
                      
                      
                      String request
          =sb.toString();
                      String response
          ="";
                      
          if("getPublicKey".equals(request)){
                          
          // 求服務(wù)器公鑰
                          response=model.getPublicKey();
                      }
                      
          else{
                          response
          =getResponse(request);
                      }
                      
                      
          // 向客戶端送出反饋
                      out.print(response);
                      out.flush();
                      out.close();

          步驟八:
          客戶端解密服務(wù)器端響應(yīng)的過程:

                  String cipheredAesKey="";// 經(jīng)服務(wù)器RSA公鑰加密的客戶端AES鑰匙密文
                  String cipheredResponse="";// 經(jīng)客戶端AES加密的密文
                  
                  
          // 用正則表達式得到密鑰文,客戶端的RSA公鑰和密文
                  String regex="<aeskey>(.+)</aeskey>(.+)";
                  Pattern pattern
          =Pattern.compile(regex);
                  Matcher matcher
          =pattern.matcher(response);
                      
                  
          while(matcher.find()){
                      cipheredAesKey
          =matcher.group(1);
                      cipheredResponse
          =matcher.group(2);
                      
          break;
                  }
                  
                  
          // 得到經(jīng)過服務(wù)器RSA私鑰解密后的AES密鑰
                  String plainAesKey="";
                  
          try {
                      
          byte[] cipheredAesKeyArr=Base64.decodeBase64(cipheredAesKey);
                      plainAesKey
          =rsaCoder.getDecryptString(cipheredAesKeyArr);
                  } 
          catch (Exception e) {
                      e.printStackTrace();
                  }
                  
                  
          // 使用AES密鑰解密出明文
                  byte[] cipheredResponseArr=Base64.decodeBase64(cipheredResponse);
                  String plainResponse
          =aesCoder.getDecryptString(cipheredResponseArr, plainAesKey);
                  System.out.println(plainResponse);

          好了,整個過程的代碼都貼出來了,感謝您花費寶貴時間看到這里。另外三個加密解密類的代碼如下:
          AESSecurityCoder類:
          package com.heyang.common.code;

          import java.security.Key;
          import java.security.NoSuchAlgorithmException;

          import javax.crypto.Cipher;
          import javax.crypto.KeyGenerator;
          import javax.crypto.SecretKey;
          import javax.crypto.spec.SecretKeySpec;

          import org.apache.commons.codec.binary.Hex;


          /**
           * AES加密解密類
           * 說明:
           * 作者:何楊(heyang78@gmail.com)
           * 創(chuàng)建時間:2010-12-25 下午12:19:12
           * 修改時間:2010-12-25 下午12:19:12
           
          */
          public class AESSecurityCoder{
              
          // 加密方法
              private static final String Algorithm="AES";
              
              
          // 進行加密解密的密鑰
              private String aesKey="";
              
              
          /**
               * 構(gòu)造函數(shù)
               * 
          @throws NoSuchAlgorithmException 
               
          */
              
          public AESSecurityCoder() throws NoSuchAlgorithmException{
                  KeyGenerator kg
          =KeyGenerator.getInstance(Algorithm);
                  kg.init(
          256);
                  SecretKey sk
          =kg.generateKey();
                  
          byte[] arr=sk.getEncoded();
                  
                  aesKey
          =new String(Hex.encodeHex(arr));
              }
              
              
          /**
               * 取得解密后的字符串
               * 
               * 說明:
               * 
          @param encryptArr
               * 
          @return
               * 創(chuàng)建時間:2010-12-1 下午03:33:31
               
          */
              
          public String getDecryptString(byte[] encryptArr){
                  
          try{
                      Cipher cp
          =Cipher.getInstance(Algorithm);
                      cp.init(Cipher.DECRYPT_MODE, getKey());
                      
          byte[] arr=cp.doFinal(encryptArr);
                      
                      
          return new String(arr);
                  }
                  
          catch(Exception ex){
                      System.out.println(
          "無法進行解密,原因是"+ex.getMessage());
                      
          return null;
                  }
              }
              
              
          /**
               * 傳入密鑰,得到解密后的字符串
               * 
               * 說明:
               * 
          @param encryptArr
               * 
          @param aesKey
               * 
          @return
               * 創(chuàng)建時間:2010-12-25 下午01:55:42
               
          */
              
          public String getDecryptString(byte[] encryptArr,String aesKeyIn){
                  
          try{
                      Cipher cp
          =Cipher.getInstance(Algorithm);
                      
                      
          byte[] arr1=Hex.decodeHex(aesKeyIn.toCharArray());
                      cp.init(Cipher.DECRYPT_MODE, 
          new SecretKeySpec(arr1,Algorithm));
                      
          byte[] arr=cp.doFinal(encryptArr);
                      
                      
          return new String(arr);
                  }
                  
          catch(Exception ex){
                      System.out.println(
          "無法進行解密,原因是"+ex.getMessage());
                      
          return null;
                  }
              }
              
              
          /**
               * 取得加密后的字節(jié)數(shù)組
               * 
               * 說明:
               * 
          @param originalString
               * 
          @return
               * 創(chuàng)建時間:2010-12-1 下午03:33:49
               
          */
              
          public byte[] getEncryptByteArray(String originalString){
                  
          try{
                      Cipher cp
          =Cipher.getInstance(Algorithm);
                      cp.init(Cipher.ENCRYPT_MODE, getKey());
                      
          return cp.doFinal(originalString.getBytes());
                  }
                  
          catch(Exception ex){
                      System.out.println(
          "無法進行加密,原因是"+ex.getMessage());
                      
          return null;
                  }
              }
              
              
          /**
               * 取得密鑰
               * 
               * 說明:
               * 
          @return
               * 
          @throws Exception
               * 創(chuàng)建時間:2010-12-1 下午03:33:17
               
          */
              
          private Key getKey() throws Exception{
                  
          byte[] arr=Hex.decodeHex(aesKey.toCharArray());
                  
                  
          return new SecretKeySpec(arr,Algorithm);
              }

              
          /**
               * 取得AES加密鑰匙
               * 
               * 說明:
               * 
          @return
               * 創(chuàng)建時間:2010-12-25 下午12:27:16
               
          */
              
          public String getAesKey() {
                  
          return aesKey;
              }
          }

          RSASecurityCoder類:
          package com.heyang.common.code;

          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;

          import org.apache.commons.codec.binary.Base64;

          /**
           * 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 byte[] publicKey;
              
              
          // 私鑰
              private byte[] privateKey;
              
              
          /**
               * 構(gòu)造函數(shù),在其中生成公鑰和私鑰
               * 
          @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);
                  
                  
          // 加密數(shù)據(jù)
                  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);
                  
                  
          // 解密數(shù)據(jù)
                  Cipher cp=Cipher.getInstance(Algorithm);
                  cp.init(Cipher.DECRYPT_MODE, keyPrivate);
                  
          byte[] arr=cp.doFinal(encryptedDataArray);
                  
                  
          // 得到解密后的字符串
                  return new String(arr);
              }

              
          /**
               * 取得數(shù)組形式的公鑰
               * 
               * 說明:
               * 
          @return
               * 創(chuàng)建時間:2010-12-25 上午07:50:04
               
          */
              
          public byte[] getPublicKey() {
                  
          return publicKey;
              }
              
              
          /**
               * 取得字符串形式的公鑰
               * 
               * 說明:
               * 
          @return
               * 創(chuàng)建時間:2010-12-25 上午07:51:11
               
          */
              
          public String getPublicKeyString() {
                  
          return  Base64.encodeBase64String(getPublicKey());
              }
              
              
          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(
          "用公鑰加密后的結(jié)果為:");
                  
          for(byte b:encryptArray){
                      System.out.print(b);
                  }
                  System.out.println();
                  
                  
          // 用私鑰解密
                  String str1=rsaCoder.getDecryptString(encryptArray);
                  System.out.println(
          "用私鑰解密后的字符串為:"+str1);
              }
          }

          Base64SecurityUtil類:
          package com.heyang.common.code;

          import org.apache.commons.codec.binary.Base64;


          /**
           * 常規(guī)Base64加密解密實用工具類
           * 說明:
           * 作者:何楊(heyang78@gmail.com)
           * 創(chuàng)建時間:2010-11-29 上午07:52:01
           * 修改時間:2010-11-29 上午07:52:01
           
          */
          public class Base64SecurityUtil{
              
          /**
               * 得到Base64加密后的字符串
               * 
               * 說明:
               * 
          @param originalString
               * 
          @return
               * 創(chuàng)建時間:2010-11-29 上午07:53:30
               
          */
              
          public static String getEncryptString(String originalString){
                  
          byte[] arr = Base64.encodeBase64(originalString.getBytes(), true);
                  
          return new String(arr);
              }
              
              
          /**
               * 得到Base64解密后的字符串
               * 
               * 說明:
               * 
          @param encryptString
               * 
          @return
               * 創(chuàng)建時間:2010-11-29 上午07:56:02
               
          */
              
          public static String getDecryptString(String encryptString){
                  
          byte[] arr = Base64.decodeBase64(encryptString.getBytes());
                  
          return new String(arr);
              }
              
              
          /**
               * 測試
               * 
               * 說明:
               * 
          @param args
               * 創(chuàng)建時間:2010-11-29 上午07:56:39
               
          */
              
          public static void main(String[] args){
                  String str
          ="Hello world!你好,世界。";
                  
                  String str1
          =Base64SecurityUtil.getEncryptString(str);
                  System.out.println(
          "經(jīng)Base64加密后的密文為"+str1);
                  
                  String str2
          =Base64SecurityUtil.getDecryptString(str1);
                  System.out.println(
          "經(jīng)Base64解密后的原文為"+str2);
                  
              }
          }

          posted on 2010-12-26 11:41 何楊 閱讀(7352) 評論(4)  編輯  收藏

          Feedback

          # re: 一個完整的混合加密方式在Socket客戶機服務(wù)器通信應(yīng)用中的例子 2011-12-12 12:09 Horrison
          不懂啊  回復(fù)  更多評論
            

          # re: 一個完整的混合加密方式在Socket客戶機服務(wù)器通信應(yīng)用中的例子 2011-12-14 11:37 何楊
          @Horrison

          工作中涉及就會懂了,用不到那也沒啥。  回復(fù)  更多評論
            

          # re: 一個完整的混合加密方式在Socket客戶機服務(wù)器通信應(yīng)用中的例子 2015-10-30 11:28 junxuelian
          在不?  回復(fù)  更多評論
            


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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 益阳市| 大竹县| 彭阳县| 大英县| 洞头县| 舒兰市| 三河市| 玉田县| 教育| 桃江县| 宣化县| 隆林| 安仁县| 称多县| 兴安县| 邯郸县| 通山县| 伽师县| 台前县| 桐梓县| 芮城县| 东台市| 临桂县| 澄城县| 宁强县| 台北市| 迁西县| 永修县| 永兴县| 临武县| 日照市| 沙田区| 博乐市| 昌都县| 大渡口区| 翁源县| 分宜县| 尚志市| 容城县| 剑川县| 白城市|