HTTPS那些事 用java實現HTTPS工作原理



         今天被問到關於https原理的問題,結果由於知識掌握不牢靠,停留於表面,很多細節都無法回答清楚,於是決定把https的原理弄個明白,廢話不多說,我們先看看https的定義

 (由於很久未寫博客,排版有些凌亂,請諒解)

一:什么是https協議

     在說HTTPS之前先說說什么是HTTP,HTTP就是我們平時瀏覽網頁時候使用的一種協議。HTTP協議傳輸的數據都是未加密的,也就是明文的,因此使 用HTTP協議傳輸隱私信息非常不安全。為了保證這些隱私數據能加密傳輸,於是網景公司設計了SSL(Secure Sockets Layer)協議用於對HTTP協議傳輸的數據進行加密,從而就誕生了HTTPS。SSL目前的版本是3.0,被IETF(Internet Engineering Task Force)定義在RFC 6101中,之后IETF對SSL 3.0進行了升級,於是出現了TLS(Transport Layer Security) 1.0,定義在RFC 2246。實際上我們現在的HTTPS都是用的TLS協議,但是由於SSL出現的時間比較早,並且依舊被現在瀏覽器所支持,因此SSL依然是HTTPS的 代名詞,但無論是TLS還是SSL都是上個世紀的事情,SSL最后一個版本是3.0,今后TLS將會繼承SSL優良血統繼續為我們進行加密服務。目前 TLS的版本是1.2,定義在RFC 5246中,暫時還沒有被廣泛的使用。對歷史感興趣的朋友可以參考http://en.wikipedia.org/wiki/Transport_Layer_Security,這里有對TLS/SSL詳盡的敘述。

 

二:https的工作原理是什么

     HTTPS在傳輸數據之前需要客戶端(瀏覽器)與服務端(網站)之間進行一次握手,在握 手過程中將確立雙方加密傳輸數據的密碼信息,通常情況下會配合數字證書實現。

TLS/SSL協議不僅僅是一套加密傳輸的協議,更是一件經過藝術家精心設計的藝術品,TLS/SSL中使用 非對稱加密,對稱加密以及HASH算法。

這里我們先看看這上面提到的幾種技術(如果你對這些技術已經非常了解,那么請跳過該段落,直接到段落三)

  1. 數字證書

        數字證書是一種權威性的電子文檔,由權威公正的第三方機構,即CA中心簽發的證書。它以數字證書為核心的加密技術可以對網絡上傳輸的信息進行加密和解密、數字簽名和簽名驗證,確保網上傳遞信息的機密性、完整性。 使用了數字證書,即使您發送的信息在網上被他人截獲,甚至您丟失了個人的賬戶、密碼等信息,仍可以保證您的賬戶、資金安全。 

     它能提供在Internet上進行身份驗證的一種權威性電子文檔,人們可以在互聯網交往中用它來證明自己的身份和識別對方的身份。當然在數字證書認證的過程中證書認證中心(CA)作為權威的、公正的、可信賴的第三方,其作用是至關重要的.如何判斷數字認證中心公正第三方的地位是權威可信的。VeriSign、GeoTrust、Thawte 是國際權威數字證書頒發認證機構的“三巨頭”,其中,應用最廣的為VerSign簽發的電子商務數字證書。

CER(Canonical Encoding Rules,規范編碼格式) 是數字證書的一種編碼格式,它是BER(Basic Encoding Rules 基本編碼格式) 的一個變種,比BER 規定得更嚴格。后綴的證書文件有兩種編碼:

DER(Distinguished Encoding Rule 卓越編碼格式) 同樣是BER的一個變種,DER使用定長模式。

PKCS(Public-Key Cryptography Standards,公鑰加密標准) 由RSA實驗室和其他安全系統開發商為公鑰密碼的發展而制定的一系列標准。

pfx是指以pkcs#12格式存儲的證書和相應私鑰。 

在Security編程中,有幾種典型的密碼交換信息文件格式: 
DER-encoded certificate: .cer, .crt 
PEM-encoded message: .pem 
PKCS#12 Personal Information Exchange: .pfx, .p12 
PKCS#10 Certification Request: .p10 .csr
PKCS#7 cert request response: .p7r 
PKCS#7 binary message: .p7b .p7c .spc

cer/.crt 是用於存放證書,它是2進制形式存放

pem 跟crt/cer的區別是它以Ascii來表示

pfx/p12 用於存放個人證書/私鑰,他通常包含保護密碼,2進制方式 

p10 .csr 是證書請求 

p7r是CA對證書請求的回復,只用於導入 

p7b .p7c .spc 以樹狀展示證書鏈(certificate chain),同時也支持單個證書,不含私鑰

 

 

  1. 非對稱加密算法

          1976年,美國學者Dime和Henman為解決信息公開傳送和密鑰管理問題,提出一種新的密鑰交換協議,允許在不安全的媒體上的通訊雙方交換信息,安全地達成一致的密鑰,這就是"公開密鑰系統"。相對於"對稱加密算法"這種方法也叫做"非對稱加密算法"。與對稱加密算法不同,非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密(privatekey)。公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;如果用私有密鑰對數據進行加密,那么只有用對應的公開密鑰才能解密。因為加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。

       非對稱加密算法實現機密信息交換的基本過程是:甲方生成一對密鑰並將其中的一把作為公用密鑰向其它方公開;得到該公用密鑰的乙方使用該密鑰對機密信息進行加密后再發送給甲方;甲方再用自己保存的另一把專用密鑰對加密后的信息進行解密。甲方只能用其專用密鑰解密由其公用密鑰加密后的任何信息。非對稱加密算法的保密性比較好,它消除了最終用戶交換密鑰的需要,但加密和解密花費時間長、速度慢,它不適合於對文件加密而只適用於對少量數據進行加密。 經典的非對稱加密算法如RSA算法等安全性都相當高. 非對稱加密的典型應用是數字簽名。采用雙鑰密碼系統的加密方法,在一個過程中使用兩個密鑰,一個用於加密,另一個用於解密,這種加密方法稱為非對稱加密,也稱為公鑰加密,因為其中一個密鑰是公開的(另一個則需要保密)。

DH (Diffie-Hellman)
       Diffie-Hellman算法(D-H算法),密鑰一致協議。是由公開密鑰密碼體制的奠基人Diffie和Hellman所提出的一種思想。簡單的說就是允許兩名用戶在公開媒體上交換信息以生成"一致"的、可以共享的密鑰。換句話說,就是由甲方產出一對密鑰(公鑰、私鑰),乙方依照甲方公鑰產生乙方密鑰對(公鑰、私鑰)。以此為基線,作為數據傳輸保密基礎,同時雙方使用同一種對稱加密算法構建本地密鑰(SecretKey)對數據加密。這樣,在互通了本地密鑰(SecretKey)算法后,甲乙雙方公開自己的公鑰,使用對方的公鑰和剛才產生的私鑰加密數據,同時可以使用對方的公鑰和自己的私鑰對數據解密。不單單是甲乙雙方兩方,可以擴展為多方共享數據通訊,這樣就完成了網絡交互數據的安全通訊!該算法源於中國的同余定理——中國餘數定理。

