14. 加密服务支持

14.1. 加密算法

14.1.1. 概述

长安链使用多种密码学算法为链上成员及节点提供认证鉴权和隐私保护。

14.1.2. 丰富的隐私保护、认证鉴权能力

长安链使用传统的签名算法,配合证书体系和TLS协议,为区块链上的通信提供可靠性保障和基本的隐私保护。

  • 长安链在对节点、用户进行认证鉴权时,使用证书体系,把节点、用户所属的组织、拥有的身份等信息都写入证书中,并签名防止篡改。证书中使用的签名算法可以在SM2-SM3国密签名算法套件、ECDSA-SHA256国际标准算法套件中进行选择。

  • 长安链支持TLS协议,在传输时为数据提供隐私保护和完整性校验。除了国际标准的TLS签名算法套件之外,还支持SM2-SM3签名算法套件在TLS协议中的使用。

14.1.2.1. 密码算法基本组件

长安链为智能合约提供了多种密码算法的调用接口:

  • 签名:国密SM2、ECDSA、ED25519等;

  • 非对称加密:国密SM2、ElGamal、ECIES等;

  • 对称加密:国密SM4、AES等,配合GCM、CBC等分组模式;

  • 哈希:国密SM3、SHA2系列、SHA3系列等。

长安链支持多种密码算法引擎, 并支持可选配置:

14.1.2.2. 同态加密

长安链在合约环境中支持Paillier同态加密算法,提供对密文进行加、减、乘运算的能力,支持负数。

14.1.2.3. 零知识证明

长安链引入Bulletproofs零知识证明算法,配合Pedersen承诺算法,在支持在链上对密文进行加、减、乘运算的同时,为计算结果提供范围证明,达到不解密获取明文就能判断计算结果合法性的效果。

14.1.2.4. HIBE

长安链使用Boneh-Boyen-Goh的HIBE算法,从算法上为密文的解密能力提供一个树形权限管理结构,在无需可信任的第三方的情况下实现了细粒度的属性读权限管理体系。

以上提及的密码学算法会逐步开源。



14.2. 硬件加密

14.2.1. 概述

目前大多数区块链项目,用户私钥和节点私钥通常以文件的形式存放在硬盘上,虽然文件可以通过口令进行加密存储,但仍然存在被窃取和破译风险,在某些金融和政务场景下 不符合安全、合规的要求。为了满足以上需求,长安链支持对接硬件加密设备,通过硬件设备对私钥进行安全存储;并通过硬件密码服务处理加密和签名操作。节点服务、CA证书服务以及sdk均可以选择硬件密码设备进行加密或签名。

14.2.2. 整体设计

为了保证不强制绑定特定厂商硬件密码设备,设计上采用pkcs11接口来对接硬件密码设备,提供私钥保护和加密功能。
私钥生命周期管理依托于符合国密局要求的硬件密码设备提供,其中加密/签名操作调用栈如下:

硬件密码设备:硬件加密机,加密卡等
设备接入层:硬件密码设备接入方式和接入配置, 需要支持pkcs11标准
密码接口层:屏蔽底层设备调用,为上层应用提供统一的密码服务。
密码应用层:加密或签名应用,如交易签名,共识签名等。

14.2.2.1. 硬件密码设备

密码设备厂商提供, 略

14.2.2.2. 设备接入层

密码设备厂商提供,略

14.2.2.3. 密码接口层

14.2.2.3.1. 密码接口设计
// 私钥签名接口
type PrivateKey interface {

   // 私钥签名
   Sign(data []byte) ([]byte, error)

   SignWithOpts(data []byte, opts *SignOpts) ([]byte, error)

   // 返回公钥
   PublicKey() PublicKey

   // 转换为crypto包中的 PrivateKey 接口类
   ToStandardKey() crypto.PrivateKey
}
// === 对称密钥加解密接口 ===
type SymmetricKey interface {

   // 加密接口
   Encrypt(plain []byte) ([]byte, error)
   EncryptWithOpts(plain []byte, opts *EncOpts) ([]byte, error)

   // 解密接口
   Decrypt(ciphertext []byte) ([]byte, error)
   DecryptWithOpts(ciphertext []byte, opts *EncOpts) ([]byte, error)
}
//初始化pkcs11 handle(创建session连接池并验证登陆)
func New(lib string, label string, password string, sessionCacheSize int, hash string) (*P11Handle, error) {
   //略
}
14.2.2.3.2. 密码接口实例化
//pkcs11对称密钥接口实例化
func NewSecretKey(p11 *P11Handle, keyId string, keyType bccrypto.KeyType) (bccrypto.SymmetricKey, error){
   //略
}

