本文主要内容翻译自:The RLPx Transport Protocol,其中添加了一些个人的理解,由于密码学水平有限,不正确之处望指正。另外原文可能已经更新,最新内容请直接阅读原文。

本文档定义了RLPx传输协议,一种基于TCP的用于Ethereum节点间通信的传输协议。该协议适用于任意内容的加密帧,但它通常用于承载devp2p应用程序协议。

节点标识

所有加密操作都基于secp256k1椭圆曲线。每个节点都需要维护一个在会话间保存和复原的静态私钥。建议私钥只能手动重置,例如,通过删除文件或数据库条目。

ECIES加密

ECIES(Elliptic Curve Integrated Encryption Scheme)是在RLPx握手中使用的非对称加密方法。RLPx使用的密码系统是:

  • secp256k1椭圆曲线,生成元\(G\)
  • \(KDF(k,len)\):NIST SP 800-56级联密钥导出函数
  • \(MAC(k,m)\):HMAC使用SHA-256哈希函数
  • \(AES(k,iv,m)\):AES-256加密算法CTR模式

这里原文是AES-128,但是Ethereum源代码中是AES-256,所以本文更改为AES-256

Alice想要发送可以被Bob的静态私钥\(k_B\)解密的加密消息。Alice知道Bob的静态公钥\(K_B\)。

为了加密消息\(m\),Alice生成了一个随机数\(r\),相应的生成了椭圆曲线公钥\(R=r*G\)并计算出共享密钥\(S=P_x\),\((P_x,P_y)=r*K_B\)。接着,\(k_E\mid\mid k_M=KDF(S,32)\)导出加密和认证主密钥,随机生成一个初始向量\(iv\)。Alice向Bob发送加密消息\(R \mid\mid iv \mid\mid c \mid\mid d\),其中\(c=AES(k_E,iv,m)\),\(d=MAC(k_M,iv\mid\mid c)\)。

Bob需要解密消息\(R \mid\mid iv \mid\mid c \mid\mid d\),为此,需要导出共享密钥\(S=P_x\),其中\((P_x,P_y)=k_B*R\),以及导出加密和认证密钥\(k_E \mid\mid k_M=KDF(S,32)\)。Bob通过等式\(d==MAC(k_M,iv\mid\mid c)\)是否成立验证消息后计算\(m=AES(k_E,iv\mid\mid c)\)获取明文消息。

握手

“握手”过程构建了会话阶段中使用的主密钥。握手是在发起端(发起TCP连接请求的节点)和接收端(接受连接的节点)之间完成。

握手协议:

E是上面定义的ECIES非对称加密函数。

补充说明: E代表加密;S代表签名;H代表Hash运算

  1. auth -> E(remote-pubk, S(ephemeral-privk, static-shared-secret ^ nonce) || H(ephemeral-pubk) || pubk || nonce || 0x0) # 由握手发起方发送,向对方发送密钥协商需要的本节点(公钥+临时公钥+随机数)
  2. auth-ack -> E(remote-pubk, remote-ephemeral-pubk || nonce || 0x0) # 接收方回应auth消息,向对方发送密钥协商需要的本节点(临时公钥+随机数),本节点公钥对方已经知道,所以这里不需要发送了。
  3. static-shared-secret = ecdh.agree(privkey, remote-pubk)

握手后值的计算(步骤如下):

  1. ephemeral-shared-secret = ecdh.agree(ephemeral-privkey, remote-ephemeral-pubk)
  2. shared-secret = keccak256(ephemeral-shared-secret || keccak256(nonce || initiator-nonce))
  3. aes-secret = keccak256(ephemeral-shared-secret || shared-secret)
  4. # destroy shared-secret
  5. mac-secret = keccak256(ephemeral-shared-secret || aes-secret)
  6. # destroy ephemeral-shared-secret
  7. Initiator:
  8. egress-mac = keccak256.update(mac-secret ^ recipient-nonce || auth-sent-init)
  9. # destroy nonce
  10. ingress-mac = keccak256.update(mac-secret ^ initiator-nonce || auth-recvd-ack)
  11. # destroy remote-nonce
  12. Recipient:
  13. egress-mac = keccak256.update(mac-secret ^ initiator-nonce || auth-sent-ack)
  14. # destroy nonce
  15. ingress-mac = keccak256.update(mac-secret ^ recipient-nonce || auth-recvd-init)
  16. # destroy remote-nonce
  1. 用临时密钥,一定程度上可以保证前向安全性。后文中有前向安全性的描述。
  2. 握手过程最重要的是协商密钥(对应上面的aes-secret、mac-secret)。
  3. 密钥协商过程中需要知道本节点和对方节点的(公钥+临时公钥+随机数)。这不是绝对的,不同的密钥协商算法有不同的实现方式,但基本上都需要双方交换一些数据,从而分别推到出相同的密钥。