RSA
       RSA公鑰加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美國麻省理工學院)開發的。RSA取名來自開發他們三者的名字。RSA是目前最有影響力的公鑰加密算法,它能夠抵抗到目前為止已知的所有密碼攻擊,已被ISO推薦為公鑰數據加密標准。RSA算法基於一個十分簡單的數論事實:將兩個大素數相乘十分容易,但那時想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰。

EL Gamal
         EL Gamal算法是公鑰密碼體制中的一種 ,在密碼學中占有重要的地位。但該算法所采用的冪剩余計算耗時太多的問題 ,一直是制約其廣泛應用的瓶頸問題。提出一種通過建表 ,以及對傳統二進制算法進行改進 ,即將指數進行 2 k進制化 ,減少原 BR算法迭代次數 ,提高加密解密速度的算法。

ECC 
ECC (Elliptical Curve Cryptography,橢圓曲線加密)算法不橢圓曲線理論為基礎,在創建密鑰時可以更快,更小,並且更有效,它是用大質數的積來產生。

目前Java 6公提供了DH和RSA兩種算法實現,通過Bouncy Castle可以實現Elmal算法支持,另ECC加密算法,目前沒有開源組件提支持

  1. 對稱加密算法

        對加密和解密使用相同密鑰的加密算法。由於其速度,對稱性加密通常在消息發送方需要加密大量數據時使用。對稱性加密也稱為密鑰加密。對稱式數據加密的方式的工作原理如圖。所謂對稱,就是采用這種加密方法的雙方使用方式用同樣的密鑰進行加密和解密。密鑰實際上是一種算法,通信發送方使用這種算法加密數據,接收方再以同樣的算法解密數據。因此對稱式加密本身不是安全的。常用的對稱加密有: 

DES、IDEA、RC2、RC4、SKIPJACK算法等 。

采用單鑰密碼系統的加密方法,同一個密鑰可以同時用作信息的加密和解密,這種加密方法稱為對稱加密,也稱為單密鑰加密。

 

  1. HASH算法

常用的摘要算法包括MD5,SHA1,SHA256

消息摘要算法的特點:

① 無論輸入的消息有多長,計算出來的消息摘要的長度總是固定的。
② 消息摘要看起來是“隨機的”。這些比特看上去是胡亂的雜湊在一起的。
③ 一般地,只要輸入的消息不同,對其進行摘要以后產生的摘要消息也必不相同;但相同的輸入必會產生相同的輸出。
④ 消息摘要函數是無陷門的單向函數,即只能進行正向的信息摘要,而無法從摘要中恢復出任何的消息,甚至根本就找不到任何與原信息相關的信息。
⑤ 好的摘要算法,無法找到兩條消息,是它們的摘要相同。

 

消息摘要(Message Digest)又稱為數字摘要(Digital Digest)。它是一個唯一對應一個消息或文本的固定長度的值,它由一個單向Hash加密函數對消息進行作用而產生。如果消息在途中改變了,則接收者通過對收到消息的新產生的摘要與原摘要比較,就可知道消息是否被改變了。因此消息摘要保證了消息的完整性。消息摘要采用單向Hash 函數將需加密 的明文"摘要"成一串128bit的密文,這一串密文亦稱為數字指紋(Finger Print),它有固定的長度,且不同的明文摘要成密文,其結果總是不同的,而同樣的明文其摘要必定一致 。這樣這串摘要便可成為驗證明文是否是"真身"的"指紋"了。


       HASH函數的抗沖突性使得如果一段明文稍有變化,哪怕只更改該段落的一個字母,通過哈希算法作用后都將產生不同的值。而HASH算法的單向性使得要找到到哈希值相同的兩個不 同的輸入消息,在計算上是不可能的。所以數據的哈希值,即消息摘要,可以檢驗數據的完整性。哈希函數的這種對不同的輸入能夠生成不同的值的特性使得無法找到兩個具有相同哈希值的輸入。因此,如果兩個文檔經哈希轉換后成為相同的值,就可以肯定它們是同一文檔。 所以,當希望有效地比較兩個數據塊時,就可以比較它們的哈希值。例如,可以通過比較郵件發送前和發送后的哈希值來驗證該郵件在傳遞時是否修改


      消息摘要算法的主要特征是加密過程不需要密鑰,並且經過加密的數據無法被解密,只有輸入相同的明文數據經過相同的消息摘要算法才能得到相同的密文。消息摘要算法不存在 密鑰的管理與分發問題,適合於分布式網絡相同上使用。由於其加密計算的工作量相當可觀,所以以前的這種算法通常只用於數據量有限的情況下的加密,例如計算機的口令就是 用不可逆加密算法加密的。

 

   三 https握手的過程詳細描述

1.瀏覽器將自己支持的一套加密規則發送給網站,如RSA加密算法,DES對稱加密算法,SHA1摘要算法
2.網站從中選出一組加密算法與HASH算法,並將自己的身份信息以證書的形式發回給瀏覽器。證書里面包含了網站地址,加密公鑰,以及證書的頒發機構等信息(證書中的私鑰只能用於服務器端進行解密,在握手的整個過程中,都用到了證書中的公鑰和瀏覽器發送給服務器的隨機密碼以及對稱加密算法)


3.獲得網站證書之后瀏覽器要做以下工作:
    a) 驗證證書的合法性(頒發證書的機構是否合法,證書中包含的網站地址是否與正在訪問的地址一致等),如果證書受信任,則瀏覽器欄里面會顯示一個小鎖頭,否則會給出證書不受信的提示。
    b) 如果證書受信任,或者是用戶接受了不受信的證書,瀏覽器會生成一串隨機數的密碼,並用證書中提供的公鑰加密。
    c) 使用約定好的HASH算法計算握手消息(如SHA1),並使用生成的隨機數對消息進行加密,最后將之前生成的被公鑰加密的隨機數密碼,HASH摘要值一起發送給服務器


4.網站接收瀏覽器發來的數據之后要做以下的操作:
    a) 使用自己的私鑰將信息解密並取出瀏覽器發送給服務器的隨機密碼,使用密碼解密瀏覽器發來的握手消息,並驗證HASH是否與瀏覽器發來的一致。
    b) 使用隨機密碼加密一段握手消息,發送給瀏覽器。
    5.瀏覽器解密並計算握手消息的HASH,如果與服務端發來的HASH一致,此時握手過程結束,之后所有的通信數據將由之前瀏覽器生成的隨機密碼並利用對稱加密算法進行加密。

 

