1. 程式人生 > >區塊鏈入門教程以太坊源碼分析p2p-rlpx節點之間的加密鏈路一

區塊鏈入門教程以太坊源碼分析p2p-rlpx節點之間的加密鏈路一

cti thp 能夠 但是 安全性 開啟 操作 傳輸層安全 使用

RLPx Encryption(RLPx加密)
之前介紹的discover節點發現協議, 因為承載的數據不是很重要,基本是明文傳輸的。
每一個節點會開啟兩個同樣的端口,一個是UDP端口,用來節點發現,一個是TCP端口,用來承載業務數據。 UDP的端口和TCP的端口的端口號是同樣的。 這樣只要通過UDP發現了端口,就等於可以用TCP來連接到對應的端口。
RLPx協議就定義了TCP鏈接的加密過程。
RLPx使用了(Perfect Forward Secrecy), 簡單來說。 鏈接的兩方生成生成隨機的私鑰,通過隨機的私鑰得到公鑰。 然後雙方交換各自的公鑰, 這樣雙方都可以通過自己隨機的私鑰和對方的公鑰來生成一個同樣的共享密鑰(shared-secret)。後續的通訊使用這個共享密鑰作為對稱加密算法的密鑰。 這樣來說。如果有一天一方的私鑰被泄露,也只會影響泄露之後的消息的安全性, 對於之前的通訊是安全的(因為通訊的密鑰是隨機生成的,用完後就消失了)。
前向安全性(引用自維基百科)
前向安全或前向保密(英語:Forward Secrecy,縮寫:FS),有時也被稱為完美前向安全[1](英語:Perfect Forward Secrecy,縮寫:PFS),是密碼學中通訊協議的安全屬性,指的是長期使用的主密鑰泄漏不會導致過去的會話密鑰泄漏。[2]前向安全能夠保護過去進行的通訊不受密碼或密鑰在未來暴露的威脅。[3]如果系統具有前向安全性,就可以保證萬一密碼或密鑰在某個時刻不慎泄露,過去已經進行的通訊依然是安全,不會受到任何影響,即使系統遭到主動***也是如此。
迪菲-赫爾曼密鑰交換
迪菲-赫爾曼密鑰交換(英語:Diffie–Hellman key exchange,縮寫為D-H) 是一種安全協議。它可以讓雙方在完全沒有對方任何預先信息的條件下通過不安全信道創建起一個密鑰。這個密鑰可以在後續的通訊中作為對稱密鑰來加密通訊內容。公鑰交換的概念最早由瑞夫·墨克(Ralph C. Merkle)提出,而這個密鑰交換方法,由惠特菲爾德·迪菲(Bailey Whitfield Diffie)和馬丁·赫爾曼(Martin Edward Hellman)在1976年首次發表。馬丁·赫爾曼曾主張這個密鑰交換方法,應被稱為迪菲-赫爾曼-墨克密鑰交換(英語:Diffie–Hellman–Merkle key exchange)。
迪菲-赫爾曼密鑰交換的同義詞包括:
迪菲-赫爾曼密鑰協商
迪菲-赫爾曼密鑰創建
指數密鑰交換
迪菲-赫爾曼協議
雖然迪菲-赫爾曼密鑰交換本身是一個匿名(無認證)的密鑰交換協議,它卻是很多認證協議的基礎,並且被用來提供傳輸層安全協議的短暫模式中的完備的前向安全性。
描述
迪菲-赫爾曼通過公共信道交換一個信息,就可以創建一個可以用於在公共信道上安全通信的共享秘密(shared secret)。
p2p/rlpx.go源碼解讀
這個文件實現了RLPx的鏈路協議。
鏈接聯系的大致流程如下:
doEncHandshake() 通過這個方法來完成交換密鑰,創建加密信道的流程。如果失敗,那麽鏈接關閉。
doProtoHandshake() 這個方法來進行協議特性之間的協商,比如雙方的協議版本,是否支持Snappy加密方式等操作。
鏈接經過這兩次處理之後,就算建立起來了。因為TCP是流式的協議。所有RLPx協議定義了分幀的方式。所有的數據都可以理解為一個接一個的rlpxFrame。 rlpx的讀寫都是通過rlpxFrameRW對象來進行處理。
doEncHandshake
鏈接的發起者被稱為initiator。鏈接的被動接受者被成為receiver。 這兩種模式下處理的流程是不同的。完成握手後。 生成了一個sec.可以理解為拿到了對稱加密的密鑰。 然後創建了一個newRLPXFrameRW幀讀寫器。完成加密信道的創建過程。

func (t *rlpx) doEncHandshake(prv *ecdsa.PrivateKey, dial *discover.Node) (discover.NodeID, error) {
    var (
        sec secrets
        err error
    )
    if dial == nil {
        sec, err = receiverEncHandshake(t.fd, prv, nil)
    } else {
        sec, err = initiatorEncHandshake(t.fd, prv, dial.ID, nil)
    }
    if err != nil {
        return discover.NodeID{}, err
    }
    t.wmu.Lock()
    t.rw = newRLPXFrameRW(t.fd, sec)
    t.wmu.Unlock()
    return sec.RemoteID, nil
}

initiatorEncHandshake 首先看看鏈接的發起者的操作。首先通過makeAuthMsg創建了authMsg。 然後通過網絡發送給對端。然後通過readHandshakeMsg讀取對端的回應。 最後調用secrets創建了共享秘密。

// initiatorEncHandshake negotiates a session token on conn.
// it should be called on the dialing side of the connection.
//
// prv is the local client‘s private key.
func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remoteID discover.NodeID, token []byte) (s secrets, err error) {
    h := &encHandshake{initiator: true, remoteID: remoteID}
    authMsg, err := h.makeAuthMsg(prv, token)
    if err != nil {
        return s, err
    }
    authPacket, err := sealEIP8(authMsg, h)
    if err != nil {
        return s, err
    }
    if _, err = conn.Write(authPacket); err != nil {
        return s, err
    }

    authRespMsg := new(authRespV4)
    authRespPacket, err := readHandshakeMsg(authRespMsg, encAuthRespLen, prv, conn)
    if err != nil {
        return s, err
    }
    if err := h.handleAuthResp(authRespMsg); err != nil {
        return s, err
    }
    return h.secrets(authPacket, authRespPacket)
}

makeAuthMsg。這個方法創建了initiator的handshake message。 首先對端的公鑰可以通過對端的ID來獲取。所以對端的公鑰對於發起連接的人來說是知道的。 但是對於被連接的人來說,對端的公鑰應該是不知道的。

// makeAuthMsg creates the initiator handshake message.
func (h *encHandshake) makeAuthMsg(prv *ecdsa.PrivateKey, token []byte) (*authMsgV4, error) {
    rpub, err := h.remoteID.Pubkey()
    if err != nil {
        return nil, fmt.Errorf("bad remoteID: %v", err)
    }
    h.remotePub = ecies.ImportECDSAPublic(rpub)
    // Generate random initiator nonce.
    // 生成一個隨機的初始值, 是為了避免重放***麽? 還是為了避免通過多次連接猜測密鑰?
    h.initNonce = make([]byte, shaLen)
    if _, err := rand.Read(h.initNonce); err != nil {
        return nil, err
    }
    // Generate random keypair to for ECDH.
    //生成一個隨機的私鑰
    h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, crypto.S256(), nil)
    if err != nil {
        return nil, err
    }

區塊鏈入門教程以太坊源碼分析p2p-rlpx節點之間的加密鏈路一