深刻理解HTTPS

級別: ★★☆☆☆
標籤:「HTTPS」「CA」「ECC」
做者: snow
審校: QiShare團隊php


前言

感謝偉大的數學家和密碼學家們,讓咱們的網絡處於一個相對安全的環境。html

最近整理了一下 HTTPS 相關的知識,本文中全部的分析是基於 TLS1.2 版本。java

WebTrust

WebTrust 是由全球兩大著名註冊會計師協會 AICPA(美國註冊會計師協會)和 CICA(加拿大註冊會計師協會)共同制定的安全審計標準,主要對互聯網服務商的系統及業務運做邏輯安全性、保密性等共計七項內容進行近乎嚴苛的審查和鑑證。只有經過 WebTrust 國際安全審計認證的根證書才能預裝到主流的瀏覽器中。git

CA機構

CA機構定義

證書頒發機構(CA, Certificate Authority)即頒發數字證書的機構。是負責發放和管理數字證書的權威機構,並做爲電子商務交易中受信任的第三方,承擔公鑰體系中公鑰的合法性檢驗的責任。github

有哪些CA機構

目前全球主流的 CA 機構有 Comodo 、Symantec、GeoTrust、DigiCert、Thawte、GlobalSign、RapidSSL 等,其中 Symantec、GeoTrust 都是 DigiCert 機構的子公司,目前市場上主流的 SSL 證書品牌是 Comodo 證書、Symantec 證書、GeoTrust 證書、Thawte 證書和 RapidSSL 證書,還有一些不知名的證書機構也是能夠頒發數字證書的。算法

國內的 CA 機構主要有中國金融認證中心(CFCA)、沃通(WoSign)、數安時代(GDCA)和安信證書(AnTruet)等。api

對稱加密

定義

採用單鑰密碼系統的加密方法,同一個密鑰能夠同時用做信息的加密和解密,這種加密方法稱爲對稱加密,也稱爲單密鑰加密。瀏覽器

經常使用加密算法

DES、AES、RC二、RC四、RC5 等安全

示例

public class DES {
    