從上面的4個大的步驟可以看到,握手的整個過程使用到了數字證書、對稱加密、HASH摘要算法,接下來我們用實際代碼來實現整個過程

 

   四 使用java代碼模擬整個握手過程

          一:准備工作

                          1、創建java證書,

                               C:\> keytool -genkey -alias wangyi -keypass wangyi -keyalg RSA -keysize 1024 -keystore https.keystore -storepass wangyi

                              

                           2、將創建的證書保存到C盤(為了方便演示)

                             C:\>keytool -export -keystore https.keystore -alias wangyi -file https.crt -storepass wangyi

                             
                           
 

          二:代碼實現

                          代碼包含6個類,分別為:

名稱 說明
CertifcateUtils 證書操作類
DesCoder Des對稱加密和解密工具類
HttpsMockBase https父類
HttpsMockClient client類
HttpsMockServer 服務器類
SocketUtils socket工具類

                        

Java代碼   收藏代碼
  1. package httpsmock;  
  2.   
  3. import java.io.ByteArrayInputStream;  
  4. import java.io.FileInputStream;  
  5. import java.io.InputStream;  
  6. import java.security.KeyStore;  
  7. import java.security.PrivateKey;  
  8. import java.security.PublicKey;  
  9. import java.security.cert.CertificateFactory;  
  10. /** 
  11.  * Created by kingj on 2014/8/13. 
  12.  */  
  13. public class CertifcateUtils {  
  14.     public static byte[] readCertifacates() throws Exception{  
  15.         CertificateFactory factory=CertificateFactory.getInstance("X.509");  
  16.         InputStream in=new FileInputStream("c:/https.crt");  
  17.         java.security.cert.Certificate cate=factory.generateCertificate(in);  
  18.         return cate.getEncoded();  
  19.     }  
  20.   
  21.     public static byte[] readPrivateKey() throws  Exception{  
  22.         KeyStore store=KeyStore.getInstance("JKS");  
  23.         InputStream in=new FileInputStream("c:/https.keystore");  
  24.         store.load(in,"wangyi".toCharArray());  
  25.         PrivateKey pk=(PrivateKey)store.getKey("wangyi","wangyi".toCharArray());  
  26.         return pk.getEncoded();  
  27.     }  
  28.   
  29.     public static PrivateKey readPrivateKeys() throws  Exception{  
  30.         KeyStore store=KeyStore.getInstance("JKS");  
  31.         InputStream in=new FileInputStream("c:/https.keystore");  
  32.         store.load(in,"wangyi".toCharArray());  
  33.         PrivateKey pk=(PrivateKey)store.getKey("wangyi","wangyi".toCharArray());  
  34.         return pk;  
  35.     }  
  36.   
  37.     public static PublicKey readPublicKeys() throws  Exception{  
  38.         CertificateFactory factory=CertificateFactory.getInstance("X.509");  
  39.         InputStream in=new FileInputStream("c:/https.crt");  
  40.         java.security.cert.Certificate cate=factory.generateCertificate(in);  
  41.         return cate.getPublicKey();  
  42.     }  
  43.   
  44.     public static  java.security.cert.Certificate createCertiface(byte b[]) throws Exception{  
  45.         CertificateFactory factory=CertificateFactory.getInstance("X.509");  
  46.         InputStream in=new ByteArrayInputStream(b);  
  47.         java.security.cert.Certificate cate=factory.generateCertificate(in);  
  48.         return cate;  
  49.     }  
  50.   
  51.     public static String byte2hex(byte[] b) {  
  52.         String hs = "";  
  53.         String stmp = "";  
  54.         for (int n = 0; n < b.length; n++) {  
  55.             stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));  
  56.             if (stmp.length() == 1) {  
  57.                 hs = hs + "0" + stmp;  
  58.             } else {  
  59.                 hs = hs + stmp;  
  60.             }  
  61.         }  
  62.         return hs.toUpperCase();  
  63.     }  
  64. }  

     

