背景

最近应公司项目需求,需要对fabric中的加密相关模块进行改造,主要目的是使fabric底层加密服务支持国密算法sm2、sm3以及sm4等。借这次机会,顺便熟悉一下fabric加密模块的源码实现,故此处简单记录了国密改造的整个过程。

fabric tag: 1.4.1

国密改造整体方案

msp是基于数字证书的成员身份管理,会调用bccsp即证书服务完成签名验签等功能。Fabric提供国密算法服务,需要同时使用基于国密的数字证书服务,以便使用数字证书时,能验证国密的数字签名,辨别用户身份。

bccsp模块对上层抽象出了区块链密码服务,包含非对称加密、对称加密、数字签名算法、摘要计算,以及各种算法对于的密钥生成和导入。不同的加密算法需要实现bccsp中定义的接口,以向上层提供加密服务。目前,bccsp中支持标准加密的软实现和标准加密的硬实现。提供国密算法服务,就需要国密算法实现,实现bccsp模块中定义的接口。

设计gm接口实现国密库的可插拔,实现使用不同的国密库的目的,利用gm接口实现bccsp中的国密插件,在底层国密库更换时,国密插件和Fabric上层模块无需修改。

为每一个国密实现都进行一次封装,形成各自的gm adapter,满足gm接口。国密实现可以是C语言的动态链接库,可以是Go语言模块,甚至可以是基于加密机提供的RPC加密服务接口。

设计证书接口实现证书库的可插拔,实现使用不同证书库的目的。利用证书接口实现证书操作函数,fabric中所有证书操作,都调用封装的证书函数,在使用不同证书库时,fabric上层模块无需再适配证书库。

为每一个证书库都进行一次封装,形成各自的x509 cert adapter,为了让Fabric同时支持国密和标准加密,需要封装Go标准库中的证书操作,以及国密证书库,形成2个不同的插件。

准备工作:

确定 base 分支

熟悉底层加密实现库

  1. C 语言的动态链接库
  2. Go 语言实现
  3. 加密机提供的RPC加密服务接口

模块拆分

先来总体看一下fabric进行国密改造会涉及到的主要模块

java 国密改造如何做 国密改造背景_fabric

如图所示,从上往下,首先是上层调用模块,这一块主要是msp等模块,为fabric提供成员加密服务,它的实现依赖于BCCSP模块和X509模块。

我们先看右边,BCCSP模块主要是实现四套接口,分别是BCCSP接口、opts接口、key接口以及keystore接口,其中以BCCSP接口为主,它包含了加解密、签名验签等主要方法,其他三套接口为辅,主要包含了用于密钥管理和存储的一些方法。

接着往下,BCCSP模块有两套实现,一套是标准加密,它直接依赖于Go SDK原生的加密库,另一套是国密实现,需要依赖于第三方的提供的底层加密库,分为硬实现和软实现,其中硬实现就是加密机,软实现现在主要有G语言实现和C语言动态链接库实现两种。

考虑到fabric定义的BCCSP接口并不直接兼容于第三方提供的加密接口,因此需要做一个国密适配器,主要用于适配上层的BCCSP模块和底层的第三方加密库,这个国密适配器主要包含了SM2、SM3以及SM4三种国密算法的适配。

然后我们看一下左边,X509模块主要提供的是有关证书的一系列方法。在这里fabric原先默认是使用标准X509的,底层直接调用的是Go SDK 原生的加密库。为了让X509支持国密的同时也兼容标准加密,这里我们就把证书相关的接口抽象出来,定义为X509接口。然后底层采用两套实现,标准加密和非国密实现,标准加密依旧是直接调用原生Go SDK标准加密库,而国密则是调用第三方的国密库。

需要说明的是,在调用BCCSP模块的加密服务时,如果选择国密算法,需要加载一个国密的插件,而如果是标准加密,则不需要加密国密插件;在调用X509模块的证书服务时,不管是国密X509证书还是标准X509证书均需要加密X509插件。具体选择国密还是标准加密算法可通在orderer、peer和cli的配置文件中的配置项进行指定。

方法和接口一览

上面已经把fabirc国密改造整体涉及到的模块简单介绍了一下,下面我通过们一张图来看一下这些模块具体涉及到的接口和方法以及代码的调用逻辑等。

java 国密改造如何做 国密改造背景_java 国密改造如何做_02

高清大图请戳这里

fabric ca 国密改造

Fabric-ca国密支持改造,主要是指Fabric-ca端通过改造使其可以用以生成国密公私钥对、签发、吊销、查询国密类型的证书。证书申请和签发的流程如下图所示,所有改造工作都围绕证书申请和签发的流程展开的:

java 国密改造如何做 国密改造背景_bc_03

Fabric-ca主要是调用Fabric的bccsp(blockchain cryptographic service provider,区块链加密服务提供者)模块来完成加解密及签名验签的工作。

Fabric-ca client端主要负责国密证书的请求签发以及存储国密证书链的工作。对于请求国密证书,client端首先生成国密的公私钥对,并把公钥编码到生成证书的请求中,发送生成国密证书的请求给Fabric-ca的server端。存储国密的证书链则需要使用支持国密适配的x509来解析证书,并写入到client端本地路径中。

Fabric-ca server端主要负责国密证书的签发、吊销、查询等功能。启动时加载自身的国密证书。在接收到签发请求时,调用国密的签名方法来对证书请求进行签名,并返回国密证书给client端。

改造要点:

  1. Fabric-ca/lib:主要是接口的实现,主要在解析申请证书请求以及签发证书流程要替换为国密算法;
  2. Fabric-ca/util:该包数据工具类,主要在证书的编解码等操作中扩展国密算法;
  3. Fabric-ca/vendor:因为CA沿用Fabric中的BCCSP套件,所以需要替换对Fabric的包的引用,提供对国密算法的支持。

具体接口和方法一览

java 国密改造如何做 国密改造背景_java 国密改造如何做_04

高清大图请戳这里

fabric sdk 国密改造

关于README可以参考此处

不过我觉得意义不大,无非是怎么下载下来这个项目,然后跑一下测试

因此我又自己写了个使用说明文档,可以参考此处

在改造 SDK 之前,我们先来看一下SDK的目录结构

2. SDK项目介绍

首先介绍一下sdk项目的架构。

├── internal
├── pkg
├── scripts
├── test
└── third_party

其中internal和third_party包含fabric相关核心代码。pkg为sdk核心代码,对外提供接口进行服务。

internal文件夹

└── github.com
└── github.com
    └── hyperledger
        ├── fabric
        │   ├── bccsp
        │   ├── common
        │   ├── core
        │   ├── discovery
        │   ├── gossip
        │   ├── msp
        │   ├── protoutil
        │   ├── sdkinternal
        │   └── sdkpatch
        └── fabric-ca
            ├── api
            ├── lib
            ├── sdkpatch
            └── util

third_party文件夹:

└── github.com
└── github.com
    └── hyperledger
        └── fabric
            ├── common
            ├── core
            └── internal

大概就是这样,废话不多说,直接开始改吧

添加国密底层实现库 mod

添加国密插件和X509插件

添加gmfactory及相关接口

定义公私钥基础类型并替换原有的公私钥

将原生的 X509 库替换为自定义的 x509 库

2.x 不再支持RSA、去掉了插件plugin实现方式

添加一个orderer字段,用于指定orderer配置