    public static String encrypt(String content, String key) {
        try {
            byte[] encryptionBytes = content.getBytes("UTF-8");
            SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(key.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secureKey = keyFactory.generateSecret(desKey);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, secureKey, random);
            byte[] encryptionBase64Bytes = Base64.getEncoder().encode(cipher.doFinal(encryptionBytes));
            return new String(encryptionBase64Bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String decrypt(String content, String key) {
        try {
            byte[] decryptionBytes = Base64.getDecoder().decode(content);
            SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(key.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secureKey = keyFactory.generateSecret(desKey);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.DECRYPT_MODE, secureKey, random);
            return new String(cipher.doFinal(decryptionBytes), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args) {

        final String key = "this_is_key";
        String content = "九點下班";

        String encryptStr = DES.encrypt(content, key);
        System.out.println("加密:" + encryptStr);

        String decryptStr = DES.decrypt(encryptStr, key);
        System.out.println("解密:" + decryptStr);
    }
}
複製代碼

image.png

一、李雷想要給韓梅梅發送消息,他們約定使用對稱加密的方式把消息進行加密服務器

二、李雷用密鑰把消息加密而後發送給韓梅梅

三、韓梅梅用同一個密鑰解密,而後看到李雷發送給本身的消息

能夠看到使用上面的方式,一旦密鑰泄漏,消息就很容易被破解

非對稱加密

定義

對稱加密算法在加密和解密時使用的是同一個祕鑰,非對稱加密算法須要兩個密鑰來進行加密和解密,這兩個密鑰是公開密鑰(public key,簡稱公鑰)和私有密鑰(private key,簡稱私鑰)。

經常使用加密算法

RSA、ECC 等

示例

public class RSA {

    private static Cipher cipher;

    static {
        try {
            cipher = Cipher.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
    }

    public static void generateKeyPair() {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();
            String publicKeyStr = getKeyString(publicKey);
            String privateKeyStr = getKeyString(privateKey);

            System.out.println("publicKeyStr :" + publicKeyStr);
            System.out.println("privateKeyStr :" + privateKeyStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static PublicKey getPublicKey(String key) throws Exception {
        byte[] keyBytes = Base64.decode(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }


    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes = Base64.decode(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }


    public static String getKeyString(Key key) {
        byte[] keyBytes = key.getEncoded();
        return Base64.encode(keyBytes);
    }


    public static String encrypt(String publicKey, String content) {
        try {
            cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey));
            byte[] encryptBytes = cipher.doFinal(content.getBytes());
            return Base64.encode(encryptBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static String decrypt(String privateKey, String content) {
        try {
            cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKey));
            byte[] decryptBytes = cipher.doFinal(Base64.decode(content));
            return new String(decryptBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void main(String[] args) {

// generateKeyPair();

        final String publicKey = "使用generateKeyPair生成";
        final String privateKey = "使用generateKeyPair生成";

        String content = "九點下班";
        String encryptStr = encrypt(publicKey, content);
        System.out.println("加密:" + encryptStr);
        String decryptStr = decrypt(privateKey, encryptStr);
        System.out.println("解密:" + decryptStr);
    }
}
複製代碼

image.png

一、李雷想要給韓梅梅發送消息,他們約定使用非對稱加密的方式把消息進行加密

二、李雷首先要獲得韓梅梅的公鑰

二、李雷用韓梅梅的公鑰把消息加密而後發送給韓梅梅

三、韓梅梅用本身的私鑰解密,而後看到李雷發送給本身的消息

韓梅梅給李雷發送消息同理。

數字簽名

數字簽名(Digital Signature)是一種功能相似寫在紙上的普通簽名、可是使用了公鑰加密領域的技術,以用於鑑別數字信息的方法。一套數字簽名一般會定義兩種互補的運算,一個用於簽名,另外一個用於驗證。一般咱們使用公鑰加密,用私鑰解密。而在數字簽名中,咱們使用私鑰加密(至關於生成簽名),公鑰解密(至關於驗證簽名)。咱們能夠直接對消息進行簽名(即便用私鑰加密,此時加密的目的是爲了簽名,而不是保密),驗證者用公鑰正確解密消息,若是和原消息一致,則驗證簽名成功。但一般咱們會對消息的散列值簽名,由於一般散列值的長度遠小於消息原文,使得簽名(非對稱加密)的效率大大提升。注意,計算消息的散列值不是數字簽名的必要步驟。

TLS與SSL

TLS(傳輸層安全性協議:Transport Layer Security)及其前身 SSL(安全套接層:Secure Sockets Layer)是一種安全協議,目的是爲互聯網通訊提供安全及數據完整性保障。

咱們訪問個人我的博客 democome.com/,而後用 WireShark 抓包看下 TLS 握手的過程。

WireShark抓包TLS握手

TLS 握手有 RSA 握手、ECDH 握手。經過我下面的抓包分析,下面的示例中使用的是 ECDH 握手。使用 WireShark 進行 ip 過濾

ip.dst == 185.199.109.153 or ip.src == 185.199.109.153

TLS 握手過程以下圖,咱們如今只關注 Protocol 爲 TLSv1.2 的抓包信息:

image.png

經過上面的圖咱們能夠發現,TLS 的握手過程主要分爲如下幾步。

  • Client Hello
  • Server Hello
  • Certificate
  • Server Key Exchange
  • Client Key Exchange

其中涉及到了對稱加密、非對稱加密等算法,咱們來對每一步進行分析。

Client Hello

瀏覽器發送給服務器

image.png

咱們須要關注如下內容:

  • TLS版本:1.2
  • 隨機數:Radnom
  • 瀏覽器支持的加密套件:Cipher Suites

能夠看到瀏覽器支持的 Cipher Suites 有17種,服務器會從中選擇一個。隨機數會在最後計算主密鑰(master key)即對稱加密所使用的密鑰時使用。

Server Hello

服務器發送給瀏覽器

image.png

  • 隨機數:Radnom
  • 服務器選擇的加密套件:Cipher Suite

能夠看到服務器選擇的加密套件是:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

咱們看下一每一部分的含義

ECDHE:密鑰協商算法

RSA:證書公鑰加密算法

AES_128:對稱加密算法、AES的密碼長度

GCM:AES加密模式

SHA256:驗證消息的消息摘要算法(哈希算法)

Certificate

服務器發送給瀏覽器

在 Server Hello 過程當中服務器已經選擇好了加密套件。服務器下發證書,攜帶了 CA 證書鏈和證書的公鑰。在證書鏈最上層有一個根 CA 證書,這個證書存儲在瀏覽器或者操做系統中,由系統直接信任的。

咱們先在瀏覽器中看一下證書鏈以下:

image.png

而後再看一下 macOS 系統根證書,能夠發現最上層的證書是系統信任的。

image.png

瀏覽器驗證服務器證書的過程以下,首先找到找到 democome.com 證書的中級證書頒發機構 Let's Encrypt Authority X3 ,而後再往上找直到根證書,這裏就是 DST Root CA X3。

而後從根證書開始往下去驗證數字簽名。在這個例子中用 DST Root CA X3 的公鑰驗證 Let's Encrypt Authority X3 證書的數字簽名。再用 Let's Encrypt Authority X3 證書的公鑰驗證服務器證書 democome.com 的數字簽名。若是在驗證過程當中任何一個環節失敗,那麼這個證書就是不合法的。

Certificate 這一步驟信息以下

image.png

證書的公鑰以下圖:

image.png

證書籤名以下圖:

證書的簽名用來確保證書沒有被篡改過。

image.png

Server Key Exchange

服務器發送給瀏覽器

服務器選擇的加密套件爲:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 其中 ECDHE(Elliptic Curve Diffie Hellman Ephemeral)用於密鑰協商。這裏涉及到了橢圓曲線加密。橢圓曲線密碼(Elliptic Curve Cryptography,縮寫:ECC)是一種基於橢圓曲線數學的公開密鑰加密算法。ECC 的主要優點是在某些狀況下它比其餘的算法(好比 RSA 加密算法)使用更小的密鑰並提供至關的或更高等級的安全。

image.png

以上 Server Key Exchange 內容咱們重點關注 EC Diffie-Hellman Server Params,能夠看到 Named Curve 這裏選擇的是 x25519 這條曲線。它的原理能夠簡單理解以下:

仍是李雷和韓梅梅要寫信

一、李雷用本身的私鑰 a 算出橢圓曲線上點 Q1,而後把基點 GQ1 發送給韓梅梅

二、韓梅梅用本身的私鑰 b 算出橢圓曲線上點 Q2 發送給李雷

三、根據橢圓曲線計算規則雙方共同計算出的 K 是相同的。

這樣就能夠進行對稱加密了,而且加密的密鑰沒有在網絡上傳遞過。其實這個計算出來的 K 也不是最終對稱加密的密鑰這裏能夠理解爲 premaster key ,最終還會用瀏覽器和服務器雙方的隨機數再進行一個計算(PRF)獲得真正的對稱加密密鑰 master key。

image.png

上圖中的 Pubkey 就能夠理解爲服務器計算的橢圓上一點。

如下內容主要是橢圓曲線加密算法的一些數學原理,不感興趣能夠忽略,直接到 Client Key Exchange 這一步驟。

DH 算法

DH(Diffie–Hellman key exchange)它可讓雙方在徹底沒有對方任何預先信息的條件下經過不安全信道建立起一個密鑰。這個密鑰能夠在後續的通信中做爲對稱密鑰來加密通信內容。

image.png

簡單解釋一下,假如通訊的雙方是 李雷 和 韓梅梅

前提條件:

  • a 是 李雷 的私鑰,b 是 韓梅梅 的私鑰。
  • p 是一個質數,是公開的
  • gp 的一個原根,是公開的

協商過程:

第一步:李雷 根據本身的私鑰 a 計算出本身的 公鑰 A = g^a\mod p

第二步:李雷 將 gpA 發送給 韓梅梅

第三步:韓梅梅 根據本身的私鑰 b 計算出本身的 公鑰 B = g^b\mod p

第四步:韓梅梅 把本身的公鑰 B 發送給 李雷

第五步:李雷 計算對稱加密的密鑰 K=B^a\mod p

第六步:韓梅梅 計算對稱加密的密鑰 K=A^b\mod p

由上圖的推導可知最終計算的 K 是相同的。

具體例子:

李雷 與 韓梅梅 協定使用 p=23以及g=5。 李雷 的私鑰 a=6, 計算A = g^a\mod p併發送給 韓梅梅。 A = 5^6\mod 23 =8 韓梅梅 的私鑰 b=15, 計算B = g^b\mod p 併發送給 李雷。 B = 5^{15}\mod 23 = 19 李雷 計算 K=B^a\mod p K=19^6\mod 23 = 2 韓梅梅 計算 K=A^b\mod p K=8^{15}\mod 23 = 2

能夠看到對稱加密的密鑰 K 並無在 李雷 和 韓梅梅 之間傳輸,可是計算出來的結果是同樣的。

ECC算法

橢圓曲線密碼(Elliptic Curve Cryptography,縮寫:ECC)是一種基於橢圓曲線數學的公開密鑰加密算法。ECC的主要優點是在某些狀況下它比其餘的算法(好比RSA加密算法)使用更小的密鑰並提供至關的或更高等級的安全。

橢圓曲線的方程以下:

y^2 = x^3 + ax + b

橢圓曲線的函數圖像以下:

y^2 = x^3 - x + 1

image.png

y^2 = x^3 + x + 1

image.png

能夠看到是關於 X 軸對稱的。

橢圓曲線運算

過曲線上 A、B 兩點與橢圓曲線交與點 C,點 C 關於 A 軸作對稱,與橢圓曲線的交點定義爲 A+B。

image.png

考慮加法的一種特殊狀況,若是 A = B,也就A(B)是橢圓曲線的切點,這個時候在重複上面的運算獲得 A+A = 2A。

image.png

A 關於 X 軸作對稱獲得的點定義爲 -A。

image.png

下面有兩張動態圖,描述了這一過程:

A+B = C

A+C = D

A+D = E

img

A 和 B 重合演示以下:

img

有了以上 A+B2A 的運算,若是已知橢圓曲線上一點 G ,咱們能夠求出 2G3G=G+2G4G=2G+2G5G=2G+3G 、... kG,可是反過來若是咱們已知 kG ,要想求出 G 是很是困難的。

橢圓曲線的有限域

橢圓曲線加密算法並不是使用實數域,而是使用有限域,那麼咱們把橢圓曲線定義在有限域上。

Ep(a,b) 表示橢圓曲線方程 y^2=x^3+ax+b ,在有限域 Fp 中,表示全部在同餘( mod )意義上知足該方程的 (x, y) 點。

舉例:加入咱們的曲線是 E_{23}(1, 1)p=23,a=1,b=1 。那麼 y^2=x^3+x+1

P(3, 10) 知足 y^2=10^2=100 ,100(mod)23=8x^3+x+1=3^3+3+1=31,31(mod)23=8

因此點 P(3, 10) 在曲線上。

image.png

以上是離散化以後的點。利用橢圓曲線進行加密通訊的過程以下(這裏給出推理過程,涉及到的運算比較複雜,須要的數學知識比較多,我還在研究中):

一、李雷選擇一條曲線 Ep(a,b),取橢圓曲線上一點 G 做爲基點。

二、李雷選擇一個私鑰 k,而後生成公鑰 K=kG

三、李雷把 Ep(a,b) 、公鑰 K 和 基點 G 傳給韓梅梅

四、韓梅梅以上信息,把明文編碼到 Ep(a,b) 上一點 M,併產生一個隨機數 r

五、韓梅梅計算 C_1 = M+rKC_2 = rG

六、韓梅梅把 C_一、C_2 傳給李雷

七、李雷收到信息後,計算 C_1-kC2 結果就是點 M

由於 C_1-kC_2 = M+rK-krG = M+rkG-krG=M

數學概念

有限域

在數學中,有限域(finite field)是包含有限個元素的域。與其餘域同樣,有限域是進行加減乘除運算都有定義而且知足特定規則的集合。有限域最多見的例子是當 p 爲素數時,整數對 p 取模。有限域的元素個數稱爲它的

數學裏面的羣是一類定義了二元運算(咱們稱之爲加法,用符號+表示)的集合。若是想讓集合

[公式]
變成一個羣,咱們必須定義知足以下四條性質的加法:

一、封閉性:若是 ab 屬於 G,那麼 a+b 也屬於 G

二、結合律:(a+b)+c=a+(b+c)

三、存在單位元(注:在二元運算中,單位元指與任意元素運算不改變其值的元素,以實數爲例,乘法單位元爲1,加法單位元爲0)\theta 使得 a+\theta = \theta + a = a

四、每一個元素都存在逆元素,也即對於任意元素 a 存在 b 使得 a+b=\theta

若是咱們添加第五條要求:

五、交換律:a+b=b+a

那麼這個羣就是阿貝爾羣。

Curve25519

在密碼學中,Curve25519 是一種橢圓曲線,被設計用於橢圓曲線迪菲-赫爾曼(ECDH)密鑰交換方法。它是不被任何已知專利覆蓋的最快 ECC 曲線之一。

Curve25519 橢圓曲線方程爲:y^2 = x^3 + 486662x^2 + x,使用基點 x = 9

ECDH

還以 李雷 和 韓梅梅 爲例,把 DH 的交換內容改成曲線上的點

image.png

當咱們選擇 Curve25519 是一種橢圓曲線時,參數是肯定的,G 也是肯定的,因此只交換雙方的公鑰便可。

Client Key Exchange

瀏覽器發送給服務器

同理,這裏的 Pubkey 就能夠理解爲瀏覽器計算的橢圓上一點。這一步和 Server Key Exchange 相似,都是爲了計算對稱加密的密鑰。

image.png

對稱加密通訊

有了上面的基礎,瀏覽器能夠計算出一個對稱加密密鑰,服務器能夠計算出一個對稱加密密鑰,儘管這兩個密鑰沒有在網絡上傳輸,可是能夠保證這兩個密鑰是相同的。這樣使用這個密鑰進行加密就能夠在網絡上進行傳輸了。

以上就是關於 TLS 握手的基本過程,保證了數據在網絡上傳遞的安全性。

X.509

X.509 是密碼學裏公鑰證書的格式標準。X.509 證書已應用在包括 TLS/SSL 在內的衆多網絡協議裏,同時它也用在不少非在線應用場景裏,好比電子簽名服務。X.509 證書裏含有公鑰、身份信息(好比網絡主機名,組織的名稱或個體名稱等)和簽名信息(能夠是證書籤發機構 CA 的簽名,也能夠是自簽名)。對於一份經由可信的證書籤發機構簽名或者能夠經過其它方式驗證的證書,證書的擁有者就能夠用證書及相應的私鑰來建立安全的通訊,對文檔進行數字簽名。

工具

在線畫圖工具

參考文章

SSL證書CA機構 數字證書與網絡安全 數字簽名是什麼? 橢圓曲線加密 Curve25519 橢圓曲線密碼學的簡單介紹 TLS的握手流程 再談HTTPS ECC橢圓曲線加解密原理詳解(配圖) ECC橢圓曲線加密算法:介紹 新手上路:實數上的橢圓曲線和羣論 密碼學基礎2:橢圓曲線密碼學原理分析 HTTPS 溫故知新(五) —— TLS 中的密鑰計算 有限域


瞭解更多iOS及相關新技術,請關注咱們的公衆號:

image

小編微信:可加並拉入《QiShare技術交流羣》。

image

關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)

推薦文章:
淺談 GPU 及 「App渲染流程」
iOS 查看及導出項目運行日誌
Flutter Platform Channel 使用與源碼分析
開發沒切圖怎麼辦?矢量圖標(iconFont)上手指南
DarkMode、WKWebView、蘋果登陸是否必須適配?
iOS 接入 Google、Facebook 登陸(二)
iOS 接入 Google、Facebook 登陸(一)
Nginx 入門實戰 iOS中的3D變換(二)
iOS中的3D變換(一)
WebSocket 雙端實踐(iOS/ Golang)
今天咱們來聊一聊WebSocket(iOS/Golang)
奇舞團安卓團隊——aTaller
奇舞週刊

相關文章
相關標籤/搜索