Java代碼   收藏代碼
  1. package httpsmock;  
  2.   
  3. /** 
  4.  * Created by kingj on 2014/8/13. 
  5.  */  
  6. import org.apache.commons.codec.binary.Hex;  
  7.   
  8. import java.security.Key;  
  9. import java.security.SecureRandom;  
  10.   
  11. import javax.crypto.Cipher;  
  12. import javax.crypto.KeyGenerator;  
  13. import javax.crypto.SecretKey;  
  14. import javax.crypto.SecretKeyFactory;  
  15. import javax.crypto.spec.DESKeySpec;  
  16.   
  17. /** 
  18.  * DES Coder<br/> 
  19.  * secret key length:   56 bit, default:    56 bit<br/> 
  20.  * mode:    ECB/CBC/PCBC/CTR/CTS/CFB/CFB8 to CFB128/OFB/OBF8 to OFB128<br/> 
  21.  * padding: Nopadding/PKCS5Padding/ISO10126Padding/ 
  22.  * @author Aub 
  23.  * 
  24.  */  
  25. public class DesCoder {  
  26.   
  27.     /** 
  28.      * 密鑰算法 
  29.      */  
  30.     private static final String KEY_ALGORITHM = "DES";  
  31.   
  32.     private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";  
  33. //  private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/ISO10126Padding";  
  34.   
  35.   
  36.     /** 
  37.      * 初始化密鑰 
  38.      * 
  39.      * @return byte[] 密鑰 
  40.      * @throws Exception 
  41.      */  
  42.     public static byte[] initSecretKey(SecureRandom random) throws Exception{  
  43.         //返回生成指定算法的秘密密鑰的 KeyGenerator 對象  
  44.         KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);  
  45.         //初始化此密鑰生成器,使其具有確定的密鑰大小  
  46.         kg.init(random);  
  47.         //生成一個密鑰  
  48.         SecretKey  secretKey = kg.generateKey();  
  49.         return secretKey.getEncoded();  
  50.     }  
  51.   
  52.     /** 
  53.      * 轉換密鑰 
  54.      * 
  55.      * @param key   二進制密鑰 
  56.      * @return Key  密鑰 
  57.      * @throws Exception 
  58.      */  
  59.     public static Key toKey(byte[] key) throws Exception{  
  60.         //實例化DES密鑰規則  
  61.         DESKeySpec dks = new DESKeySpec(key);  
  62.         //實例化密鑰工廠  
  63.         SecretKeyFactory skf = SecretKeyFactory.getInstance(KEY_ALGORITHM);  
  64.         //生成密鑰  
  65.         SecretKey  secretKey = skf.generateSecret(dks);  
  66.         return secretKey;  
  67.     }  
  68.   
  69.     /** 
  70.      * 加密 
  71.      * 
  72.      * @param data  待加密數據 
  73.      * @param key   密鑰 
  74.      * @return byte[]   加密數據 
  75.      * @throws Exception 
  76.      */  
  77.     public static byte[] encrypt(byte[] data,Key key) throws Exception{  
  78.         return encrypt(data, key,DEFAULT_CIPHER_ALGORITHM);  
  79.     }  
  80.   
  81.     /** 
  82.      * 加密 
  83.      * 
  84.      * @param data  待加密數據 
  85.      * @param key   二進制密鑰 
  86.      * @return byte[]   加密數據 
  87.      * @throws Exception 
  88.      */  
  89.     public static byte[] encrypt(byte[] data,byte[] key) throws Exception{  
  90.         return encrypt(data, key,DEFAULT_CIPHER_ALGORITHM);  
  91.     }  
  92.   
  93.   
  94.     /** 
  95.      * 加密 
  96.      * 
  97.      * @param data  待加密數據 
  98.      * @param key   二進制密鑰 
  99.      * @param cipherAlgorithm   加密算法/工作模式/填充方式 
  100.      * @return byte[]   加密數據 
  101.      * @throws Exception 
  102.      */  
  103.     public static byte[] encrypt(byte[] data,byte[] key,String cipherAlgorithm) throws Exception{  
  104.         //還原密鑰  
  105.         Key k = toKey(key);  
  106.         return encrypt(data, k, cipherAlgorithm);  
  107.     }  
  108.   
  109.     /** 
  110.      * 加密 
  111.      * 
  112.      * @param data  待加密數據 
  113.      * @param key   密鑰 
  114.      * @param cipherAlgorithm   加密算法/工作模式/填充方式 
  115.      * @return byte[]   加密數據 
  116.      * @throws Exception 
  117.      */  
  118.     public static byte[] encrypt(byte[] data,Key key,String cipherAlgorithm) throws Exception{  
  119.         //實例化  
  120.         Cipher cipher = Cipher.getInstance(cipherAlgorithm);  
  121.         //使用密鑰初始化,設置為加密模式  
  122.         cipher.init(Cipher.ENCRYPT_MODE, key);  
  123.         //執行操作  
  124.         return cipher.doFinal(data);  
  125.     }  
  126.   
  127.   
  128.   
  129.     /** 
  130.      * 解密 
  131.      * 
  132.      * @param data  待解密數據 
  133.      * @param key   二進制密鑰 
  134.      * @return byte[]   解密數據 
  135.      * @throws Exception 
  136.      */  
  137.     public static byte[] decrypt(byte[] data,byte[] key) throws Exception{  
  138.         return decrypt(data, key,DEFAULT_CIPHER_ALGORITHM);  
  139.     }  
  140.   
  141.     /** 
  142.      * 解密 
  143.      * 
  144.      * @param data  待解密數據 
  145.      * @param key   密鑰 
  146.      * @return byte[]   解密數據 
  147.      * @throws Exception 
  148.      */  
  149.     public static byte[] decrypt(byte[] data,Key key) throws Exception{  
  150.         return decrypt(data, key,DEFAULT_CIPHER_ALGORITHM);  
  151.     }  
  152.   
  153.     /** 
  154.      * 解密 
  155.      * 
  156.      * @param data  待解密數據 
  157.      * @param key   二進制密鑰 
  158.      * @param cipherAlgorithm   加密算法/工作模式/填充方式 
  159.      * @return byte[]   解密數據 
  160.      * @throws Exception 
  161.      */  
  162.     public static byte[] decrypt(byte[] data,byte[] key,String cipherAlgorithm) throws Exception{  
  163.         //還原密鑰  
  164.         Key k = toKey(key);  
  165.         return decrypt(data, k, cipherAlgorithm);  
  166.     }  
  167.   
  168.     /** 
  169.      * 解密 
  170.      * 
  171.      * @param data  待解密數據 
  172.      * @param key   密鑰 
  173.      * @param cipherAlgorithm   加密算法/工作模式/填充方式 
  174.      * @return byte[]   解密數據 
  175.      * @throws Exception 
  176.      */  
  177.     public static byte[] decrypt(byte[] data,Key key,String cipherAlgorithm) throws Exception{  
  178.         //實例化  
  179.         Cipher cipher = Cipher.getInstance(cipherAlgorithm);  
  180.         //使用密鑰初始化,設置為解密模式  
  181.         cipher.init(Cipher.DECRYPT_MODE, key);  
  182.         //執行操作  
  183.         return cipher.doFinal(data);  
  184.     }  
  185.   
  186.     private static String  showByteArray(byte[] data){  
  187.         if(null == data){  
  188.             return null;  
  189.         }  
  190.         StringBuilder sb = new StringBuilder("{");  
  191.         for(byte b:data){  
  192.             sb.append(b).append(",");  
  193.         }  
  194.         sb.deleteCharAt(sb.length()-1);  
  195.         sb.append("}");  
  196.         return sb.toString();  
  197.     }  
  198.   
  199. }  

 

  