//pkcs11公钥密钥接口实例化
func NewPrivateKey(p11 *P11Handle, keyId string, keyType bccrypto.KeyType) (bccrypto.PrivateKey, error){
   //略
}

说明:

  1. keyId:硬件密码机中,密钥id标识,对应pkcs11标准中CKA_ID或者CKA_LABEL字段

  2. keyType:密钥类型,目前支持RSA,ECDSA,AES,SM2,SM4

14.2.2.4. 密码应用层

14.2.2.4.1. 硬件加密配置
//硬件加密配置项(以下配置项与密码设备相关)
pkcs11:
  enabled: false                                      # set true if enable pkcs11
  library: /usr/local/lib64/libpkcs11.so              # path to the so file of pkcs11 interface
  label: HSM                                          # label for the slot to be used
  password: 11111111                                  # password to logon the HSM
  session_cache_size: 10                              # size of HSM session cache, default to 10
  hash: "SHA256"                                      # hash algorithm used to compute SKI
14.2.2.4.2. 签名和加密示例
//pkcs11 handle初始化
p11Handle, err = pkcs11.New(library, label, password, sessionCacheSize, hash)
if err != nil{
	return nil, fmt.Errorf("failed to initialize pkcs11 handle, err = %s", err)
}

//sm2密钥初始化, SM2SignKey1为keyId,表示密码机SM2密钥索引
sk, err :=  pkcs11.NewPrivateKey(p11Handle, "SM2SignKey123", bccrypto.SM2)
if err != nil{
  log.Fatalf("failed to new sm2 private key, err = %s", err)
}

//使用sm2签名/验证
// 硬件签名
sig, _ := sk.SignWithOpts(msg, &bccrypto.SignOpts{
   Hash: hashAlgo,
   UID:  bccrypto.CRYPTO_DEFAULT_UID,
})
// 软件验签(公钥来自x509证书)
der, _ := x509.MarshalPKIXPublicKey(cert.PublicKey)
pk, _ := asym.PublicKeyFromDER(der) 
ok, _ := pk.VerifyWithOpts(msg, sig, &bccrypto.SignOpts{
		Hash: hashAlgo,
		UID:  bccrypto.CRYPTO_DEFAULT_UID,
})


//sm4密钥初始化, SM4EncKey1为keyId,表示密码机SM4密钥索引
sk, err :=  pkcs11.NewSecretKey(p11Handle, "SM4EncKey1", bccrypto.SM4)
if err != nil{
   log.Fatalf("failed to new secret key, err = %s", err)
}

//使用sm4加密/解密, 默认CBC模式
ciphertext, _ := sk.Encrypt(msg)
msg _ := sk.Decrypt(ciphertext)

注:以上为示例代码,仅供参考。

14.3. 国密TLS设计和实现

14.3.1. 背景

互联网上传输的数据,每时每刻都存在着被窃听和篡改的风险, SSL/TLS协议 在保护用户 数据机密性、完整性以及身份鉴别 等方面发挥了重大作用。国际通用TLS协议并不包含中国国密局推荐使用的商用密码算法 (即 国密算法 ) 套件,而绝大部分的编程语言原生TLS实现、第三方开源TLS实现大都不支持国密套件。随着国内安全合规、自主可控政策的指引, 国密TLS 的需求也越来越大,尤其在金融、政务领域已然成为刚需。与此同时,国密相关密码产品大多依托于硬件或者芯片,存在价格昂贵,部署成本高,部分中小企业用户难以承担的问题。 国密软件产品存在以下问题也急需解决:

  1. 未形成国密权威密码实现库,开源生态不活跃

  2. 国密TLS实现不完善,各语言版本支持现状参差不齐。

国密算法套件包括 SM2 签名、SM2 非对称加密、SM3 杂凑函数 (哈希)、SM4 对称加密,以及一个国密密钥协商协议。要在安全信道中完全使用国密算法,对TLS协议实现、与其相关的X509协议实现都需要做大量的改造适配。应用层的协议 (GRPC、HTTP等) 在实现上也需要做相应的适配。

长安链致力于打造国内完全自主可控区块链,启用全国密算法,支持国密TLS成为必要需求。 本文主要内容:

  1. 长安链国密支撑整体设计思路

  2. 长安链国密TLS支持现状

  3. 长安链国密未来工作

14.3.2. 整体设计思路

