去中心化的互联网,首先需要革CA(Certification Authority)的命
1977年,MIT教授 Rivest, Shamir 和 Adleman 发明了三人名字命名的RSA算法,开创了非对称加密算法实用化的新时代。
2002年,Rivest, Shamir 和 Adleman 三人获得当年的图灵奖。
![](https://img.haomeiwen.com/i7209287/6190f4a245af16d7.jpg)
非对称加密
对于外行来说非对称密码算法比较玄妙,通常我们容易接受『一把钥匙开一把锁』,但对于非对称加密算法来说这里变成了『两把钥匙:一把上锁,一把解锁』
非对称加密解密
对于外行来说非对称密码算法比较玄妙,通常我们容易接受『一把钥匙开一把锁』,但对于非对称加密算法来说这里变成了『两把钥匙:一把上锁,一把解锁』
![](https://img.haomeiwen.com/i7209287/c155faf1b9794c2c.jpg)
参考之前专门写过一篇 加解密(Encryption)& 哈希(Hash)算法----入门指引
非对称加密算法(Asymmetric Cryptography)是现代密码学的绝对的基石。基于非对称加密算法,我们伟大的程序员们发明出了很多有意思的东西:
- 利用 非对称加密 + 对称加密 + 哈希,我们搞出了『数字签名』。
- 利用 非对称加密 + 密钥交换 + 对称加密 + 哈希,我们搞出了SSL/TLS 和 HTTPS。
- 利用 数字签名 + HTTPS,他们搞出了CA(Certification Authority),躺着数钱。
- 利用 非对称加密 + 哈希 + P2P,中本聪搞出了Bitcoin。
那么,如果DHT(Distributed Hash Table)
遇上 非对称加密 + 密钥交换 + 对称加密 + 哈希
会有什么有趣的东西产生呢?
Certification Authority
我们知道,传统的TLS/SSL需要一个层级化的CA系统,类似于一个传销系统的金字塔,根证书(Root CA)给下一层CA签名做签名,最后一层CA给网站做签名。
![](https://img.haomeiwen.com/i7209287/ceed1498d9472b7d.jpg)
这样就导致了,如果你能控制一个CA,那么很多中间人攻击的勾当就可以悄无声息的进行了。参见:
人构成的组织,反而成为了最大的漏洞。
继续聊下去之前,我们必须提一下DH算法https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange。我们不关心他的原理,简单来说,这个算法实现了这么一个功能:
DH(A.Public, B.Private) == DH(B.Public, A.Private)
通过这个几乎可以和RSA比肩的伟大发明,Alice可以仅获取Bob的Public Key并结合自己的Private Key来计算出一个和Bob用同样方式计算的相同密钥。
那么剩下的问题就在于如何防止在获取Bob的Public Key的时候被调包,也就是黑客们常说的MITM攻击(Man-in-the-middle attack)。
CA在HTTPS中的作用主要是作为一个中介,防止MITM。大致方式就是浏览器或操作系统把常见的CA的公钥放在预先存起来。访问使用HTTPS的网站的时候通过相应的根证书进行验证。
![](https://img.haomeiwen.com/i7209287/3d9b4159fc41ff71.jpg)
Decentralize
在构建CovenantSQL的时候我们对这个问题进行了思考,于是抛弃了CA创造了DH-RPC。
DH-RPC = DHT + ECDH + RPC
在DH-RPC里我们都用NodeID来作为URI(Uniform Resource Identifier),NodeID是通过Node的PublicKey上一个256位的随机数(NodeNonce
)做两层不同的哈希生成的。
NodeID := sha256(blake2b-512(NodePublicKey + Uint256Nonce))
生成的NodeID大致长这个样子:
0000000004e249292693ee2eb89e1cfc4b05a211f0b0ff0ecbb9d5bc155c078f
把NodeID:Addr
和 NodeID:PublicKey
存储在DHT上,为了防止针对DHT的各种女巫攻击 和 日食攻击,我们参考Bitcoin的思想,把NodeID前面连续的0
的个数定义为难度,并且可以对允许存储在DHT上的NodeID难度进行一定的最低限制。
我们采用了Bitcoin使用的Elliptic Curve Secp256k1
作为非对称加密算法。AES-256-CBC
作为对称加密算法。
首先,Alice通过可信途径获取到Bob的NodeID,并在DHT上查询出Bob的网络地址和公钥。此时Alice已经得到了DH算法所需的Alice的私钥、Bob的公钥。
Alice向Bob发起连接,在RPC的TCP连接建立完成之后,连接发起方(Alice)首先会把一个自己的NodeID
、NodeNonce
发送给对端(Bob)。Bob收到Alice的NodeID
之后通过查询DHT获取到Alice之前存储在DHT上的Alice.PublicKey
并缓存在本地。Bob通过Alice发过来的NodeNonce
和DHT上获取的Alice.PublicKey
可以验证Alice的公钥是否是约定的算法生成的。此时Bob也获取到了DH算法所需的Bob的私钥、Alice的公钥。此时的Alice和Bob的通信就是经过高强度加密并且P2P的了。
流程图如下:
![](https://img.haomeiwen.com/i7209287/b9610a81cf58a4f8.jpg)
如果有黑客尝试覆盖Alice在DHT上的信息的方式进行MITM
,由于NodeNonce
验证NodeID
和ECDH
的特性,黑客在没有Alice.PrivateKey
的前提下是没有办法获取到通信加密用的对称密钥的。
当然,重放攻击等常见攻击手法也是在框架中进行了防御,不在我们的重点讨论之内。
Features
CovenantSQL几乎所有的网络通信都是构建在DH-RPC上的,其它DH-RPC的特性还包括:
-
100% compatible with Go net/rpc standard.
-
ID based routing and Key exchange built on Secure Enhanced DHT.
-
use MessagePack for serialization which support most types without writing
Marshal
andUnmarshal
. -
Crypto Schema
-
Use Elliptic Curve Secp256k1 for Asymmetric Encryption
-
ECDH for Key Exchange
-
PKCS#7 for padding
-
AES-256-CBC for Symmetric Encryption
-
Private key protected by master key
-
Annoymous connection is also supported
-
DHT persistence layer has 2 implementations:
-
BoltDB based simple traditional DHT
-
Kayak based 2PC strong consistent DHT
-
Connection pool based on Yamux, make thousands of connections multiplexed overOne TCP connection.
Example
示例写了一个简单的P2P聊天节点,简单的改造一下应该就可以构建一个去中心化的聊天App了。
package main
import (
"bufio"
"fmt"
"os"
"strings"
"github.com/CovenantSQL/CovenantSQL/conf"
"github.com/CovenantSQL/CovenantSQL/proto"
"github.com/CovenantSQL/CovenantSQL/route"
"github.com/CovenantSQL/CovenantSQL/rpc"
"github.com/CovenantSQL/CovenantSQL/utils/log"
)
// TestService to be register to RPC server
type TestService struct {
}
func NewTestService() *TestService {
return &TestService{}
}
func (s *TestService) Talk(msg string, ret *string) error {
fmt.Println(msg)
resp := fmt.Sprintf("got %s", msg)
*ret = resp
return nil
}
func main() {
//log.SetLevel(log.DebugLevel)
conf.GConf, _ = conf.LoadConfig(os.Args[1])
log.Debugf("GConf: %#v", conf.GConf)
// Init Key Management System
route.InitKMS(conf.GConf.PubKeyStoreFile)
// Register DHT service
server, err := rpc.NewServerWithService(rpc.ServiceMap{
"Test": NewTestService(),
})
if err != nil {
log.Fatal(err)
}
// Init RPC server with an empty master key, which is not recommend
addr := conf.GConf.ListenAddr
masterKey := []byte("")
server.InitRPCServer(addr, conf.GConf.PrivateKeyFile, masterKey)
// Start Node RPC server
go server.Serve()
// Register Node public key, addr to Tracker(BP)
for _, n := range conf.GConf.KnownNodes {
client := rpc.NewCaller()
reqA := &proto.PingReq{
Node: n,
}
respA := new(proto.PingResp)
err = client.CallNode(conf.GConf.BP.NodeID, "DHT.Ping", reqA, respA)
if err != nil {
log.Fatal(err)
}
log.Debugf("respA: %v", respA)
}
// Read target node and connect to it
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("Input target node ID: ")
scanner.Scan()
if scanner.Err() == nil {
target := proto.NodeID(strings.TrimSpace(scanner.Text()))
pc := rpc.NewPersistentCaller(target)
log.Debugf("connecting to %s", scanner.Text())
fmt.Print("Input msg: ")
for scanner.Scan() {
input := scanner.Text()
log.Debugf("get input %s", input)
repSimple := new(string)
err = pc.Call("Test.Talk", input, repSimple)
if err != nil {
log.Fatal(err)
}
log.Infof("resp msg: %s", *repSimple)
}
}
}
Tracker代码请移步这里:CovenantSQL/CovenantSQL ,欢迎关注DH-RPC的Github:
https://github.com/CovenantSQL/CovenantSQL/tree/develop/rpc
最新公告通知
第 8 期 【Python自动化运维进阶】正在火热招生中
![](https://img.haomeiwen.com/i7209287/3c7897a897b63482.png)
网友评论