Java代碼   收藏代碼
  1. package httpsmock;  
  2.   
  3. import com.sun.org.apache.bcel.internal.generic.NEW;  
  4.   
  5. import javax.crypto.*;  
  6. import javax.crypto.spec.DESKeySpec;  
  7. import java.security.*;  
  8. import java.security.spec.InvalidKeySpecException;  
  9. import java.util.Random;  
  10.   
  11. /** 
  12.  * Created by kingj on 2014/8/13. 
  13.  */  
  14. public class HttpsMockBase {  
  15.     static PrivateKey privateKey;  
  16.     static PublicKey publicKey;  
  17.   
  18.   
  19.     public static boolean byteEquals(byte a[],byte[] b){  
  20.         boolean equals=true;  
  21.         if(a==null || b==null){  
  22.             equals=false;  
  23.         }  
  24.   
  25.         if(a!=null && b!=null){  
  26.             if(a.length!=b.length){  
  27.                 equals=false;  
  28.             }else{  
  29.                 for(int i=0;i<a.length;i++){  
  30.                     if(a[i]!=b[i]){  
  31.                         equals=false;  
  32.                         break;  
  33.                     }  
  34.                 }  
  35.             }  
  36.   
  37.         }  
  38.         return equals;  
  39.     }  
  40.   
  41.     public static byte[] decrypt(byte data[]) throws Exception{  
  42.         // 對數據解密  
  43.         Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());  
  44.         cipher.init(Cipher.DECRYPT_MODE, privateKey);  
  45.         return cipher.doFinal(data);  
  46.     }  
  47.   
  48.     public static byte[] decrypt(byte data[],SecureRandom seed) throws Exception{  
  49.         // 對數據解密  
  50.         Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());  
  51.         cipher.init(Cipher.DECRYPT_MODE, privateKey,seed);  
  52.         return cipher.doFinal(data);  
  53.     }  
  54.   
  55.     public static byte[] decryptByPublicKey(byte data[],SecureRandom seed) throws Exception{  
  56.         if(publicKey==null){  
  57.             publicKey=CertifcateUtils.readPublicKeys();  
  58.         }  
  59.         // 對數據解密  
  60.         Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());  
  61.         if(seed==null){  
  62.             cipher.init(Cipher.DECRYPT_MODE, publicKey);  
  63.         }else{  
  64.             cipher.init(Cipher.DECRYPT_MODE, publicKey,seed);  
  65.         }  
  66.   
  67.         return cipher.doFinal(data);  
  68.     }  
  69.   
  70.     public static byte[] decryptByDes(byte data[],SecureRandom seed) throws Exception{  
  71.         if(publicKey==null){  
  72.             publicKey=CertifcateUtils.readPublicKeys();  
  73.         }  
  74.         // 對數據解密  
  75.         Cipher cipher = Cipher.getInstance("DES");  
  76.         if(seed==null){  
  77.             cipher.init(Cipher.DECRYPT_MODE, publicKey);  
  78.         }else{  
  79.             cipher.init(Cipher.DECRYPT_MODE, publicKey,seed);  
  80.         }  
  81.   
  82.         return cipher.doFinal(data);  
  83.     }  
  84.   
  85.   
  86.   
  87.   
  88.     public static byte[] encryptByPublicKey(byte[] data, SecureRandom seed)  
  89.             throws Exception {  
  90.         if(publicKey==null){  
  91.             publicKey=CertifcateUtils.readPublicKeys();  
  92.         }  
  93.         // 對數據加密  
  94.         Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());  
  95.         if(seed==null){  
  96.             cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
  97.         }else{  
  98.             cipher.init(Cipher.ENCRYPT_MODE, publicKey,seed);  
  99.         }  
  100.   
  101.         return cipher.doFinal(data);  
  102.     }  
  103.   
  104.     public static String byte2hex(byte[] b) {  
  105.         String hs = "";  
  106.         String stmp = "";  
  107.         for (int n = 0; n < b.length; n++) {  
  108.             stmp = (Integer.toHexString(b[n] & 0XFF));  
  109.             if (stmp.length() == 1) {  
  110.                 hs = hs + "0" + stmp;  
  111.             } else {  
  112.                 hs = hs +"  " + stmp;  
  113.             }  
  114.         }  
  115.         return hs.toUpperCase();  
  116.     }  
  117.   
  118.     public static byte[] cactHash(byte[] bytes) {  
  119.         byte[] _bytes = null;  
  120.         try {  
  121.             MessageDigest md = MessageDigest.getInstance("SHA1");  
  122.             md.update(bytes);  
  123.             _bytes = md.digest();  
  124.         } catch (NoSuchAlgorithmException ex) {  
  125.             ex.printStackTrace();  
  126.         }  
  127.         return _bytes;  
  128.     }  
  129.   
  130.   
  131.   
  132.     static String random(){  
  133.         StringBuilder builder=new StringBuilder();  
  134.         Random random=new Random();  
  135.         int seedLength=10;  
  136.         for(int i=0;i<seedLength;i++){  
  137.             builder.append(digits[random.nextInt(seedLength)]);  
  138.         }  
  139.   
  140.         return builder.toString();  
  141.     }  
  142.   
  143.     static char[] digits={  
  144.             '0','1','2','3','4',  
  145.             '5','6','7','8','9',  
  146.             'a','b','c','d','e',  
  147.             'f','g','h','i','j'  
  148.     };  
  149.   
  150. }  

    

Java代碼   收藏代碼
  1. package httpsmock;  
  2.   
  3. import java.io.DataInputStream;  
  4. import java.io.DataOutputStream;  
  5. import java.net.Socket;  
  6. import java.security.Key;  
  7. import java.security.SecureRandom;  
  8.   
  9. /** 
  10.  * Created by kingj on 2014/8/13. 
  11.  */  
  12. public class HttpsMockClient extends  HttpsMockBase {  
  13.     static DataInputStream in;  
  14.     static DataOutputStream out;  
  15.     static Key key;  
  16.     public static void main(String args[]) throws  Exception{  
  17.         int port=80;  
  18.         Socket s=new Socket("localhost",port);  
  19.         s.setReceiveBufferSize(102400);  
  20.         s.setKeepAlive(true);  
  21.         in=new DataInputStream(s.getInputStream());  
  22.         out=new DataOutputStream(s.getOutputStream());  
  23.         shakeHands();  
  24.   
  25.         System.out.println("------------------------------------------------------------------");  
  26.         String name="duck";  
  27.         writeBytes(name.getBytes());  
  28.   
  29.         int len=in.readInt();  
  30.         byte[] msg=readBytes(len);  
  31.         System.out.println("服務器反饋消息:"+byte2hex(msg));  
  32.         Thread.sleep(1000*100);  
  33.   
  34.   
  35.     }  
  36.   
  37.     private static void shakeHands() throws Exception {  
  38.         //第一步 客戶端發送自己支持的hash算法  
  39.         String supportHash="SHA1";  
  40.         int length=supportHash.getBytes().length;  
  41.         out.writeInt(length);  
  42.         SocketUtils.writeBytes(out, supportHash.getBytes(), length);  
  43.   
  44.         //第二步 客戶端驗證服務器端證書是否合法  
  45.         int skip=in.readInt();  
  46.         byte[] certificate=SocketUtils.readBytes(in,skip);  
  47.         java.security.cert.Certificate cc= CertifcateUtils.createCertiface(certificate);  
  48.   
  49.         publicKey=cc.getPublicKey();  
  50.         cc.verify(publicKey);  
  51.         System.out.println("客戶端校驗服務器端證書是否合法:" +true);  
  52.   
  53.         //第三步  客戶端校驗服務器端發送過來的證書成功,生成隨機數並用公鑰加密  
  54.         System.out.println("客戶端校驗服務器端發送過來的證書成功,生成隨機數並用公鑰加密");  
  55.         SecureRandom seed=new SecureRandom();  
  56.         int seedLength=2;  
  57.         byte seedBytes[]=seed.generateSeed(seedLength);  
  58.         System.out.println("生成的隨機數為 : " + byte2hex(seedBytes));  
  59.         System.out.println("將隨機數用公鑰加密后發送到服務器");  
  60.         byte[] encrptedSeed=encryptByPublicKey(seedBytes, null);  
  61.         SocketUtils.writeBytes(out,encrptedSeed,encrptedSeed.length);  
  62.   
  63.         System.out.println("加密后的seed值為 :" + byte2hex(encrptedSeed));  
  64.   
  65.         String message=random();  
  66.         System.out.println("客戶端生成消息為:"+message);  
  67.   
  68.         System.out.println("使用隨機數並用公鑰對消息加密");  
  69.         byte[] encrpt=encryptByPublicKey(message.getBytes(),seed);  
  70.         System.out.println("加密后消息位數為 : " +encrpt.length);  
  71.         SocketUtils.writeBytes(out,encrpt,encrpt.length);  
  72.   
  73.         System.out.println("客戶端使用SHA1計算消息摘要");  
  74.         byte hash[]=cactHash(message.getBytes());  
  75.         System.out.println("摘要信息為:"+byte2hex(hash));  
  76.   
  77.         System.out.println("消息加密完成,摘要計算完成,發送服務器");  
  78.         SocketUtils.writeBytes(out,hash,hash.length);  
  79.   
  80.   
  81.         System.out.println("客戶端向服務器發送消息完成,開始接受服務器端發送回來的消息和摘要");  
  82.         System.out.println("接受服務器端發送的消息");  
  83.         int serverMessageLength=in.readInt();  
  84.         byte[] serverMessage=SocketUtils.readBytes(in,serverMessageLength);  
  85.         System.out.println("服務器端的消息內容為 :" + byte2hex(serverMessage));  
  86.   
  87.         System.out.println("開始用之前生成的隨機密碼和DES算法解密消息,密碼為:"+byte2hex(seedBytes));  
  88.         byte[] desKey= DesCoder.initSecretKey(new SecureRandom(seedBytes));  
  89.         key=DesCoder.toKey(desKey);  
  90.   
  91.         byte[] decrpytedServerMsg=DesCoder.decrypt(serverMessage, key);  
  92.         System.out.println("解密后的消息為:"+byte2hex(decrpytedServerMsg));  
  93.   
  94.         int serverHashLength=in.readInt();  
  95.         byte[] serverHash=SocketUtils.readBytes(in,serverHashLength);  
  96.         System.out.println("開始接受服務器端的摘要消息:"+byte2hex(serverHash));  
  97.   
  98.         byte[] serverHashValues=cactHash(decrpytedServerMsg);  
  99.         System.out.println("計算服務器端發送過來的消息的摘要 : " +byte2hex(serverHashValues));  
  100.   
  101.         System.out.println("判斷服務器端發送過來的hash摘要是否和計算出的摘要一致");  
  102.         boolean isHashEquals=byteEquals(serverHashValues,serverHash);  
  103.   
  104.         if(isHashEquals){  
  105.             System.out.println("驗證完成,握手成功");  
  106.         }else{  
  107.             System.out.println("驗證失敗,握手失敗");  
  108.         }  
  109.     }  
  110.   
  111.   
  112.     public static byte[] readBytes(int length) throws  Exception{  
  113.         byte[] undecrpty=SocketUtils.readBytes(in,length);  
  114.         System.out.println("讀取未解密消息:"+byte2hex(undecrpty));  
  115.         return DesCoder.decrypt(undecrpty,key);  
  116.     }  
  117.   
  118.     public static void writeBytes(byte[] data) throws  Exception{  
  119.         byte[] encrpted=DesCoder.encrypt(data,key);  
  120.         System.out.println("寫入加密后消息:"+byte2hex(encrpted));  
  121.         SocketUtils.writeBytes(out,encrpted,encrpted.length);  
  122.     }  
  123. }  

   