补充一点,整个协商密钥的过程核心是ECDH密钥协商,但ECDH协商的过程前提是要对方是认证过的,可信的,前面的ECIES加密,实际上相当于对消息接收方进行认证,因为只有拥有对应的私钥才能解密消息。

创建加密连接主要流程如下:

  1. 发起端向接收端发起TCP连接,发送auth消息
  2. 接收端接受连接,解密、验证auth消息(检查recovery of signature == keccak256(ephemeral-pubk)
  3. 接收端生成auth-ack消息
  4. 接收端导出密钥,发送第一个数据帧
  5. 发起端接收到auth-ack消息,导出密钥
  6. 发起端发送第一个数据帧(代码中对应Hello packet
  7. 接收端接收并验证数据帧
  8. 发起端接收并验证数据帧
  9. 如果MAC两边都验证通过,加密握手完成。

简单概括就是:建立TCP连接-->密钥协商(auth、auth-ack)-->双发导出相同的密钥-->发送hello(协议协商)-->创建完成。具体实现需要看Ethereum源码。

分帧

auth之后的所有数据包都是分帧传输的。任何一方如果第一帧数据包验证失败都可以断开连接。

分帧传输的主要目的是在单一连接上可靠的支持多路复用协议。其次,因数据包分帧,为消息认证码产生了适当的分界点,使得加密流变得简单了。数据帧通过握手产生的密钥进行验证。

数据帧头部提供了数据包的大小和协议信息。

  1. frame = header || header-mac || frame-data || frame-mac
  2. header = frame-size || header-data || padding
  3. frame-size = size of frame excluding padding, integer < 2**24, big endian
  4. header-data = rlp.list(protocol-type[, context-id])
  5. protocol-type = integer < 2**16, big endian
  6. context-id = integer < 2**16, big endian
  7. padding = zero-fill to 16-byte boundary
  8. frame-content = any binary data
  9. header-mac = left16(egress-mac.update(aes(mac-secret,egress-mac)) ^ header-ciphertext).digest
  10. frame-mac = left16(egress-mac.update(aes(mac-secret,egress-mac)) ^ left16(egress-mac.update(frame-ciphertext).digest))
  11. egress-mac = keccak256 state, continuously updated with egress bytes
  12. ingress-mac = keccak256 state, continuously updated with ingress bytes
  13. left16(x) is the first 16 bytes of x
  14. || is concatenate
  15. ^ is xor

对发送与接收的密文数据不断更新egress-macingress-mac实现消息认证;对头部数据,是通过将加密输出数据的头部与相应的mac进行异或运算(参见header-mac)。这样做是为了确保对明文mac和密文执行统一操作。所有的mac都是以明文形式发送的。

填充字节用于防止缓存区饥饿,使得帧组件按指定区块字节大小对齐。

已知的问题

  • RLPx握手被认为是易破解的,因为aes-secretmac-secret被重复用于读取和写入

    。RLPx连接的两端从相同的密钥,nonce和IV生成两个CTR流。如果攻击者知道一个明文,他们就可以用重用的密钥流破解未知明文。
  • 帧编码提供了用于多路复用的协议类型字段protocol-type,但devp2p未使用该字段。

RLPx传输协议的前向安全性

RLPx使用了(PerfectForwardSecrecy),简单来说。链接的两方都生成随机的私钥,通过随机的私钥得到公钥。然后双方交换各自的公钥,这样双方都可以通过自己随机的私钥和对方的公钥来生成一个同样的共享密钥(shared-secret)。后续的通讯使用这个共享密钥作为对称加密算法的密钥。这样来说。如果有一天一方的私钥被泄露,也只会影响泄露之后的消息的安全性,对于之前的通讯是安全的(因为通讯的密钥是随机生成的,用完后就消失了)。

前向安全性

前向安全或前向保密FS(ForwardSecrecy),有时也被称为完美前向安全PFS(PerfectForwardSecrecy),是密码学中通讯协议的安全属性,指的是长期使用的主密钥泄漏不会导致过去的会话密钥泄漏。前向安全能够保护过去进行的通讯不受密码或密钥在未来暴露的威胁。如果系统具有前向安全性,就可以保证万一密码或密钥在某个时刻不慎泄露,过去已经进行的通讯依然是安全,不会受到任何影响,即使系统遭到主动攻击也是如此。

最后,需要说明一下,这篇文档对RLPx协议进行了简述,具体实现协议还是有很多细节需处理,深入请看以太坊源码。

如果文中有问题或者不对的地方,可关注微信公众号与我交流学习,欢迎指教!

以太坊RLPx传输协议的更多相关文章

  1. Geth命令用法-参数详解 and 以太坊源码文件目录

    本文是对以太坊客户端geth命令的解析 命令用法 geth [选项] 命令 [命令选项] [参数-] 版本 1.7.3-stable 命令 account 管理账户 attach 启动交互式JavaS ...

  2. 死磕以太坊源码分析之rlpx协议

    死磕以太坊源码分析之rlpx协议 本文主要参考自eth官方文档:rlpx协议 符号 X || Y:表示X和Y的串联 X ^ Y: X和Y按位异或 X[:N]:X的前N个字节 [X, Y, Z, ... ...

  3. 通俗讲解:PoW共识机制与以太坊的关系、Ghost协议 及 PoS共识机制的变种---Casper

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

  4. 以太坊中的Ghost协议

    https://blog.csdn.net/t46414704152abc/article/details/81191804 写得超好,终于弄懂了什么是叔块,怎么确定哪条链最长,以太坊与比特币出块的差 ...

  5. 使用 Go-Ethereum 1.7.2搭建以太坊私有链

    目录 [toc] 1.什么是Ethereum(以太坊) 以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约.开源的底层系统,以太坊从诞生到2017年5月,短短3年半时间,全球 ...

  6. C#以太坊基础入门

    在这一部分,我们将使用C#开发一个最简单的.Net控制台应用,来接入以太坊节点,并打印 所连接节点旳版本信息.通过这一部分的学习,你将掌握以下技能: 如何使用节点仿真器 如何在命令行访问以太坊节点 如 ...

  7. android和java以太坊开发区块链应用使用web3j类库

    如何使用web3j为Java应用或Android App增加以太坊区块链支持,教程内容即涉及以太坊中的核心概念,例如账户管理包括账户的创建.钱包创建.交易转账,交易与状态.智能合约开发与交互.过滤器和 ...

  8. 转:使用 Go-Ethereum 1.7.2搭建以太坊私有链

    使用 Go-Ethereum 1.7.2搭建以太坊私有链 目录 [toc] 1.什么是Ethereum(以太坊) 以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约.开源的底 ...

  9. 以太坊预言机与WEB API(原创,转载请说明原址)

    什么是预言机? 从链外获得数据,提供区块链与现实世界事件之间的连接,提供外部信息的平台 预言机自身也是一种智能合约,它允许区块链连接到任何现有的API 是这个预言机去调用各种 WEB API的接口 这 ...

随机推荐

  1. HTTP请求代理类(GET 、 POST 、PUT 、DELETE)

    package com.jm.http.tools; import java.io.BufferedReader; import java.io.IOException; import java.io ...

  2. 正确写网站title、keywords、description

    一.title title,也就是标题,是在浏览器上面显示出来的,方便用户了解这个页面的内容;特别是搜索引擎判断你网页内容的主要根据.搜索引擎就很大部分是依靠网站title来判断你网站是关于什么内容的 ...

  3. Codeforces Gym101518F:Dimensional Warp Drive(二分+高斯消元)

    题目链接 题意 给出一个11元组A和11元组B,给出n个11元方程,每个方程有一个日期,要让A变成B,问最少需要日期多少才可以变. 思路 因为日期满足单调性,所以可以二分答案.判断的时候就是高斯消元套 ...

  4. 用CSS3 vh 简单实现DIV全屏居中

    vh.vw.vmin.vmax介绍 vw:视窗宽度的百分比(1vw 代表视窗的宽度为 1%)vh:视窗高度的百分比vmin:当前 vw 和 vh 中较小的一个值vmax:当前 vw 和 vh 中较大的 ...

  5. 职业生涯之完成OCM考试后的感想

    背景知识:关于OCM认证,百科是这样描述的: Oracle Certified Master(OCM) 大师认证资质是Oracle认证的最高级别.此认证是对技术.知识和操作技能的最高级别的认可.Ora ...

  6. Html5学习导航

    给大家推荐一下学习研究HTML5必备的一些个网站,更加有利于大家对HTML5的学些和研究.如果各位童鞋还有更多的,欢迎投递资源给我们,也可以支持我们,让我们利用大家的力量收集更多的HTML5学习资料, ...

  7. 第八章 Fisco Bcos 国密版本的部署、控制台搭建、合约的部署、sdk 调用

    鉴于笔者以前各大博客教程都有很多人提问,早期建立一个技术交流群,里面技术体系可能比较杂,想了解相关区块链开发,技术提问,请加QQ群:538327407 参考资料 证书说明:https://mp.wei ...

  8. [NOIP2009]靶形数独 题解

    407. [NOIP2009] 靶形数独 时间限制:5 s   内存限制:128 MB [问题描述] 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低. ...

  9. Java编程思想:为什么要使用内部类

    public class Test { public static void main(String[] args) { Callbacks.test(); } } /* 为什么需要内部类: 1.可以 ...

  10. Code Review最佳实践

    我一直认为Code Review(代码审查)是软件开发中的最佳实践之一,可以有效提高整体代码质量,及时发现代码中可能存在的问题.包括像Google.微软这些公司,Code Review都是基本要求,代 ...