1)该加密货币现有的P2P流量是否加密?
我选择的是以太坊,该加密货币现有的P2P流量已经加密。
2)介绍一下在使用的加密方案。
以太坊p2p网络可以分为三层,从下到上依次分别为:基于udp的邻居发现层、基于tcp的加密通信层和核心协议层。基于udp的邻居发现层使用Kad (Kademlia p2p网络协议)节点发现机制,与网络中的其他节点进行ping pong握手、交换邻居的方式发现邻居,计算节点之间的距离,动态维护邻居表。基于tcp的加密通信层与节点发现层发现的节点进行握手建立安全加密连接,负责对核心层协议提供的数据进行编解码与加解密、安全传输,rlpx为该层实际使用的协议。核心协议层负责将需要发送的业务数据传入加密通信层,并处理从加密通信层收到的业务数据。
一、RLPx传输协议
以太坊p2p网络采用了RLPx传输协议。
RLPx为基于TCP 的传输协议,用于以太坊节点之间的安全加密通信。
RLPx使用了完全前向保密技术(perfect forward secrecy),通信双方生成随机公私钥对,交换各自的公钥,使用自己的随机私钥和对方的公钥生成共享秘密(shared-secret)。后续使用这个共享秘密对称加密传输的数据,即使一方的私钥被泄露,过去的通信还是安全的。
完全前向保密
完全前向保密(perfect forward secrecy)技术是一种秘钥协商协议,保证即使服务器的私钥被泄露,会话秘钥也不会被泄露。前向保密保护过去的会话抵抗秘钥或密码在未来泄露的威胁。为每一次会话产生唯一的会话秘钥,一个会话秘钥的泄露不会影响其它会话中传输的数据安全性。
Diffie-Hellman秘钥交换协议
Diffie-Hellman秘钥交换是一种在公共信道中安全交换秘钥的方法,由Whitfield Diffie 与Martin Hellman 在1976年提出。双方在没有对方任何预先信息的情况下,能够在不安全的信道上建立共享的私钥。该私钥作为对称秘钥用于加密后续的通信数据。Diffie-Hellman 秘钥交换是一种非认证 秘钥交换协议,但为很多认证协议提供了基础,在传输层临时安全中用于前向保密。
ECDH :Elliptic Curve Diffie-Hellman 椭圆曲线
Diffie-Hellman 秘钥交换协议
ECDHE:(Ephemeral Elliptic Curve Diffie-Hellman)临时椭圆曲线
ECIES(椭圆曲线集成加密方案)用作RLPx协议握手的非对称密钥。在RLPx协议中使用以下EXIES点
RLPx 协议建立连接
通信双方进行加密握手,生成共享秘密创建加密信道,再进行协议握手。后续业务数据在这个加密信道中传输。
发起者(initator ) 为主动开启TCP连接的一个节点,接受者(Recipient)为接受连接的节点。
节点通过底层的节点发现机制获取对方节点的 ip,tcp地址信息。发起者开启tcp连接。
E 为EXIES 非对称加密函数,Rlpx 加密握手协议如下:
authPacket -> E(remote-pubk, S(ephemeral-privk, static-shared-secret ^ nonce) || H(ephemeral-pubk) || pubk || nonce || 0x0)
authResponsePacket- -> E(remote-pubk, remote-ephemeral-pubk || nonce || 0x0)
static-shared-secret = ecdh.agree(privkey, remote-pubk)
加密握手
发起者的加密握手流程如下:
1.生成一个随机数init-nonce
2.通过ecies生成随机秘钥对,随机私钥ephemeral-privk 与随机公钥ephemeral-pubk
3.用自己的私钥privk和对方的公钥remote_pubk生成静态共享秘密static-shared-secrets
4.将生成的共享秘密static-shared-secrets与随机数init-nonce进行异或运算,得到一个哈希值
5.使用自己的随机私钥ephemeral-privk 对该哈希值进行ECDSA签名计算,得到签名sig
6.将签名sig、自己的公钥pubk 、初始nonce 作为认证信息authMsg。
7.对authMsg进行编码,然后再用对方的公钥remote_pubk进行ecies加密,得到认证数据包authPacket,将数据包通过发送给对方节点
8.等待读取对方节点的响应
9.收到对方响应之后,读取数据,使用自己的私钥privk 进行解密,再进行解码,得到认证响应authRespMsg
10.读取响应nonce, 和对方的随机公钥remote-ephemeral-pubk。
接受者加密握手流程:
1.接收方读取对方发送的加密握手数据包。
2.先通过自己的私钥privk解密数据包,然后进行解码,得到认证数据authMsg。
3.获取对方的remote_pubk, 和nonce。
4.生成随机ECDH 秘钥对, 私钥ephemeral-privk 与公钥ephemeral-pubk。
5.通过自己的私钥privk 和对方的公钥remote-pubk生成协商的静态共享秘密static-shared-secrets
6.用nonce对静态共享秘密进行异或运算得到 签名的消息signedMsg
7.用signedMsg 和authMsg中的签名信息,恢复出对方的随机公钥remote-ephemeral-pubk
8.生成随机数responseNonce, 与随机公钥ephemeral-pubk 作为认证响应authRespMsg
9.对authRespMsg进行编码, 然后用对方的公钥remote-pubk进行加密生成认证响应数据authresponsePacket
10.将authResponsePacket 发送给对方
计算共享秘密(shared secret)
发起者和接受者在握手完成之后,通过认证消息authPacket 和认证响应消息authRespPacket 计算协商的连接秘密。该连接秘密只有在当前连接中有效,所以当一方的私钥被泄露之后,之前的通信消息还是安全的。
计算共享秘密步骤如下:
1.用当前连接的随机私钥ephemeral-privk和对端随机公钥emote-ephemeral-pubk计算一个个ECDH共享秘密:
2.计算共享秘密:
3.计算AES秘密:
4.计算消息认证码秘密
5.对发起方(initiator),计算出口连接消息认证码
6.对发起方(initiator), 计算入口连接消息认证码
7.对接收方(Recipient), 计算出口连接消息认证码
8.对接收方(Recipient),计算入口连接消息认证码
9.将对方公钥remote-pubk, aes-secret, mac-secre,egress-mac, ingress-mac 作为当前连接的协商秘密(connection secrets) 用于数据分帧
协议握手
协议握手发送简单的握手信息,检查对方的响应,判断加密握手是否起作用,同时判断对方是否支持snappy压缩。握手成功则建立连接完成。
数据分帧
加密握手成功之后,在此连接上发送的所有业务信息,都通过连接协商秘密(connection secrets) 按一定格式进行数据分帧。
分帧格式:
frame = header || header-mac || frame-data || frame-mac
header = frame-size || header-data || padding
对于要发送的数据,按如下步骤写入tcp连接:
- 如果启用了snappy,则用snappy压缩消息内容
- 将消息大小和类型等写入消息头header
- 计算消息头认证码header-mac
其中left16()为取前16个字节。
- 对消息内容加密,写入加密后的的帧数据 frame-data
- 计算帧消息认证码,并写入
对于从tcp层接受到到数据,按如下步骤读取:
- 读取32个字节的消息头header
- 校验header-mac 是否正确
- 读取消息类型和消息大小
- 校验frame-mac是否正确
- 读取消息内容并使用当前连接的秘密(connection secrets)AES解密
- 如果使用了snappy压缩,则用snappy解压获取消息内容
- 读取完毕,将消息内容交给上层协议处理
通过密文持续更新egress-mac 与ingress-mac 以及header-mac得到消息认证。