Java代碼   收藏代碼
  1. package httpsmock;  
  2.   
  3. import javax.net.ServerSocketFactory;  
  4. import java.io.DataInputStream;  
  5. import java.io.DataOutputStream;  
  6. import java.net.ServerSocket;  
  7. import java.net.Socket;  
  8. import java.security.Key;  
  9. import java.security.SecureRandom;  
  10. import java.util.concurrent.ExecutorService;  
  11. import java.util.concurrent.Executors;  
  12.   
  13. /** 
  14.  * Created by kingj on 2014/8/13. 
  15.  */  
  16. public class HttpsMockServer extends HttpsMockBase {  
  17.     static DataInputStream in;  
  18.     static DataOutputStream out;  
  19.     static String hash;  
  20.     static Key key;  
  21.     static ExecutorService executorService= Executors.newFixedThreadPool(20);  
  22.     public static void main(String args[]) throws Exception{  
  23.         int port=80;  
  24.         ServerSocket ss= ServerSocketFactory.getDefault().createServerSocket(port);  
  25.         ss.setReceiveBufferSize(102400);  
  26.         ss.setReuseAddress(false);  
  27.         while(true){  
  28.             try {  
  29.                 final Socket s = ss.accept();  
  30.                 doHttpsShakeHands(s);  
  31.                 executorService.execute(new Runnable() {  
  32.                     @Override  
  33.                     public void run() {  
  34.                         doSocketTransport(s);  
  35.                     }  
  36.                 });  
  37.   
  38.             }catch (Exception e){  
  39.                 e.printStackTrace();  
  40.             }  
  41.         }  
  42.     }  
  43.   
  44.     private static void doSocketTransport(Socket s){  
  45.         try{  
  46.             System.out.println("--------------------------------------------------------");  
  47.             int length=in.readInt();  
  48.             byte[] clientMsg=readBytes(length);  
  49.             System.out.println("客戶端指令內容為:" + byte2hex(clientMsg));  
  50.   
  51.             writeBytes("服務器已經接受請求".getBytes());  
  52.         }catch (Exception ex){  
  53.             ex.printStackTrace();  
  54.         }  
  55.     }  
  56.   
  57.     public static byte[] readBytes(int length) throws  Exception{  
  58.         byte[] undecrpty=SocketUtils.readBytes(in,length);  
  59.         System.out.println("讀取未解密消息:"+byte2hex(undecrpty));  
  60.         return DesCoder.decrypt(undecrpty,key);  
  61.     }  
  62.   
  63.     public static void writeBytes(byte[] data) throws  Exception{  
  64.         byte[] encrpted=DesCoder.encrypt(data,key);  
  65.         System.out.println("寫入加密后消息:"+byte2hex(encrpted));  
  66.         SocketUtils.writeBytes(out,encrpted,encrpted.length);  
  67.     }  
  68.   
  69.     private static void doHttpsShakeHands(Socket s) throws Exception {  
  70.          in=new DataInputStream(s.getInputStream());  
  71.          out=new DataOutputStream(s.getOutputStream());  
  72.   
  73.         //第一步 獲取客戶端發送的支持的驗證規則,包括hash算法,這里選用SHA1作為hash  
  74.         int length=in.readInt();  
  75.         in.skipBytes(4);  
  76.         byte[] clientSupportHash=SocketUtils.readBytes(in,length);  
  77.         String clientHash=new String(clientSupportHash);  
  78.         hash=clientHash;  
  79.         System.out.println("客戶端發送了hash算法為:"+clientHash);  
  80.   
  81.         //第二步,發送服務器證書到客戶端  
  82.         byte[] certificateBytes=CertifcateUtils.readCertifacates();  
  83.         privateKey=CertifcateUtils.readPrivateKeys();  
  84.         System.out.println("發送證書給客戶端,字節長度為:"+certificateBytes.length);  
  85.         System.out.println("證書內容為:" + byte2hex(certificateBytes));  
  86.         SocketUtils.writeBytes(out, certificateBytes, certificateBytes.length);  
  87.   
  88.         System.out.println("獲取客戶端通過公鑰加密后的隨機數");  
  89.         int secureByteLength=in.readInt();  
  90.         byte[] secureBytes=SocketUtils.readBytes(in, secureByteLength);  
  91.   
  92.         System.out.println("讀取到的客戶端的隨機數為:"+byte2hex(secureBytes));  
  93.         byte secureSeed[]=decrypt(secureBytes);  
  94.         System.out.println("解密后的隨機數密碼為:" +byte2hex(secureSeed));  
  95.   
  96.         //第三步 獲取客戶端加密字符串  
  97.         int skip=in.readInt();  
  98.         System.out.println("第三步 獲取客戶端加密消息,消息長度為 :" +skip);  
  99.         byte[] data=SocketUtils.readBytes(in,skip);  
  100.   
  101.         System.out.println("客戶端發送的加密消息為 : " +byte2hex(data));  
  102.         System.out.println("用私鑰對消息解密,並計算SHA1的hash值");  
  103.         byte message[] =decrypt(data,new SecureRandom(secureBytes));  
  104.         byte serverHash[]=cactHash(message);  
  105.   
  106.   
  107.         System.out.println("獲取客戶端計算的SHA1摘要");  
  108.         int hashSkip=in.readInt();  
  109.         byte[] clientHashBytes=SocketUtils.readBytes(in,hashSkip);  
  110.         System.out.println("客戶端SHA1摘要為 : " + byte2hex(clientHashBytes));  
  111.   
  112.         System.out.println("開始比較客戶端hash和服務器端從消息中計算的hash值是否一致");  
  113.         boolean isHashEquals=byteEquals(serverHash,clientHashBytes);  
  114.         System.out.println("是否一致結果為 : " + isHashEquals);  
  115.   
  116.   
  117.   
  118.         System.out.println("第一次校驗客戶端發送過來的消息和摘譯一致,服務器開始向客戶端發送消息和摘要");  
  119.         System.out.println("生成密碼用於加密服務器端消息,secureRandom : "+byte2hex(secureSeed));  
  120.         SecureRandom secureRandom=new SecureRandom(secureSeed);  
  121.   
  122.         String randomMessage=random();  
  123.         System.out.println("服務器端生成的隨機消息為 : "+randomMessage);  
  124.   
  125.         System.out.println("用DES算法並使用客戶端生成的隨機密碼對消息加密");  
  126.         byte[] desKey=DesCoder.initSecretKey(secureRandom);  
  127.         key=DesCoder.toKey(desKey);  
  128.   
  129.         byte serverMessage[]=DesCoder.encrypt(randomMessage.getBytes(), key);  
  130.         SocketUtils.writeBytes(out,serverMessage,serverMessage.length);  
  131.         System.out.println("服務器端發送的機密后的消息為:"+byte2hex(serverMessage)+",加密密碼為:"+byte2hex(secureSeed));  
  132.   
  133.         System.out.println("服務器端開始計算hash摘要值");  
  134.         byte serverMessageHash[]=cactHash(randomMessage.getBytes());  
  135.         System.out.println("服務器端計算的hash摘要值為 :" +byte2hex(serverMessageHash));  
  136.         SocketUtils.writeBytes(out,serverMessageHash,serverMessageHash.length);  
  137.   
  138.         System.out.println("握手成功,之后所有通信都將使用DES加密算法進行加密");  
  139.     }  
  140.   
  141. }  

   

