<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

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

    真正的快樂來源于創造

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks
    按:下面的文字涉及早已在工程中廣泛采用的混合加密方式,對此熟知者就不用往下看了,以免浪費時間。

    我們知道,現代加密方式有兩大類:一類是對稱加密方式,其優點是加密速度快,缺點是密鑰不便于傳遞,其中典型代表是AES;一類是非對稱加密方式,優點是交換鑰匙方便,缺點是加密時間長,代表是RSA。在實際應用,我們可以取其所長,棄其所短,這就是混合加密方式,有的場合也成為Hybrid方式。

    具體來說混合加密方式的工作過程大體是這樣:首先,客戶端將明文用本地的AES鑰匙加密,然后從服務器端得到服務器端的RSA公鑰,用它來對本地的AES鑰匙加密,然后把兩端密文拼合在一起送給服務器端;服務器端得到密文后,將其拆分成密鑰文和密文兩段,然后,用本地的RSA私鑰對密鑰文進行解密,得到加密密文的AES鑰匙,然后用AES鑰匙對密文解密,得到明文。在此過程中,對明文加密和對密文解密都采用了對稱加密解密方式,速度快,且都在服務器客戶機的一側進行,沒有通過網絡傳輸,安全性高;而網絡傳輸的是服務器的RSA公鑰和經其加密的AES鑰匙,即使被截獲也沒有什么好擔心的。如果要雙向傳遞則把這個過程反過來就可以了。

    以上過程的示意UML SEQUENCE圖如下:



    下面用代碼來輔助說明一下。

    客戶端進行加密并傳輸密文到服務器端的代碼,其中,服務器端的RSA公鑰已經用別的方法得到了,下面serverPublicKey變量就存儲了它:
            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);
            
            
    // 在發出的密文前附帶經服務器RSA公鑰加密的AES密鑰
            String request="<key>"+encryptedKey+"</key>"+cipherText;
            
            out.print(request);
            out.flush();
            s.shutdownOutput();
    // 輸出結束

    從上面這段代碼可以看出,想發送到服務器端的明文是:
    <request><command>register</command><username>何楊</username><password>123456</password></request>

    通過這段代碼的處理后,最終發送到服務器端的密文是,
    <key>1B2FM07HS4iB+vjeehb/RqHTnEXAr1cj/CR6z+SDPI58ZG5TK54iEoi8cvdIL0oj60X7axrAL3YO
    b6PMzQxKHzipSYw3ishH/3KxoYF8bkQGn2PkMNsn+xL1Gz6XgJcQ+B700hYvVT2FFPfelVz3VNlB
    KhwVIE6h8LyD4w/SxhE=
    </key>J4TsMoB3l8Cy91a9v6O0TADXZvKEkDPZ3E5noeu2dImfdsM55urhEY7lFAAsXm0AB4/jUL1h1lNP
    cafz9srORh7h8NCb4760XnrBA5Q2JQrqwr1TGsB3oGq2Ha+FOLoFcI2Ab/wjEiAhe/kB6ZTgTA==
    其中key節點的內容是加密的AES密鑰,后面是AES加密后的密文。如果這段文字在網絡上被截獲,截獲者可能會猜測出key節點是密鑰,后半段是密文,但密鑰部分是被服務器的公鑰進行RSA加密的,只有用服務器的私鑰來解密;而密鑰文解不出來的話,截獲者對后端密文也是無能為力。這就可以讓人放心了,如果服務器端沒有潛伏一個余則成和截獲者里應外合的話。這里還可以把整段文字用Base64加密一下,到服務器再解密。

    服務器端的處理代碼:
            String cipheredAesKey="";// 經服務器RSA公鑰加密的客戶端AES鑰匙密文
            String cipherText="";// 經客戶端AES加密的密文
            
            
    // 用正則表達式得到密鑰文和密文
            String regex="<key>(.+)</key>(.+)";
            Pattern pattern
    =Pattern.compile(regex);
            Matcher matcher
    =pattern.matcher(request);
                
            
    while(matcher.find()){
                cipheredAesKey
    =matcher.group(1);
                cipherText
    =matcher.group(2);
                
    break;
            }

            
    // 得到經過服務器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);

    這段代碼的輸入是:
    <key>P9SQ2DtWqrdH3hJbQNWRb51OEs9c7KpsgjRg0yPT5LZJoqJBeYmq3r/1T050n136OelvTh+XtaZaXbCJAvfnF4fvtAKdXqPp+lzUNgPYk8R0OaVDUIi8pNi1rb/+GvtY2ZucFYL1BOwO8ARwvXf8f52Cl+Vdu5TdinXVjmwSPZY=</key>u0ube9sy7bsIy8aaUSJofoswY+R3WXD8yJbOzEZWiDniyXNNyrHNiygfRHj3TKwVQXRck/OVPXptMvUjCVqmg118TN0tc4sKoOKHaSmUtvGC2WW3K5anxlFzdUIZMIhvpDF1nWoaTXvEJ1nOuwhIig==
    它和客戶端傳過來的內容是一樣的。

    而經過拆分和解密后,AES密鑰是:
    83aeacfa1b59eb2dc557a9f3d5df6af83ee9a1646652f1d2b55ea6ec76a95bde

    用得到的AES密鑰解密后,最終得到的明文部分是:
    <request><command>register</command><username>何楊</username><password>123456</password></request>

    到這里,密文的還原工作就完成了。如果服務器端要向客戶端發回處理后的結果,把上述過程再做一遍就可以了,注意一點,客戶端要把自己的RSA公鑰發過來,也就是說傳遞的文本中還要增加一個節點,這樣服務器端就有了客戶端的RSA公鑰對服務器端的AES鑰匙進行加密。(完整混合加密客戶機服務器通訊過程請參看:http://www.tkk7.com/heyang/archive/2010/12/26/341556.html

    這種方式看似比純RSA方式和AES方式都復雜了一點,但考慮到網絡傳輸的安全性和速度,多寫一些代碼是完全值得的。

    上文中用到的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)
     * 創建時間:2010-12-25 下午12:19:12
     * 修改時間:2010-12-25 下午12:19:12
     
    */
    public class AESSecurityCoder{
        
    // 加密方法
        private static final String Algorithm="AES";
        
        
    // 進行加密解密的密鑰
        private String aesKey="";
        
        
    /**
         * 構造函數
         * 
    @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
         * 創建時間: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
         * 創建時間: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;
            }
        }
        
        
    /**
         * 取得加密后的字節數組
         * 
         * 說明:
         * 
    @param originalString
         * 
    @return
         * 創建時間: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
         * 創建時間:2010-12-1 下午03:33:17
         
    */
        
    private Key getKey() throws Exception{
            
    byte[] arr=Hex.decodeHex(aesKey.toCharArray());
            
            
    return new SecretKeySpec(arr,Algorithm);
        }

        
    /**
         * 取得AES加密鑰匙
         * 
         * 說明:
         * 
    @return
         * 創建時間: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)
     * 創建時間: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;
        
        
    /**
         * 構造函數,在其中生成公鑰和私鑰
         * 
    @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);
        }

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

    好了,感謝您看到這里,希望它沒有太多耽誤您的寶貴時間。
    posted on 2010-12-25 16:02 何楊 閱讀(4324) 評論(6)  編輯  收藏

    Feedback

    # re: 在網絡通訊中采用混合方式對信息進行加密 2010-12-25 21:20 Michaelsong
    加密解密,大學專業是信息安全,要好好學學……  回復  更多評論
      

    # re: 在網絡通訊中采用混合方式對信息進行加密[未登錄] 2012-06-11 00:29 Tim
    對我有用。。十分感謝。謝謝  回復  更多評論
      

    # re: 在網絡通訊中采用混合方式對信息進行加密 2014-01-17 11:26 無敵3
    請問樓主,服務器存儲的公鑰密鑰對只有一個,還是根據客戶端發來的隨機數生成針對這個用戶的公鑰密鑰對  回復  更多評論
      

    # re: 在網絡通訊中采用混合方式對信息進行加密 2014-11-29 20:59 Zagfai
    還不是跟https一個原理  回復  更多評論
      

    # re: 在網絡通訊中采用混合方式對信息進行加密 2016-07-04 12:58 #123
    還在 不
    ?
      回復  更多評論
      

    # re: 在網絡通訊中采用混合方式對信息進行加密 2016-07-04 12:59 #123
    你給的那個程序 代碼鏈接 打不開了
    是不是 失效了 能不能再給個   回復  更多評論
      


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


    網站導航:
     
    主站蜘蛛池模板: 国产免费拔擦拔擦8x| 亚洲国产日韩在线视频| 一区二区三区精品高清视频免费在线播放 | 亚洲AV无码一区二区三区在线观看 | 四虎永久在线精品免费网址| 国产成人综合亚洲一区| 久久久亚洲欧洲日产国码农村| 黄瓜视频影院在线观看免费| 人体大胆做受免费视频| 亚洲视频免费一区| 午夜亚洲国产成人不卡在线| 最近中文字幕电影大全免费版| 国产亚洲人成在线播放| 亚洲欧洲国产精品你懂的| 白白国产永久免费视频| 美女视频黄的免费视频网页| 亚洲中文字幕无码mv| 亚洲精品无码乱码成人| 成年人在线免费观看| 一个人免费视频在线观看www | 亚洲人成影院在线高清| 久久久久久久亚洲精品| 99精品全国免费观看视频| 免费一级不卡毛片| 老司机午夜免费视频| 456亚洲人成影院在线观| 国产亚洲综合成人91精品 | 免费A级毛片无码A∨男男| 8x网站免费入口在线观看| 国产裸体美女永久免费无遮挡 | 久草免费手机视频| 免费大片av手机看片| 亚洲首页国产精品丝袜| 久久青草亚洲AV无码麻豆| 亚洲国产香蕉人人爽成AV片久久| 很黄很色很刺激的视频免费| 91福利免费体验区观看区| 中国国语毛片免费观看视频| 黄人成a动漫片免费网站| 亚洲色偷精品一区二区三区| 亚洲另类精品xxxx人妖|