这是基于fabric-v2.2.0修改的支持国密算法的fabric,已通过命令行完成网络部署以及链码操作测试。
版权所有 上海旺链信息科技有限公司(http://www.vonechain.com)。
SM2为基于椭圆曲线密码的公钥密码算法标准,包含数字签名、密钥交换和公钥加密 SM3为密码哈希算法,用于替代MD5 / SHA-1 / SHA-256等国际算法。 SM4为分组密码,用于替代DES / AES等国际算法。 SM2,SM3,SM4现在是公开标准,直接使用苏州同济区块链研究院实现的代码
通过国密SM2加解密、SM3withSM2签名验签,SM3哈希完成国密的改造.
- BCCSP的全称是区块链密码服务提供者,它能够用来提供Fabric中加解密、签名校验相关功能 。 BCCSP通过Membership Service(成员服务提供者)给相关核心功能和客户端SDK提供加密算法相关的服务。 相关的核心功能集中在core中,包括consensus模块,endorser模块等。
对国密算法的支持首先就要通过这个模块进行入手,创建bccsp的gm国密模块,实现思路是,参照sw模块来实现gm模块
(1)新增gmfactory.go,定义GMFactory结构体,增加gm文件夹,与sw类似
bccsp/factory/gmfactory.go
bccsp/gm/certhelper.go
bccsp/gm/conf.go
bccsp/gm/dummyks.go
bccsp/gm/ecdsakey.go
bccsp/gm/fileks.go
bccsp/gm/hash.go
bccsp/gm/impl.go
bccsp/gm/internals.go
bccsp/gm/keyderiv.go
bccsp/gm/keygen.go
bccsp/gm/keyimport.go
bccsp/gm/sm2.go
bccsp/gm/sm2key.go
bccsp/gm/sm4.go
bccsp/gm/sm4key.go
(2)sw是bccsp中的软件实现方案,加入对sm2,sm4的处理,定义相关的结构体,修改清单如下
bccsp/sw/sm2.go //新增
bccsp/sw/sm2key.go //新增
bccsp/sw/sm4.go //新增
bccsp/sw/sm4key.go //新增
bccsp/sw/conf.go
bccsp/sw/ecdsa.go
bccsp/sw/fileks.go
bccsp/sw/impl_test.go
bccsp/sw/keyderiv.go
bccsp/sw/keygen.go
bccsp/sw/keyimport.go
bccsp/sw/new.go
(3)factory是bccsp中的工厂服务,提供密码选项的配置,指定加解密方式,生成特定的服务工厂
bccsp/factory/factory.go
bccsp/factory/factory_test.go
bccsp/factory/nopkcs11.go
bccsp/factory/nopkcs11_test.go
bccsp/factory/opts.go
bccsp/factory/opts_test.go
bccsp/factory/pkcs11.go
(4)utils是bccsp中的工具函数服务,提供一些支持服务,修改清单: 参考文章
bccsp/utils/errs.go
bccsp/utils/io.go
bccsp/utils/keys.go
bccsp/utils/slice.go
(5)新增国密选项
bccsp/hashopts.go
bccsp/opts.go
(6)修改signer包中证书的解析函数
bccsp/signer/signer.go
- idemix(Identity Mixer)的核心是零知识证明(Zero Knowledge Proof)。 用户无需暴露私有数据以及任何有用的信息,也能证明自己拥有这些私有数据,对方能够进行有效验证,这就是零知识证明。 idemix是一个密码协议套件(X.509+加密算法),保留隐私实现匿名性,交易时不用透露交易者的身份,而且交易间是无关联的,不可往前追溯。
idemix包中的修改需要把所有ecdsa算法改为sm2算法,修改的文件清单如下:
bccsp/idemix/bridge/bridge_test.go
bccsp/idemix/bridge/revocation.go
bccsp/idemix/bridge/signaturescheme.go
bccsp/idemix/handlers/idemix.go
bccsp/idemix/handlers/mock/revocation.go
bccsp/idemix/handlers/mock/signature_scheme.go
bccsp/idemix/handlers/revocation.go
bccsp/idemix/handlers/revocation_test.go
- common包是一些通用的模块的集合,主要是包含各种策略定义工具包、编译工具包、配置文件工具包、加解密工具包、账本包和docker挂载相关的工具包、基本数据metadata工具包等
主要修改crypto包里面的ca.go和key.go,tools包作相应调整和适配
- 将crypto/x509替换成github.com/tjfoc/gmsm/sm2, 将ecdsa替换成github.com/tjfoc/gmsm/sm2,将crypto/tls替换成github.com/tjfoc/gmtls,将google.golang.org/grpc/credentials替换成github.com/tjfoc/gmtls/gmcredentials 修改的列表:
(1)core包:大部分核心实现代码都在本包下,其他包的代码封装上层接口,最终调用本包内代码
core/chaincode/accesscontrol/mapper.go
core/chaincode/lifecycle/serializer.go
core/deliverservice/config.go
core/deliverservice/deliveryclient.go
core/endorser/msgvalidation.go
core/operations/system.go
core/operations/tls.go
core/peer/config.go
(2)gossip包:实现gossip协议
gossip/api/crypto.go
gossip/comm/comm_impl.go
gossip/comm/crypto.go
gossip/comm/crypto_test.go
gossip/util/grpc.go
idemix/revocation_authority.go
idemix/signature.go
(3)msp包:Member Service Provider包
msp/cert.go
msp/cert_test.go
msp/configbuilder.go
msp/identities.go
msp/mgmt/mgmt.go //主要文件,localMsp和mspMap都在这个文件,还有多个管理函数
msp/mgmt/testtools/config_test.go
msp/mspimpl.go //实现MSP接口,结构为bccspmsp
msp/mspimplsetup.go
msp/mspimplsetup_test.go
msp/mspimplvalidate.go
(4)order包:order服务相关的入口和框架代码
orderer/common/cluster/comm.go
orderer/common/cluster/comm_test.go
orderer/common/cluster/connections.go
orderer/common/cluster/deliver.go
orderer/common/cluster/rpc_test.go
orderer/common/cluster/util.go
orderer/common/cluster/util_test.go
orderer/consensus/etcdraft/membership.go
orderer/consensus/etcdraft/util.go
orderer/consensus/kafka/config.go
- sha256替换成sm3
protoutil/txutils.go
- 重点说明
(1)证书相关的结构体的修改,增加sm2证书和sm2私钥
type CA struct {
Name string
Country string
Province string
Locality string
OrganizationalUnit string
StreetAddress string
PostalCode string
Signer crypto.Signer
SignCert *x509.Certificate
SignSm2Cert *sm2.Certificate //sm2证书
Sm2Key *sm2.PrivateKey //sm2私钥
}
(2)证书生成的函数修改,指定证书的签名方式和计算私钥的SKI
func NewCA(
baseDir,
org,
name,
country,
province,
locality,
orgUnit,
streetAddress,
postalCode string,
) (*CA, error) {
var ca *CA
err := os.MkdirAll(baseDir, 0755)
if err != nil {
return nil, err
}
priv, err := csp.GeneratePrivateKey(baseDir)
if err != nil {
return nil, err
}
template := x509Template()
//this is a CA
template.IsCA = true
template.KeyUsage |= x509.KeyUsageDigitalSignature |
x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign |
x509.KeyUsageCRLSign
template.ExtKeyUsage = []x509.ExtKeyUsage{
x509.ExtKeyUsageClientAuth,
x509.ExtKeyUsageServerAuth,
}
//set the organization for the subject
subject := subjectTemplateAdditional(country, province, locality, orgUnit, streetAddress, postalCode)
subject.Organization = []string{org}
subject.CommonName = name
template.Subject = subject
templateSm2 := gm.ParseX509Certificate2Sm2(&template)
//TODO important
templateSm2.SubjectKeyId = computeSKI(priv) //指定证书的SKI
sm2PubKey := priv.PublicKey
if err != nil {
errors.Errorf("error,%v", err)
}
templateSm2.SignatureAlgorithm = sm2.SM2WithSM3 //指定证书的签名算法
sm2Cert, err := genCertificateGMSM2(
baseDir,
name,
templateSm2,
templateSm2,
&sm2PubKey,
priv,
)
if err != nil {
return nil, err
}
ca = &CA{
Name: name,
Signer: priv,
Country: country,
Province: province,
Locality: locality,
OrganizationalUnit: orgUnit,
StreetAddress: streetAddress,
PostalCode: postalCode,
SignSm2Cert: sm2Cert,
Sm2Key: priv,
}
return ca, err
}
//定义sm2私钥的ski计算函数
func computeSKI(privKey *sm2.PrivateKey) []byte {
// Marshall the public key
raw := elliptic.Marshal(privKey.Curve, privKey.PublicKey.X, privKey.PublicKey.Y)
// Hash it
hash := sha256.New()
hash.Write(raw)
return hash.Sum(nil)
}
(3)sm2私钥生成
//TODO SM2
func GeneratePrivateKey(keystorePath string) (*sm2.PrivateKey, error) {
priv, err := sm2.GenerateKey()
if err != nil {
return nil, errors.WithMessage(err, "failed to generate private key")
}
pkcs8Encoded, err := sm2.MarshalSm2PrivateKey(priv,nil) //解析sm2证书方式
if err != nil {
return nil, errors.WithMessage(err, "failed to marshal private key")
}
pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: pkcs8Encoded})
keyFile := filepath.Join(keystorePath, "priv_sk")
err = ioutil.WriteFile(keyFile, pemEncoded, 0600)
if err != nil {
return nil, errors.WithMessagef(err, "failed to save private key to file %s", keyFile)
}
return priv, err
}
进入你克隆到本地的fabric仓库的根目录
go mod vendor
cd vendor/github.com/tjfoc/gmtls //暂时如此操作,防止后面的问题
go mod vendor
make docker //回到克隆到本地的fabric仓库的根目录
1.出现的问题
remote error: tls: unexpected message
解决办法
cd vendor/github.com/tjfoc/gmtls
go mod vendor
2.出现的问题:找不到rootca的证书链
解决办法
templateSm2.SubjectKeyId = computeSKI(priv) //指定证书的SKI
3.出现的问题:验证签名失败
解决办法
templateSm2.SignatureAlgorithm = sm2.SM2WithSM3 //指定证书的签名算法
docker-compose -f docker-compose-cli.yaml -f docker-compose-etcdraft2.yaml -f docker-compose-ca.yaml up -d