Java代碼   收藏代碼
  1. package httpsmock;  
  2.   
  3. import java.io.ByteArrayInputStream;  
  4. import java.io.DataInputStream;  
  5. import java.io.DataOutputStream;  
  6. import java.io.IOException;  
  7. import java.net.Socket;  
  8. import java.util.Arrays;  
  9.   
  10. /** 
  11.  * Created by kingj on 2014/8/13. 
  12.  */  
  13. public class SocketUtils {  
  14.     public static void close(Socket s){  
  15.         try {  
  16.             s.shutdownInput();  
  17.             s.shutdownOutput();  
  18.         } catch (IOException e) {  
  19.             e.printStackTrace();  
  20.         }  
  21.     }  
  22.   
  23.   
  24.   
  25.     public static byte[] readBytes(DataInputStream in,int length) throws IOException {  
  26.         int r=0;  
  27.         byte[] data=new byte[length];  
  28.         while(r<length){  
  29.             r+=in.read(data,r,length-r);  
  30.         }  
  31.   
  32.         return data;  
  33.     }  
  34.   
  35.     public static void writeBytes(DataOutputStream out,byte[] bytes,int length) throws IOException{  
  36.         out.writeInt(length);  
  37.         out.write(bytes,0,length);  
  38.         out.flush();  
  39.     }  
  40. }  

 

 

    通過運行上述代碼,我們可以看看服務器端和客戶端控制台打印的消息記錄(https握手完成后,整個過程數據傳輸都需要客戶端和服務端使用約定的DES算法對數據進行加密和解密)

    1、服務端消息記錄

