mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-27 04:36:19 +08:00
pkcs7: remove deprecated method SignWithSM2
This commit is contained in:
parent
6b18205bba
commit
d199697b20
18
docs/sm2.md
18
docs/sm2.md
@ -306,6 +306,24 @@ func calculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) {
|
||||
```
|
||||
公钥加密就没啥特殊,只要确保输出密文的编码格式和KMS一致即可。
|
||||
|
||||
## 基于密码硬件,定制SM2私钥
|
||||
密码硬件(SDF/SKF)中的私钥通常是无法导出的,但通常提供了签名、解密APIs供调用,为了和本软件库集成,通常需要自定义实现以下接口:
|
||||
|
||||
1. `crypto.Signer`,这个接口的实现通常把传入的数据作为哈希值。
|
||||
2. `crypto.Decrypter`,这个接口用于解密操作。
|
||||
|
||||
通常需要实现四个方法:
|
||||
1. `Public() crypto.PublicKey`
|
||||
2. `Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error)`
|
||||
3. `Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error)`
|
||||
|
||||
第一个返回公钥的方法是必须要实现的,后面的方法取决于这个KEY的用途。
|
||||
|
||||
**注意**:
|
||||
`Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error)`方法通常用于对哈希值作签名,最好遵从以下实现逻辑:检查`opts`是否是`*sm2.SM2SignerOption`类型,如果是,则把传入的`digest`作为原始数据进行处理,具体实现可以参考`sm2.SignASN1`函数。当然,目前不管三七二十一,简单当作原始数据大多数情况下都没有问题。实现者可以根据实际应用情况酌情处理。
|
||||
|
||||
如果密码硬件有自己的随机数源,可以忽略传入的`rand`。
|
||||
|
||||
## SM2扩展应用
|
||||
SM2的一些扩展应用,譬如从签名中恢复公钥、半同态加密、环签名等,大多尚处于POC状态,也无相关标准。其它扩展应用(但凡椭圆曲线公钥密码算法能用到的场合),包括但不限于:
|
||||
* [确定性签名](https://datatracker.ietf.org/doc/html/rfc6979)
|
||||
|
107
pkcs7/sign.go
107
pkcs7/sign.go
@ -19,12 +19,12 @@ import (
|
||||
|
||||
// SignedData is an opaque data structure for creating signed data payloads
|
||||
type SignedData struct {
|
||||
sd signedData
|
||||
certs []*smx509.Certificate
|
||||
data, messageDigest []byte
|
||||
contentTypeOid asn1.ObjectIdentifier
|
||||
digestOid asn1.ObjectIdentifier
|
||||
encryptionOid asn1.ObjectIdentifier
|
||||
sd signedData
|
||||
certs []*smx509.Certificate
|
||||
data []byte
|
||||
contentTypeOid asn1.ObjectIdentifier
|
||||
digestOid asn1.ObjectIdentifier
|
||||
encryptionOid asn1.ObjectIdentifier
|
||||
}
|
||||
|
||||
// NewSignedData takes data and initializes a PKCS7 SignedData struct that is
|
||||
@ -167,30 +167,11 @@ func (sd *SignedData) AddSignerChain(ee *smx509.Certificate, pkey crypto.Private
|
||||
sd.sd.DigestAlgorithmIdentifiers = append(sd.sd.DigestAlgorithmIdentifiers,
|
||||
pkix.AlgorithmIdentifier{Algorithm: sd.digestOid, Parameters: asn1.NullRawValue},
|
||||
)
|
||||
hasher, err := getHashForOID(sd.digestOid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h := newHash(hasher, sd.digestOid)
|
||||
h.Write(sd.data)
|
||||
sd.messageDigest = h.Sum(nil)
|
||||
encryptionOid, err := getOIDForEncryptionAlgorithm(pkey, sd.digestOid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attrs := &attributes{}
|
||||
attrs.Add(OIDAttributeContentType, sd.sd.ContentInfo.ContentType)
|
||||
attrs.Add(OIDAttributeMessageDigest, sd.messageDigest)
|
||||
attrs.Add(OIDAttributeSigningTime, time.Now().UTC())
|
||||
for _, attr := range config.ExtraSignedAttributes {
|
||||
attrs.Add(attr.Type, attr.Value)
|
||||
}
|
||||
finalAttrs, err := attrs.ForMarshalling()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// create signature of signed attributes
|
||||
signature, err := signAttributes(finalAttrs, pkey, hasher)
|
||||
finalAttrs, signature, err := sd.signWithAttributes(pkey, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -216,6 +197,34 @@ func (sd *SignedData) AddSignerChain(ee *smx509.Certificate, pkey crypto.Private
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sd *SignedData) signWithAttributes(pkey crypto.PrivateKey, config SignerInfoConfig) ([]attribute, []byte, error) {
|
||||
hasher, err := getHashForOID(sd.digestOid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
h := newHash(hasher, sd.digestOid)
|
||||
h.Write(sd.data)
|
||||
messageDigest := h.Sum(nil)
|
||||
|
||||
attrs := &attributes{}
|
||||
attrs.Add(OIDAttributeContentType, sd.sd.ContentInfo.ContentType)
|
||||
attrs.Add(OIDAttributeMessageDigest, messageDigest)
|
||||
attrs.Add(OIDAttributeSigningTime, time.Now().UTC())
|
||||
for _, attr := range config.ExtraSignedAttributes {
|
||||
attrs.Add(attr.Type, attr.Value)
|
||||
}
|
||||
finalAttrs, err := attrs.ForMarshalling()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// create signature of signed attributes
|
||||
signature, err := signAttributes(finalAttrs, pkey, hasher)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return finalAttrs, signature, nil
|
||||
}
|
||||
|
||||
func newHash(hasher crypto.Hash, hashOid asn1.ObjectIdentifier) hash.Hash {
|
||||
var h hash.Hash
|
||||
if hashOid.Equal(OIDDigestAlgorithmSM3) || hashOid.Equal(OIDDigestAlgorithmSM2SM3) {
|
||||
@ -240,20 +249,7 @@ func (sd *SignedData) SignWithoutAttr(ee *smx509.Certificate, pkey crypto.Privat
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key, ok := pkey.(crypto.Signer)
|
||||
if !ok {
|
||||
return errors.New("pkcs7: private key does not implement crypto.Signer")
|
||||
}
|
||||
_, isSM2 := pkey.(sm2.Signer)
|
||||
if isSM2 {
|
||||
signature, err = key.Sign(rand.Reader, sd.data, sm2.DefaultSM2SignerOpts)
|
||||
} else {
|
||||
h := newHash(hasher, sd.digestOid)
|
||||
h.Write(sd.data)
|
||||
sd.messageDigest = h.Sum(nil)
|
||||
signature, err = key.Sign(rand.Reader, sd.messageDigest, hasher)
|
||||
}
|
||||
if err != nil {
|
||||
if signature, err = signData(sd.data, pkey, hasher); err != nil {
|
||||
return err
|
||||
}
|
||||
var ias issuerAndSerial
|
||||
@ -380,20 +376,33 @@ func signAttributes(attrs []attribute, pkey crypto.PrivateKey, hasher crypto.Has
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return signData(attrBytes, pkey, hasher)
|
||||
}
|
||||
|
||||
if key, ok := pkey.(sm2.Signer); ok {
|
||||
return key.SignWithSM2(rand.Reader, nil, attrBytes)
|
||||
}
|
||||
|
||||
h := hasher.New()
|
||||
h.Write(attrBytes)
|
||||
hash := h.Sum(nil)
|
||||
|
||||
// signData signs the provided data using the given private key and hash function.
|
||||
// It returns the signed data or an error if the signing process fails.
|
||||
func signData(data []byte, pkey crypto.PrivateKey, hasher crypto.Hash) ([]byte, error) {
|
||||
key, ok := pkey.(crypto.Signer)
|
||||
if !ok {
|
||||
return nil, errors.New("pkcs7: private key does not implement crypto.Signer")
|
||||
}
|
||||
return key.Sign(rand.Reader, hash, hasher)
|
||||
hash := data
|
||||
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
|
||||
} else {
|
||||
return nil, fmt.Errorf("pkcs7: unsupported hash function %s", hasher)
|
||||
}
|
||||
} else {
|
||||
h := hasher.New()
|
||||
h.Write(data)
|
||||
hash = h.Sum(nil)
|
||||
}
|
||||
return key.Sign(rand.Reader, hash, opts)
|
||||
}
|
||||
|
||||
// concats and wraps the certificates in the RawValue structure
|
||||
|
@ -87,6 +87,7 @@ func testSign(t *testing.T, isSM bool, content []byte, sigalgs []x509.SignatureA
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
content := []byte("Hello World")
|
||||
sigalgs := []x509.SignatureAlgorithm{
|
||||
|
@ -25,8 +25,17 @@ import (
|
||||
// should be performed.
|
||||
var directSigning crypto.Hash = 0
|
||||
|
||||
// Signer SM2 special signer
|
||||
// Signer is an interface for an opaque private key that can be used for
|
||||
// signing operations. For example, an SM2 key kept in a hardware module.
|
||||
// Deprecated: please use crypto.Signer directly.
|
||||
type Signer interface {
|
||||
// Public returns the public key corresponding to the opaque,
|
||||
// private key.
|
||||
Public() crypto.PublicKey
|
||||
|
||||
// SignWithSM2 signs raw message with the private key, possibly using entropy from
|
||||
// rand, and the user ID (UID). If the UID is not provided, a default UID (1234567812345678) is used.
|
||||
// The signature is generated using the SM2 algorithm.
|
||||
SignWithSM2(rand io.Reader, uid, msg []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
@ -251,8 +260,8 @@ func bigIntToBytes(curve elliptic.Curve, value *big.Int) []byte {
|
||||
}
|
||||
|
||||
// CalculateSM2Hash calculates the SM2 hash for the given public key, data, and user ID (UID).
|
||||
// If the UID is not provided, a default UID (1234567812345678) is used.
|
||||
// The public key must be valid, otherwise will be panic.
|
||||
// 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.
|
||||
func CalculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) {
|
||||
if len(uid) == 0 {
|
||||
@ -650,7 +659,6 @@ func randomPoint(c *sm2Curve, rand io.Reader, checkOrderMinus1 bool) (k *bigmod.
|
||||
// randomPoint rejects a candidate for being higher than the modulus.
|
||||
var testingOnlyRejectionSamplingLooped func()
|
||||
|
||||
|
||||
// RecoverPublicKeysFromSM2Signature attempts to recover the public keys from an SM2 signature.
|
||||
// This function takes a hash and a signature as input and returns a slice of possible public keys
|
||||
// that could have generated the given signature.
|
||||
|
Loading…
x
Reference in New Issue
Block a user