pkcs7: code review and refactor

This commit is contained in:
Sun Yimin 2024-12-20 08:34:32 +08:00 committed by GitHub
parent d199697b20
commit 805fa40c97
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 55 additions and 56 deletions

View File

@ -320,9 +320,9 @@ func calculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) {
第一个返回公钥的方法是必须要实现的后面的方法取决于这个KEY的用途。
**注意**
`Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error)`方法通常用于对哈希值作签名,最好遵从以下实现逻辑:检查`opts`是否是`*sm2.SM2SignerOption`类型,如果是,则把传入的`digest`作为原始数据进行处理,具体实现可以参考`sm2.SignASN1`函数。当然,目前不管三七二十一,简单当作原始数据大多数情况下都没有问题。实现者可以根据实际应用情况酌情处理。
如果密码硬件有自己的随机数源,可以忽略传入的`rand`
1. `Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error)`方法通常用于对哈希值作签名,最好遵从以下实现逻辑:检查`opts`是否是`*sm2.SM2SignerOption`类型,如果是,则把传入的`digest`作为原始数据进行处理,具体实现可以参考`sm2.SignASN1`函数。当然,目前不管三七二十一,简单当作原始数据大多数情况下都没有问题。实现者可以根据实际应用情况酌情处理。
2. 如果密码硬件有自己的随机数源,可以忽略传入的`rand`
3. 很多设备签名函数通常只接收哈希值,需要调用```sm2.CalculateSM2Hash```自行计算哈希值
## SM2扩展应用
SM2的一些扩展应用譬如从签名中恢复公钥、半同态加密、环签名等大多尚处于POC状态也无相关标准。其它扩展应用但凡椭圆曲线公钥密码算法能用到的场合包括但不限于

View File

@ -3,6 +3,7 @@ package pkcs7
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/rand"
"crypto/x509/pkix"
"encoding/asn1"
@ -390,10 +391,16 @@ func signData(data []byte, pkey crypto.PrivateKey, hasher crypto.Hash) ([]byte,
var opts crypto.SignerOpts = hasher
if !hasher.Available() {
// if you pass a private key with type *ecdsa.PrivateKey and the curve is SM2,
// you will get unexpected signature.
if sm2.IsSM2PublicKey(key.Public()) {
opts = sm2.DefaultSM2SignerOpts
switch realKey := key.(type) {
case *ecdsa.PrivateKey:
{
sm2Key := new(sm2.PrivateKey)
sm2Key.PrivateKey = *realKey
key = sm2Key
}
}
} else {
return nil, fmt.Errorf("pkcs7: unsupported hash function %s", hasher)
}

View File

@ -8,7 +8,6 @@ import (
"errors"
"github.com/emmansun/gmsm/pkcs"
"github.com/emmansun/gmsm/sm2"
"github.com/emmansun/gmsm/smx509"
)
@ -235,24 +234,7 @@ func (saed *SignedAndEnvelopedData) AddSignerChain(ee *smx509.Certificate, pkey
if err != nil {
return err
}
key, ok := pkey.(crypto.Signer)
if !ok {
return errors.New("pkcs7: private key does not implement crypto.Signer")
}
var signOpt crypto.SignerOpts
var tobeSigned []byte
if _, isSM2 := pkey.(sm2.Signer); isSM2 {
signOpt = sm2.DefaultSM2SignerOpts
tobeSigned = saed.data
} else {
signOpt = hasher
h := newHash(hasher, saed.digestOid)
h.Write(saed.data)
tobeSigned = h.Sum(nil)
}
signature, err := key.Sign(rand.Reader, tobeSigned, signOpt)
signature, err := signData(saed.data, pkey, hasher)
if err != nil {
return err
}

View File

@ -2,6 +2,7 @@ package pkcs7
import (
"bytes"
"crypto"
"crypto/ecdsa"
"encoding/pem"
"math/big"
@ -177,40 +178,47 @@ func TestCreateSignedEvnvelopedDataSM(t *testing.T) {
}
sm2Key.D.FillBytes(privKey)
rootSM2Priv, ok := (*rootCert.PrivateKey).(*sm2.PrivateKey)
if !ok {
t.Fatal("should be sm2 private key")
}
signKeys := []crypto.PrivateKey{rootSM2Priv, &rootSM2Priv.PrivateKey}
testCipers := []pkcs.Cipher{pkcs.SM4ECB, pkcs.SM4CBC, pkcs.SM4GCM}
for _, cipher := range testCipers {
saed, err := NewSMSignedAndEnvelopedData(privKey, cipher)
if err != nil {
t.Fatal(err)
}
err = saed.AddSigner(rootCert.Certificate, *rootCert.PrivateKey)
if err != nil {
t.Fatal(err)
}
err = saed.AddRecipient(recipient.Certificate)
if err != nil {
t.Fatal(err)
}
result, err := saed.Finish()
if err != nil {
t.Fatal(err)
}
for _, key := range signKeys {
for _, cipher := range testCipers {
saed, err := NewSMSignedAndEnvelopedData(privKey, cipher)
if err != nil {
t.Fatal(err)
}
err = saed.AddSigner(rootCert.Certificate, key)
if err != nil {
t.Fatal(err)
}
err = saed.AddRecipient(recipient.Certificate)
if err != nil {
t.Fatal(err)
}
result, err := saed.Finish()
if err != nil {
t.Fatal(err)
}
// fmt.Printf("%x\n", result)
// fmt.Printf("%x\n", result)
// parse, decrypt, verify
p7Data, err := Parse(result)
if err != nil {
t.Fatal(err)
}
encKeyBytes, err := p7Data.DecryptAndVerify(recipient.Certificate, *recipient.PrivateKey, func() error {
return p7Data.Verify()
})
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(encKeyBytes, privKey) {
t.Fatal("not same private key")
// parse, decrypt, verify
p7Data, err := Parse(result)
if err != nil {
t.Fatal(err)
}
encKeyBytes, err := p7Data.DecryptAndVerify(recipient.Certificate, *recipient.PrivateKey, func() error {
return p7Data.Verify()
})
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(encKeyBytes, privKey) {
t.Fatal("not same private key")
}
}
}
}

View File

@ -214,6 +214,7 @@ var defaultUID = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x
// Compliance with GB/T 32918.2-2016 5.5.
//
// This function will not use default UID even the uid argument is empty.
// Reference: GM/T 0009-2023 Chapter 8.1.
func CalculateZA(pub *ecdsa.PublicKey, uid []byte) ([]byte, error) {
uidLen := len(uid)
if uidLen > 0x1fff {
@ -263,6 +264,7 @@ func bigIntToBytes(curve elliptic.Curve, value *big.Int) []byte {
// If the UID is not provided, a default UID (1234567812345678) is used.
// The public key must be valid, otherwise will be panic.
// This function is used to calculate the hash value for SM2 signature.
// Reference: GM/T 0009-2023 Chapter 8.1 and 8.2.
func CalculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) {
if len(uid) == 0 {
uid = defaultUID