密码技术 作为长安链底层重要技术之一,在主项目chainmaker-go,ca服务、中间件以及SDK中都有深度应用。长安链在整体设计上,综合考虑了 算法性能、扩展性、标准化 等方面,密码相关组件如下:

  1. 密码算法库:提供统一密码算法接口,支持不同密码算法以及实现的扩展。

  2. 密码协议库:支持标准TLS,包括国际标准和国密标准

  3. 密码应用:长安链密码技术应用依赖于“密码算法库”和“密码协议库”,解耦具体实现细节。

14.3.3. TLS支持现状

长安链后端服务采用 Golang语言 实现,通过grpc对外提供区块链服务。生态工具SDK支持Golang、Java等不同语言。目前为止,长安链已经完成了区块链服务与客户端SDK,区块链网络节点之间的 双向国密TLS通信 。 长安链服务调用以及国密TLS支撑图如下:

  1. golang服务端:底层基于grpc通信,其中tls握手采用长安链密码协议库(支持国密TLS以及国际TLS协议)

  2. golang客户端:同上

  3. java客户端:由于java调用长安链golang密码协议库支持国密TLS,工作量较大并且维护困难,实现上采用了比较成熟的netty-tcnative + 国密openssl方式。

14.3.3.1. 密码算法库

长安链密码算法库 采用golang语言实现,目前支持主流国际密码算法AES、RSA、ECC以及SHA系列算法,并已经全面支持SM2、SM3以及SM4国密算法。底层国密实现目前采用了tjfoc密码库。

14.3.3.2. 密码协议库

长安链密码协议库 包含 国密x509、国密TLS ,并兼容国际x509、国际TLS标准。 国密TLS实现库包含 golang 国密tlsjava国密tls 两个实现。

  1. golang国密tls:在golang标准库(golang1.14版本)基础上,增加了SM2算法、SM3算法、国密X509以及SM2-SM3算法套件支持,并独立为单独的国密协议库。

  2. java国密tls:包含国密算法部分和国密TLS协议两个部分。 国密算法部分 Java侧由 Java标准库CurveDB类 提供,国密通过反射机制注入到Java标准库,国密算法实现自主研发,符合国密算法标准。 国密TLS协议 部分主要由长安链 国密openssl 提供,Java侧通过反射机制将SM3WithSM2标识注入到netty ssl io.netty.handler.ssl.ExtendedOpenSslSession 支持的签名算法 LOCAL_SUPPORTED_SIGNATURE_ALGORITHMS 列表中,Java netty通过netty-tcnative调用openssl底层密码功能。目前 netty-tcnative 已支持macOS、linux、windows以及linux_aarch等平台,并在长安链chainmaker-java-sdk中实现了 平台兼容性 ,用户只要下载长安链官方java sdk就可以实现客户端与链的国密TLS通信,无需关心netty-tcnative国密的跨平台问题。

14.3.3.3. 国密openssl

长安链的国密openssl实现是在OpenSSL-1.1.1l的基础上改造的。OpenSSL 在 1.1.1 版本中引入了国密算法的实现,但是仅仅提供了算法接口,没有把国密算法引入到任何通信协议中去支持。 长安链国密openssl把国密算法的支持加入到 X509协议 中。主要包括:

  1. 按PKCS8标准实现SM2私钥的编码序列化;

  2. 按PKIX定义的公钥编码方式实现SM2算法公钥的序列化;

  3. 实现ECC编码的SM2签名的序列化;

  4. 将SM2算法、SM3算法、SM2-SM3算法套件、SM2曲线的OID引入到X509的逻辑中。

完成了X509协议的国密支持后,进一步改造了 TLS协议 ,主要包括:

  1. 把国密算法套件加入到支持的密码算法包列表中,以供server、client两端进行算法套件的协商

  2. 在ECDSA对应的协议套件中去支持了国密算法的逻辑

  3. 身份认证阶段,使用改造过的x509协议进行国密证书验证。

14.3.4. 未来工作

  1. 支持 高性能国密库 实现:长安链开源的国密算法库目前仅支持tjfoc一种实现,与北大gmssl使用C语言实现的密码库相比存在数量级上的差距。

  2. 支持 国密双证书 体系:目前长安链国密TLS在国密证书、国密算法SM2和SM3上进行了支持,在与标准国密SSL互联互通上还需要进一步改进和完善。

14.3.5. 备注

目前长安链已经在v2.1.0版本支持国密TLS
java sdk地址: sdk-java

netty-tcnative国密jar包基于长安链国密openssl以及netty-tcnative的2.0.39.Final版本,构建流程参考
netty-tcnative官方地址: netty-tcnative wiki