客戶端發送了hash算法為:SHA1
發送證書給客戶端,字節長度為:618
證書內容為:  30  8202  66  30  8201  CF  A0030201020204  51  84  FA  AF  300D0609  2A  86  48  86  F70D01010B0500  30  66  310F  300D0603  550406  1306  77  61  6E  67  79  69  310F  300D0603  550408  1306  77  61  6E  67  79  69  310F  300D0603  550407  1306  77  61  6E  67  79  69  310F  300D0603  55040A  1306  77  61  6E  67  79  69  310F  300D0603  55040B  1306  77  61  6E  67  79  69  310F  300D0603  550403  1306  77  61  6E  67  79  69  30  1E  170D  31  34  30  38  31  33  30  35  32  30  35  34  5A  170D  31  34  31  31  31  31  30  35  32  30  35  34  5A  30  66  310F  300D0603  550406  1306  77  61  6E  67  79  69  310F  300D0603  550408  1306  77  61  6E  67  79  69  310F  300D0603  550407  1306  77  61  6E  67  79  69  310F  300D0603  55040A  1306  77  61  6E  67  79  69  310F  300D0603  55040B  1306  77  61  6E  67  79  69  310F  300D0603  550403  1306  77  61  6E  67  79  69  30  81  9F  300D0609  2A  86  48  86  F70D010101050003  81  8D00  30  81  8902  81  8100  89  20  2A  F6  BF  1E  F9  95  F8  E5  E2  C2  C6  14  22  DB  23  10  2F  44  E0  AD0B  FB  89  62  8C  A6  E2  14  52  E7  5D  FE  7B  CC  A4  D2  F4  F9  C5  8E  E0  75  CC  F3  71  E9  29  85  A9  DA  D2  BD  93  73  12  74  2B  4C  D2  74  1A  13  82  64  20  E0  8B  68  FF  9A  F0  6F0C  880F  91  A5  FE  42  44  DE  81  F0  47  C7  67  2001  C7  7E  8B  36  87  E8  1B  7E  6907  D0  39  77  DE  53  D4  F5  67  57  BD  15  8E  51  E5  44  10  CD  BE  81  EB  E3  86  E8  73  B5  1D  1F  FF0203010001  A3  21  30  1F  30  1D0603  55  1D0E04  1604  14  E2  81  F2  3E  81  92  8B  DE  7A  1D  93  A9  28  23  A7  5D  E7  65  63  EB  300D0609  2A  86  48  86  F70D01010B050003  81  810002  E6  BF00  FB  CE  3A  4A  AC  9E  5F  10  6C  4F  FE  44  93  A4  6D  89  BC  4F  CB  25  30  1F  B4  C7  67  E3  E6  A1  1D  66  4B  DA  E4  6D  D8  90  CC  D2  74  34  48  6C  9B  33  2E  C2  4E  9E  AA  470B  9B  4000  7A  59  67  3E  C2  75  1A  A0  7A  48  16  53  D6  C4  53  97080B  F4  23  49  2E06  60  DF  9D  B4  5B  76  B2  AC  35  CF  2E  3C  CA  E3  B6  25  7D  F7  BA  69  6F  15  CE  AF  B4  9D  83  94  2E  5E  37  6E  C5  C2  B9  94  54  DB06  5D  7F  B6  70  1C  91  E6  E3
獲取客戶端通過公鑰加密后的隨機數
讀取到的客戶端的隨機數為:  86  16  A9  65  F6  EC  A3  57  D6  23  A2  43  8F  F4  52  F5  37  14  F9  5B  27  6F  75  A3  25  C9  9E  D4  DD  CC  68  BA03  A2  1B  E6  8D  74  61  3B  28  28  9F  1F  5A  AD  5F  32  4B  40  81  98  54  AC0F  840B  80  BF  53  80  50  1E  A7  24  16  10  2A  2B  6A  8709  86  7C  20  75  20  14  7E  38  F3  FA  76  6207  D1  E1  37  28  93  D9  C1  2F  D4  9B  6E  9A  5205  9A  6D  54  8B  DD  1D  8205  DF  BC  AE  BB  6C  24  F5  6E  BC  F2  DE  26  AB  B1  87  1F  DA  DE  3B  25  1E
解密后的隨機數密碼為:  5B  D4
第三步 獲取客戶端加密消息,消息長度為 :128
客戶端發送的加密消息為 :   32  76  EB  3E  93  E7  F1  590E  67  EB  FA  29  24  5D  F4  A2  3E  78  BE  61  49  B1  4C  91  1A  450A  B7  D7  E0  71  A1  30  C0  12  F905  9C  CF  B9  C9  75  6B  C4  39  3C  EF  5F  1005  75  AD  50  9A09  6F  8A  7F  C0  F4  20  E0  BC  DF  74  90  F3  6A  46  5E  6C  47  FC  16  EC  4D  DD  10  F9  87  ED  E4  47  83  37  B8  6A  5B  5B  B2  17  9306  7707  72  8E  3008  73  59  89  F5  F7  E6  66  89  4F  F7  B6  2B  41  7B  3B  1B  29  63  D0  11  D4  52  60  4A  3B  74  CA  1E
用私鑰對消息解密,並計算SHA1的hash值
獲取客戶端計算的SHA1摘要
客戶端SHA1摘要為 : 01  56  CB  DF  D3  EF  5A  8F  BB  85  BE  15  FB  83  D9  10  1F  64  F6  D8
開始比較客戶端hash和服務器端從消息中計算的hash值是否一致
是否一致結果為 : true
第一次校驗客戶端發送過來的消息和摘譯一致,服務器開始向客戶端發送消息和摘要
生成密碼用於加密服務器端消息,secureRandom :   5B  D4  (使用客戶端第一次傳過來的密碼)
服務器端生成的隨機消息為 : 2355384499
用DES算法並使用客戶端生成的隨機密碼對消息加密
服務器端發送的機密后的消息為:  34  DE  39  CE  7A  280D  4F  44  83  51  2D  C3  EB  4F  1B,加密密碼為:  5B  D4   (使用客戶端第一次傳過來的密碼)
服務器端開始計算hash摘要值
服務器端計算的hash摘要值為 :  DD  3D  66  B5  C8  B6  A2  36  5E  D1  55  9A  B6  F7  C0  39  3C  97  1402
握手成功,之后所有通信都將使用DES加密算法進行加密
--------------------------------------------------------
讀取未解密消息:  9D  2D  C2  D7  5D  2F  3C  F5
客戶端指令內容為:  64  75  63  6B
寫入加密后消息:  52  91  2C  62  E3  B9  5E  80  CF  3D  39  B4  7D  55  B7  3A  97  46  34  98  5603  DA  FC  A9  E1  D1  61  8F  24  64  D8

  

    2、客戶端消息記錄

 

客戶端校驗服務器端證書是否合法:true (校驗證書)
客戶端校驗服務器端發送過來的證書成功,生成隨機數並用公鑰加密
生成的隨機數為 :   5B  D4  (客戶端生成了隨機密碼,用於整個握手過程中)
將隨機數用公鑰加密后發送到服務器
加密后的seed值為 :  86  16  A9  65  F6  EC  A3  57  D6  23  A2  43  8F  F4  52  F5  37  14  F9  5B  27  6F  75  A3  25  C9  9E  D4  DD  CC  68  BA03  A2  1B  E6  8D  74  61  3B  28  28  9F  1F  5A  AD  5F  32  4B  40  81  98  54  AC0F  840B  80  BF  53  80  50  1E  A7  24  16  10  2A  2B  6A  8709  86  7C  20  75  20  14  7E  38  F3  FA  76  6207  D1  E1  37  28  93  D9  C1  2F  D4  9B  6E  9A  5205  9A  6D  54  8B  DD  1D  8205  DF  BC  AE  BB  6C  24  F5  6E  BC  F2  DE  26  AB  B1  87  1F  DA  DE  3B  25  1E
客戶端生成消息為:9080292229
使用隨機數並用公鑰對消息加密
加密后消息位數為 : 128
客戶端使用SHA1計算消息摘要
摘要信息為:01  56  CB  DF  D3  EF  5A  8F  BB  85  BE  15  FB  83  D9  10  1F  64  F6  D8
消息加密完成,摘要計算完成,發送服務器
客戶端向服務器發送消息完成,開始接受服務器端發送回來的消息和摘要
接受服務器端發送的消息
服務器端的消息內容為 :  34  DE  39  CE  7A  280D  4F  44  83  51  2D  C3  EB  4F  1B
開始用之前生成的隨機密碼和DES算法解密消息,密碼為:  5B  D4
解密后的消息為:  32  33  35  35  33  38  34  34  39  39
開始接受服務器端的摘要消息:  DD  3D  66  B5  C8  B6  A2  36  5E  D1  55  9A  B6  F7  C0  39  3C  97  1402
計算服務器端發送過來的消息的摘要 :   DD  3D  66  B5  C8  B6  A2  36  5E  D1  55  9A  B6  F7  C0  39  3C  97  1402
判斷服務器端發送過來的hash摘要是否和計算出的摘要一致
驗證完成,握手成功
------------------------------------------------------------------
寫入加密后消息:  9D  2D  C2  D7  5D  2F  3C  F5
讀取未解密消息:  52  91  2C  62  E3  B9  5E  80  CF  3D  39  B4  7D  55  B7  3A  97  46  34  98  5603  DA  FC  A9  E1  D1  61  8F  24  64  D8
服務器反饋消息:  E6  9C  8D  E5  8A  A1  E5  99  A8  E5  B7  B2  E7  BB  8F  E6  8E  A5  E5  8F  97  E8  AF  B7  E6  B1  82


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM