fabric中的bccsp

Posted by BY on August 25, 2018

BCCSP(blockchain crypto service provider):为fabric项目提供各种加密技术,签名技术,MSP服务模块中就使用到了BCCSP。

基本架构

BCCSP的基本架构如下所示:

1-1

从大致的层次上划分,可分为三层。

BCCSP层

  • 从包结构的角度来看,这一层指的是package bccsp
  • 从文件的角度来看,主要包括bccsp/目录下的*.go文件。

这一层主要将BCCSP的一些特征抽象为interface,只定义方法而不定义实现,实现部分交给其struct具体实现。在这一层中,含interface的文件为bccsp.gokeystore.go;含struct的文件为aesopts.goecdsaopts.gohashopts.goopts.gorsaopts.gosm2opts

bccsp.go

该文件中的interface,可分为两类。一类是bccsp的interface,另一类是第一类中传入参数的interface

2-1

第一类的interface如上图所示。显然,红框的opts表示要传入的参数,并未实现。

下面,对之前的接口传入的参数的定义,同样进行接口操作:

以上属于Go中结构的嵌套。

3-1

4-1

上述文件十分重要,所以梳理出这个文件的整体结构:

6-1

keystore.go

另一个有interface的文件是keystore.go文件。

  • KeyStore表示加密密钥的存储系统。
  • 允许存储和检索bccsp.Key对象。
  • KeyStore可以是只读的,在这种情况下,StoreKey将返回一个错误。

具体如下所示:

5-1

以上的interface部分,只是定义了接口并未对其进行实现,实现部分由将struct实现。

aesopts.go

该文件定义了分组密码算法。要注意的是struct的书写要符合之前interface的定义:

AES128KeyGenOpts包含生成密钥长度为128位的密钥生成选项:

7-1

同理,该文件包含生成密钥长度为192位和256位的密钥生成选项:

8-1

9-1

ecdsaopts.gorsaopts.gosm2opts.go与之同理。

hashopts.go

要说明的是hashopts.go。这个与之前不同之处在于,只需要返回算法标识符:

10-1

11-1

还有一个函数GetHashOpts,根据传入的hashFunction进行识别:

12-1

opts.go

opts.go文件中定义了以上所有算法的常量及所有的struct。下面展示部分常量:

13-1

14-1

15-1

还有新的一些struct,添加了对密钥格式的选项,定义了整体的密钥系统,以sm2为例:

16-1

17-1

18-1

19-1

20-1

除了以上对于算法完整性的实现,也包含了对其他算法的实现。

  • HMACDeriveKeyOpts包含用于HMAC密钥派生的选项:

21-1

  • HMACImportKeyOpts包含用于导入HMAC密钥的选项。

22-1

  • SHAOpts包含用于计算SHA的选项。

23-1

  • X509PublicKeyImportOpts包含从x509证书导入公钥的选项:

24-1

小结

  • 以上为第一层BCCSP的具体介绍

  • 包括接口interface和结构体struct

  • 这一层主要将BCCSP的一些特征抽象为interface,只定义方法而不定义实现,实现部分交给其struct具体实现。

factory层

  • 从包结构的角度来看,指package factory

  • 从文件的角度来看,主要包括bccsp/ factory目录下的*.go文件。

介绍的顺序是从底层调用说起,大致可分为是否包含pkcs11的实现。

opts.go

此文件是整个factory层中最底层调用,包含以下两个函数:

  • GetDefaultOpts为Opts提供默认实现,每次都会返回一个新实例。

  • FactoryName返回提供者的名称。

25-1

factory.go

定义了BCCSPfactory的接口使其获取实例,对BCCSP的初始化和获取:

26-1

27-1

28-1

29-1

nopkcs11.go

此文件介绍了不使用pkcs11而只使用sw的方式。其中:

  1. 在使用工厂接口之前,必须调用InitFactories

  2. 可以接受使用config = nil进行调用,这种情况下会使用一些默认值。

  3. 只有在找不到defaultBCCSP时才返回错误。

30-1

31-1

  • GetBCCSPFromOpts返回根据输入中传递的选项创建的BCCSP。

32-1

swfactory.go

SoftwareBasedFactoryName是基于软件的BCCSP实现的工厂名称:

33-1

  • SWFactory是基于软实现的BCCSP的工厂。此处定义了空结构体,可作为函数接收者来使用。

34-1

  • SwOpts包含SWFactory的选项。

35-1

  • FileKeystoreOpts定义了密钥存储选项的文件格式,可为pem

36-1

pkcs11.go

pkcs11是在nopkcs11的基础上,加入了pkcs11的实现,其工厂选择如下,增加了pkcs11的选项:

37-1

  • nopkcs11相比,初始化略有不同,增加了pkcs11:

38-1

  • GetBCCSPFromOpts返回根据输入中传递的选项创建的BCCSP。略有不同的地方是增加了pkcs11

39-1

pkcs11factory.go

  • PKCS11BasedFactoryName是基于hsm的BCCSP实现的工厂名称

40-1

类似之前swfactory,定义了空的结构体以及Name和Get函数

41-1

42-1

综上,整个factory结构可如下表示:

43-1

这一层主要定义了存储BCCSP实体的全局变量,和初始化这些变量的初始函数。BCCSP采用了工厂模式的设计思想,分为软件加密和硬件加密两种模式,在这一层决定使用哪种加密模式。

impl层

impl层简单的说就是对之前定义的BCCSP真正意义上的实现。

其结构体如下:

44-1

该结构体定义了8种行为的执行者集合,用Map存储不同的执行者。

此处8个定义的相似度极高,以keyGenerators说明。

45-1

从Map中根据Key的类型获取对应的KeyGenerator(具体是哪个struct),然后调用不同KeyGenerator中的KeyGen()函数(此时函数的具体实现根据map中的KeyGenerator是哪一个struct决定)。

Map中的映射关系,在impl中有定义。先对Map进行实例化。在向其中添加对应的key和value,以下为impl文件中的New()方法部分截取

46-1

根据curve的不同,调用不同的KeyGenerator,其中SM2KeyGenOpts在bccsp\opts.go下:

47-1

sm2KeyGenerator在sw\keygen下:

48-1

KeyGenerator接口如下:

49-1

根据接口,进行struct实例化,并选择调用。

50-1

小结

总的来说,impl实现了BCCSP接口,通过impl中各种动作(比如keygen)的执行者(对应keyGenerator ),传入不同的key(可以是不同的Key struct)值,得到对应的struct,从而执行相应的操作。上述代码在这