mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 12:16:20 +08:00
sm2,smx509: add encoding paths for SM2 ecdh keys
This commit is contained in:
parent
9805aa448a
commit
984913e228
@ -66,6 +66,10 @@ type Curve interface {
|
||||
}
|
||||
|
||||
// PublicKey is an ECDH public key, usually a peer's ECDH share sent over the wire.
|
||||
//
|
||||
// These keys can be parsed with [smx509.ParsePKIXPublicKey] and encoded
|
||||
// with [smx509.MarshalPKIXPublicKey]. For SM2 curve, it then needs to
|
||||
// be converted with [sm2.PublicKeyToECDH] after parsing.
|
||||
type PublicKey struct {
|
||||
curve Curve
|
||||
publicKey []byte
|
||||
@ -129,6 +133,10 @@ func (uv *PublicKey) SM2SharedKey(isResponder bool, kenLen int, sPub, sRemote *P
|
||||
}
|
||||
|
||||
// PrivateKey is an ECDH private key, usually kept secret.
|
||||
//
|
||||
// These keys can be parsed with [smx509.ParsePKCS8PrivateKey] and encoded
|
||||
// with [smx509.MarshalPKCS8PrivateKey]. For SM2 curve, it then needs to
|
||||
// be converted with [sm2.PrivateKey.ECDH] after parsing.
|
||||
type PrivateKey struct {
|
||||
curve Curve
|
||||
privateKey []byte
|
||||
|
39
sm2/sm2.go
39
sm2/sm2.go
@ -22,6 +22,7 @@ import (
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/emmansun/gmsm/ecdh"
|
||||
"github.com/emmansun/gmsm/internal/randutil"
|
||||
"github.com/emmansun/gmsm/internal/subtle"
|
||||
"github.com/emmansun/gmsm/kdf"
|
||||
@ -869,3 +870,41 @@ func IsSM2PublicKey(publicKey interface{}) bool {
|
||||
func P256() elliptic.Curve {
|
||||
return sm2ec.P256()
|
||||
}
|
||||
|
||||
// PublicKeyToECDH returns k as a [ecdh.PublicKey]. It returns an error if the key is
|
||||
// invalid according to the definition of [ecdh.Curve.NewPublicKey], or if the
|
||||
// Curve is not supported by ecdh.
|
||||
func PublicKeyToECDH(k *ecdsa.PublicKey) (*ecdh.PublicKey, error) {
|
||||
c := curveToECDH(k.Curve)
|
||||
if c == nil {
|
||||
return nil, errors.New("sm2: unsupported curve by ecdh")
|
||||
}
|
||||
if !k.Curve.IsOnCurve(k.X, k.Y) {
|
||||
return nil, errors.New("sm2: invalid public key")
|
||||
}
|
||||
return c.NewPublicKey(elliptic.Marshal(k.Curve, k.X, k.Y))
|
||||
}
|
||||
|
||||
// ECDH returns k as a [ecdh.PrivateKey]. It returns an error if the key is
|
||||
// invalid according to the definition of [ecdh.Curve.NewPrivateKey], or if the
|
||||
// Curve is not supported by ecdh.
|
||||
func (k *PrivateKey) ECDH() (*ecdh.PrivateKey, error) {
|
||||
c := curveToECDH(k.Curve)
|
||||
if c == nil {
|
||||
return nil, errors.New("sm2: unsupported curve by ecdh")
|
||||
}
|
||||
size := (k.Curve.Params().N.BitLen() + 7) / 8
|
||||
if k.D.BitLen() > size*8 {
|
||||
return nil, errors.New("sm2: invalid private key")
|
||||
}
|
||||
return c.NewPrivateKey(k.D.FillBytes(make([]byte, size)))
|
||||
}
|
||||
|
||||
func curveToECDH(c elliptic.Curve) ecdh.Curve {
|
||||
switch c {
|
||||
case sm2ec.P256():
|
||||
return ecdh.P256()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
|
||||
"github.com/emmansun/gmsm/ecdh"
|
||||
"github.com/emmansun/gmsm/sm2"
|
||||
"github.com/emmansun/gmsm/sm9"
|
||||
)
|
||||
@ -117,7 +118,7 @@ func parseSM9PrivateKey(privKey pkcs8) (key interface{}, err error) {
|
||||
|
||||
// MarshalPKCS8PrivateKey converts a private key to PKCS #8, ASN.1 DER form.
|
||||
//
|
||||
// The following key types are currently supported: *rsa.PrivateKey, *ecdsa.PrivateKey, a *sm2.PrivateKey,
|
||||
// The following key types are currently supported: *rsa.PrivateKey, *ecdsa.PrivateKey, a *sm2.PrivateKey, a *ecdh.PrivateKey
|
||||
// a *sm9.SignMasterPrivateKey, a *sm9.SignPrivateKey, a *sm9.EncryptMasterPrivateKey, a *sm9.EncryptPrivateKey
|
||||
// and ed25519.PrivateKey. Unsupported key types result in an error.
|
||||
//
|
||||
@ -126,6 +127,8 @@ func MarshalPKCS8PrivateKey(key interface{}) ([]byte, error) {
|
||||
switch k := key.(type) {
|
||||
case *sm2.PrivateKey:
|
||||
return marshalPKCS8ECPrivateKey(&k.PrivateKey)
|
||||
case *ecdh.PrivateKey:
|
||||
return marshalPKCS8ECDHPrivateKey(k)
|
||||
case *sm9.SignPrivateKey:
|
||||
return marshalPKCS8SM9SignPrivateKey(k)
|
||||
case *sm9.EncryptPrivateKey:
|
||||
@ -280,3 +283,25 @@ func marshalPKCS8ECPrivateKey(k *ecdsa.PrivateKey) ([]byte, error) {
|
||||
}
|
||||
return asn1.Marshal(privKey)
|
||||
}
|
||||
|
||||
func marshalPKCS8ECDHPrivateKey(k *ecdh.PrivateKey) ([]byte, error) {
|
||||
var privKey pkcs8
|
||||
oid, ok := oidFromECDHCurve(k.Curve())
|
||||
if !ok {
|
||||
return nil, errors.New("x509: unknown curve while marshaling to PKCS#8")
|
||||
}
|
||||
oidBytes, err := asn1.Marshal(oid)
|
||||
if err != nil {
|
||||
return nil, errors.New("x509: failed to marshal curve OID: " + err.Error())
|
||||
}
|
||||
privKey.Algo = pkix.AlgorithmIdentifier{
|
||||
Algorithm: oidPublicKeyECDSA,
|
||||
Parameters: asn1.RawValue{
|
||||
FullBytes: oidBytes,
|
||||
},
|
||||
}
|
||||
if privKey.PrivateKey, err = marshalECDHPrivateKey(k); err != nil {
|
||||
return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " + err.Error())
|
||||
}
|
||||
return asn1.Marshal(privKey)
|
||||
}
|
||||
|
@ -124,6 +124,22 @@ func TestPKCS8(t *testing.T) {
|
||||
t.Errorf("%s: marshaled PKCS#8 didn't match original: got %x, want %x", test.name, reserialised, derBytes)
|
||||
continue
|
||||
}
|
||||
if ecKey, isEC := privKey.(*sm2.PrivateKey); isEC {
|
||||
ecdhKey, err := ecKey.ECDH()
|
||||
if err != nil {
|
||||
t.Errorf("%s: failed to convert to ecdh: %s", test.name, err)
|
||||
continue
|
||||
}
|
||||
reserialised, err := MarshalPKCS8PrivateKey(ecdhKey)
|
||||
if err != nil {
|
||||
t.Errorf("%s: failed to marshal into PKCS#8: %s", test.name, err)
|
||||
continue
|
||||
}
|
||||
if !bytes.Equal(derBytes, reserialised) {
|
||||
t.Errorf("%s: marshaled PKCS#8 didn't match original: got %x, want %x", test.name, reserialised, derBytes)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/emmansun/gmsm/ecdh"
|
||||
"github.com/emmansun/gmsm/sm2"
|
||||
)
|
||||
|
||||
@ -133,3 +134,13 @@ func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *e
|
||||
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
// marshalECDHPrivateKey marshals an EC private key into ASN.1, DER format
|
||||
// suitable for SM2 curve.
|
||||
func marshalECDHPrivateKey(key *ecdh.PrivateKey) ([]byte, error) {
|
||||
return asn1.Marshal(ecPrivateKey{
|
||||
Version: 1,
|
||||
PrivateKey: key.Bytes(),
|
||||
PublicKey: asn1.BitString{Bytes: key.PublicKey().Bytes()},
|
||||
})
|
||||
}
|
||||
|
@ -637,7 +637,7 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
|
||||
for i := 0; i < opts.Intermediates.len(); i++ {
|
||||
c, err := opts.Intermediates.cert(i)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("crypto/x509: error fetching intermediate: %w", err)
|
||||
return nil, fmt.Errorf("x509: error fetching intermediate: %w", err)
|
||||
}
|
||||
if len(c.Raw) == 0 {
|
||||
return nil, errNotParsed
|
||||
|
@ -49,6 +49,7 @@ import (
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
|
||||
|
||||
"github.com/emmansun/gmsm/ecdh"
|
||||
"github.com/emmansun/gmsm/internal/godebug"
|
||||
"github.com/emmansun/gmsm/sm2"
|
||||
)
|
||||
@ -114,6 +115,20 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith
|
||||
case ed25519.PublicKey:
|
||||
publicKeyBytes = pub
|
||||
publicKeyAlgorithm.Algorithm = oidPublicKeyEd25519
|
||||
case *ecdh.PublicKey: //TODO:will add SDK ECDH public key support from golang 1.19 later.
|
||||
publicKeyBytes = pub.Bytes()
|
||||
|
||||
oid, ok := oidFromECDHCurve(pub.Curve())
|
||||
if !ok {
|
||||
return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve")
|
||||
}
|
||||
publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA
|
||||
var paramBytes []byte
|
||||
paramBytes, err = asn1.Marshal(oid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
publicKeyAlgorithm.Parameters.FullBytes = paramBytes
|
||||
default:
|
||||
return nil, pkix.AlgorithmIdentifier{}, fmt.Errorf("x509: unsupported public key type: %T", pub)
|
||||
}
|
||||
@ -519,6 +534,15 @@ func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func oidFromECDHCurve(curve ecdh.Curve) (asn1.ObjectIdentifier, bool) {
|
||||
switch curve {
|
||||
case ecdh.P256():
|
||||
return oidNamedCurveP256SM2, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// KeyUsage represents the set of actions that are valid for a given key. It's
|
||||
// a bitmap of the KeyUsage* constants.
|
||||
type KeyUsage = x509.KeyUsage
|
||||
|
Loading…
x
Reference in New Issue
Block a user