support sm9 key format with gmssl

This commit is contained in:
emmansun 2022-10-22 15:49:01 +08:00
parent ecdf5fca82
commit 404cd10210
7 changed files with 333 additions and 27 deletions

View File

@ -101,6 +101,7 @@ func newPRFParamFromHash(h Hash) (pkix.AlgorithmIdentifier, error) {
type pbkdf2Params struct { type pbkdf2Params struct {
Salt []byte Salt []byte
IterationCount int IterationCount int
KeyLen int `asn1:"optional"`
PRF pkix.AlgorithmIdentifier `asn1:"optional"` PRF pkix.AlgorithmIdentifier `asn1:"optional"`
} }
@ -127,7 +128,7 @@ func (p PBKDF2Opts) DeriveKey(password, salt []byte, size int) (
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
params = pbkdf2Params{salt, p.IterationCount, prfParam} params = pbkdf2Params{salt, p.IterationCount, size, prfParam}
return key, params, nil return key, params, nil
} }

View File

@ -219,7 +219,7 @@ func ParsePrivateKey(der []byte, password []byte) (interface{}, KDFParameters, e
key, err := smx509.ParsePKCS8PrivateKey(decryptedKey) key, err := smx509.ParsePKCS8PrivateKey(decryptedKey)
if err != nil { if err != nil {
return nil, nil, errors.New("pkcs8: incorrect password") return nil, nil, errors.New("pkcs8: failed to parse private key while ParsePKCS8PrivateKey: " + err.Error())
} }
return key, kdfParams, nil return key, kdfParams, nil
} }

View File

@ -32,3 +32,31 @@ func TestParseFFCscryptPrivateKey(t *testing.T) {
}) })
} }
} }
const encryptedSM9SignPrivateKey = `-----BEGIN ENCRYPTED SM9 SIGN PRIVATE KEY-----
MIIBVjBhBgkqhkiG9w0BBQ0wVDA0BgkqhkiG9w0BBQwwJwQQxWctHikJLVP2A7fQ
nm6qwQIDAQAAAgEQMAsGCSqBHM9VAYMRAjAcBggqgRzPVQFoAgQQfuWLjhO7iJNX
2owsXE8/6gSB8Ot4oMs97o7dDd6o2U29uTjvkt7Xq/ti/2OPoOvDeGr/SWTmLUHY
6X71SpB/GAmBVE1qMXSxFHotgeq1cbwuZtwqLV2GA0etAnC2MZV/2BYcx+qOwwgX
uljiXhlvpvxHfxxdL7HzJ5oC+AuMblQZnAvaicmS9Pr+EPk4gzusiCc4cu1q+sTh
xl4HzCz08DYx8l5j1B/FCnN0/9tv2F2Q6j3xWARFC8EJPAEhALdO+hol56Tz7A2a
zSK4N8ox4ip3G8L6TVMIlc8qFIfsnaVn+dQSWDubya8Lq4AieEs8mL+kPqEnSIUX
fYuup/MCEz2zpA==
-----END ENCRYPTED SM9 SIGN PRIVATE KEY-----
`
func TestParseSM9PrivateKey(t *testing.T) {
keyList := []testPrivateKey{
{
name: "encryptedSM9SignPrivateKey",
clear: "",
encrypted: encryptedSM9SignPrivateKey,
password: "123456",
},
}
for i, key := range keyList {
t.Run(key.name, func(t *testing.T) {
testParsePKCS8PrivateKey(t, i, &key)
})
}
}

View File

@ -1,6 +1,9 @@
package sm9 package sm9
import ( import (
"encoding/asn1"
"encoding/pem"
"errors" "errors"
"io" "io"
"math/big" "math/big"
@ -8,6 +11,7 @@ import (
"github.com/emmansun/gmsm/sm9/bn256" "github.com/emmansun/gmsm/sm9/bn256"
"golang.org/x/crypto/cryptobyte" "golang.org/x/crypto/cryptobyte"
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
) )
// SignMasterPrivateKey master private key for sign, generated by KGC // SignMasterPrivateKey master private key for sign, generated by KGC
@ -180,6 +184,16 @@ func unmarshalG2(bytes []byte) (*bn256.G2, error) {
return g2, nil return g2, nil
} }
// UnmarshalRaw unmarsal raw bytes data to sign master public key
func (pub *SignMasterPublicKey) UnmarshalRaw(bytes []byte) error {
g2, err := unmarshalG2(bytes)
if err != nil {
return err
}
pub.MasterPublicKey = g2
return nil
}
// UnmarshalASN1 unmarsal der data to sign master public key // UnmarshalASN1 unmarsal der data to sign master public key
func (pub *SignMasterPublicKey) UnmarshalASN1(der []byte) error { func (pub *SignMasterPublicKey) UnmarshalASN1(der []byte) error {
var bytes []byte var bytes []byte
@ -187,12 +201,29 @@ func (pub *SignMasterPublicKey) UnmarshalASN1(der []byte) error {
if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() { if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() {
return errors.New("sm9: invalid sign master public key asn1 data") return errors.New("sm9: invalid sign master public key asn1 data")
} }
g2, err := unmarshalG2(bytes) return pub.UnmarshalRaw(bytes)
if err != nil { }
return err
type publicKeyInfo struct {
Raw asn1.RawContent
PublicKey asn1.BitString
}
// ParseFromPEM just for GMSSL, there are no Algorithm pkix.AlgorithmIdentifier
func (pub *SignMasterPublicKey) ParseFromPEM(data []byte) error {
block, _ := pem.Decode([]byte(data))
if block == nil {
return errors.New("failed to parse PEM block")
} }
pub.MasterPublicKey = g2
return nil var pki publicKeyInfo
if rest, err := asn1.Unmarshal(block.Bytes, &pki); err != nil {
return err
} else if len(rest) != 0 {
return errors.New("trailing data after ASN.1 of public-key")
}
der := cryptobyte.String(pki.PublicKey.RightAlign())
return pub.UnmarshalRaw(der)
} }
// MasterPublic returns the master public key corresponding to priv. // MasterPublic returns the master public key corresponding to priv.
@ -242,14 +273,9 @@ func unmarshalG1(bytes []byte) (*bn256.G1, error) {
return g, nil return g, nil
} }
// UnmarshalASN1 unmarsal der data to sign user private key // UnmarshalRaw unmarsal raw bytes data to sign user private key
// Note, priv's SignMasterPublicKey should be handled separately. // Note, priv's SignMasterPublicKey should be handled separately.
func (priv *SignPrivateKey) UnmarshalASN1(der []byte) error { func (priv *SignPrivateKey) UnmarshalRaw(bytes []byte) error {
var bytes []byte
input := cryptobyte.String(der)
if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() {
return errors.New("sm9: invalid sign user private key asn1 data")
}
g, err := unmarshalG1(bytes) g, err := unmarshalG1(bytes)
if err != nil { if err != nil {
return err return err
@ -258,6 +284,40 @@ func (priv *SignPrivateKey) UnmarshalASN1(der []byte) error {
return nil return nil
} }
// UnmarshalASN1 unmarsal der data to sign user private key
// Note, priv's SignMasterPublicKey should be handled separately.
func (priv *SignPrivateKey) UnmarshalASN1(der []byte) error {
var bytes []byte
var pubBytes []byte
var inner cryptobyte.String
input := cryptobyte.String(der)
if der[0] == 0x30 {
if !input.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) ||
!input.Empty() ||
!inner.ReadASN1BitStringAsBytes(&bytes) {
return errors.New("sm9: invalid sign user private key asn1 data")
}
if !inner.Empty() && (!inner.ReadASN1BitStringAsBytes(&pubBytes) || !inner.Empty()) {
return errors.New("sm9: invalid sign master public key asn1 data")
}
} else if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() {
return errors.New("sm9: invalid sign user private key asn1 data")
}
err := priv.UnmarshalRaw(bytes)
if err != nil {
return err
}
if len(pubBytes) > 0 {
masterPK := new(SignMasterPublicKey)
err = masterPK.UnmarshalRaw(pubBytes)
if err != nil {
return err
}
priv.SetMasterPublicKey(masterPK)
}
return nil
}
// GenerateEncryptMasterKey generates a master public and private key pair for encryption usage. // GenerateEncryptMasterKey generates a master public and private key pair for encryption usage.
func GenerateEncryptMasterKey(rand io.Reader) (*EncryptMasterPrivateKey, error) { func GenerateEncryptMasterKey(rand io.Reader) (*EncryptMasterPrivateKey, error) {
k, err := randFieldElement(rand) k, err := randFieldElement(rand)
@ -367,6 +427,33 @@ func (pub *EncryptMasterPublicKey) MarshalCompressedASN1() ([]byte, error) {
return b.Bytes() return b.Bytes()
} }
// UnmarshalRaw unmarsal raw bytes data to encrypt master public key
func (pub *EncryptMasterPublicKey) UnmarshalRaw(bytes []byte) error {
g, err := unmarshalG1(bytes)
if err != nil {
return err
}
pub.MasterPublicKey = g
return nil
}
// ParseFromPEM just for GMSSL, there are no Algorithm pkix.AlgorithmIdentifier
func (pub *EncryptMasterPublicKey) ParseFromPEM(data []byte) error {
block, _ := pem.Decode([]byte(data))
if block == nil {
return errors.New("failed to parse PEM block")
}
var pki publicKeyInfo
if rest, err := asn1.Unmarshal(block.Bytes, &pki); err != nil {
return err
} else if len(rest) != 0 {
return errors.New("trailing data after ASN.1 of public-key")
}
der := cryptobyte.String(pki.PublicKey.RightAlign())
return pub.UnmarshalRaw(der)
}
// UnmarshalASN1 unmarsal der data to encrypt master public key // UnmarshalASN1 unmarsal der data to encrypt master public key
func (pub *EncryptMasterPublicKey) UnmarshalASN1(der []byte) error { func (pub *EncryptMasterPublicKey) UnmarshalASN1(der []byte) error {
var bytes []byte var bytes []byte
@ -374,12 +461,7 @@ func (pub *EncryptMasterPublicKey) UnmarshalASN1(der []byte) error {
if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() { if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() {
return errors.New("sm9: invalid encrypt master public key asn1 data") return errors.New("sm9: invalid encrypt master public key asn1 data")
} }
g, err := unmarshalG1(bytes) return pub.UnmarshalRaw(bytes)
if err != nil {
return err
}
pub.MasterPublicKey = g
return nil
} }
// MasterPublic returns the master public key corresponding to priv. // MasterPublic returns the master public key corresponding to priv.
@ -410,14 +492,9 @@ func (priv *EncryptPrivateKey) MarshalCompressedASN1() ([]byte, error) {
return b.Bytes() return b.Bytes()
} }
// UnmarshalASN1 unmarsal der data to encrypt user private key // UnmarshalRaw unmarsal raw bytes data to encrypt user private key
// Note, priv's EncryptMasterPublicKey should be handled separately. // Note, priv's EncryptMasterPublicKey should be handled separately.
func (priv *EncryptPrivateKey) UnmarshalASN1(der []byte) error { func (priv *EncryptPrivateKey) UnmarshalRaw(bytes []byte) error {
var bytes []byte
input := cryptobyte.String(der)
if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() {
return errors.New("sm9: invalid encrypt user private key asn1 data")
}
g, err := unmarshalG2(bytes) g, err := unmarshalG2(bytes)
if err != nil { if err != nil {
return err return err
@ -426,6 +503,40 @@ func (priv *EncryptPrivateKey) UnmarshalASN1(der []byte) error {
return nil return nil
} }
// UnmarshalASN1 unmarsal der data to encrypt user private key
// Note, priv's EncryptMasterPublicKey should be handled separately.
func (priv *EncryptPrivateKey) UnmarshalASN1(der []byte) error {
var bytes []byte
var pubBytes []byte
var inner cryptobyte.String
input := cryptobyte.String(der)
if der[0] == 0x30 {
if !input.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) ||
!input.Empty() ||
!inner.ReadASN1BitStringAsBytes(&bytes) {
return errors.New("sm9: invalid encrypt user private key asn1 data")
}
if !inner.Empty() && (!inner.ReadASN1BitStringAsBytes(&pubBytes) || !inner.Empty()) {
return errors.New("sm9: invalid encrypt master public key asn1 data")
}
} else if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() {
return errors.New("sm9: invalid encrypt user private key asn1 data")
}
err := priv.UnmarshalRaw(bytes)
if err != nil {
return err
}
if len(pubBytes) > 0 {
masterPK := new(EncryptMasterPublicKey)
err = masterPK.UnmarshalRaw(pubBytes)
if err != nil {
return err
}
priv.SetMasterPublicKey(masterPK)
}
return nil
}
// fermatInverse calculates the inverse of k in GF(P) using Fermat's method // fermatInverse calculates the inverse of k in GF(P) using Fermat's method
// (exponentiation modulo P - 2, per Euler's theorem). This has better // (exponentiation modulo P - 2, per Euler's theorem). This has better
// constant-time properties than Euclid's method (implemented in // constant-time properties than Euclid's method (implemented in

View File

@ -253,3 +253,18 @@ func BenchmarkGenerateEncryptPrivKey(b *testing.B) {
} }
} }
} }
const sm9SignMasterPublicKeyFromGMSSL = `-----BEGIN SM9 SIGN MASTER PUBLIC KEY-----
MIGFA4GCAARvTUvk1ztAlmjlUK0kP3zdFEVHHr8HUL4sUbcnFoQPukP0AjurnySy
f1MY0Plzt4lZ5u0/6GC4zUjYEcjWiYV+bV9YCnOGVQAYfPr/a+4/alewf43qBJuX
Ri1gDhueE6gkoeZ4HHUu1wfhRbKRF8okwSO933f/ZSpLlYu1P7/ckw==
-----END SM9 SIGN MASTER PUBLIC KEY-----
`
func TestParseSM9SignMasterPublicKey(t *testing.T) {
key := new(SignMasterPublicKey)
err := key.ParseFromPEM([]byte(sm9SignMasterPublicKeyFromGMSSL))
if err != nil {
t.Fatal(err)
}
}

View File

@ -8,6 +8,13 @@ import (
"errors" "errors"
"github.com/emmansun/gmsm/sm2" "github.com/emmansun/gmsm/sm2"
"github.com/emmansun/gmsm/sm9"
)
var (
oidSM9 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 302}
oidSM9Sign = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 302, 1}
oidSM9Enc = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 302, 3}
) )
// pkcs8 reflects an ASN.1, PKCS #8 PrivateKey. See // pkcs8 reflects an ASN.1, PKCS #8 PrivateKey. See
@ -37,6 +44,9 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
} }
return nil, err return nil, err
} }
if privKey.Algo.Algorithm.Equal(oidSM9) || privKey.Algo.Algorithm.Equal(oidSM9Sign) || privKey.Algo.Algorithm.Equal(oidSM9Enc) {
return parseSM9PrivateKey(privKey)
}
if !privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA) { if !privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA) {
return x509.ParsePKCS8PrivateKey(der) return x509.ParsePKCS8PrivateKey(der)
} }
@ -57,6 +67,30 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
return key, err return key, err
} }
func parseSM9PrivateKey(privKey pkcs8) (key interface{}, err error) {
switch {
case privKey.Algo.Algorithm.Equal(oidSM9Sign):
sm9SignKey := new(sm9.SignPrivateKey)
err = sm9SignKey.UnmarshalASN1(privKey.PrivateKey)
if err != nil {
return
}
key = sm9SignKey
return
case privKey.Algo.Algorithm.Equal(oidSM9Enc):
sm9EncKey := new(sm9.EncryptPrivateKey)
err = sm9EncKey.UnmarshalASN1(privKey.PrivateKey)
if err != nil {
return
}
key = sm9EncKey
return
default:
return nil, errors.New("not support yet")
}
}
// MarshalPKCS8PrivateKey converts a private key to PKCS #8, ASN.1 DER form. // MarshalPKCS8PrivateKey converts a private key to PKCS #8, ASN.1 DER form.
// //
// The following key types are currently supported: *rsa.PrivateKey, *ecdsa.PrivateKey // The following key types are currently supported: *rsa.PrivateKey, *ecdsa.PrivateKey
@ -67,10 +101,72 @@ func MarshalPKCS8PrivateKey(key interface{}) ([]byte, error) {
switch k := key.(type) { switch k := key.(type) {
case *sm2.PrivateKey: case *sm2.PrivateKey:
return marshalPKCS8ECPrivateKey(&k.PrivateKey) return marshalPKCS8ECPrivateKey(&k.PrivateKey)
case *sm9.SignPrivateKey:
return marshalPKCS8SM9SignPrivateKey(k)
case *sm9.EncryptPrivateKey:
return marshalPKCS8SM9EncPrivateKey(k)
case *sm9.SignMasterPrivateKey:
return nil, errors.New("not implemented")
case *sm9.EncryptMasterPrivateKey:
return nil, errors.New("not implemented")
} }
return x509.MarshalPKCS8PrivateKey(key) return x509.MarshalPKCS8PrivateKey(key)
} }
type sm9PrivateKey struct {
PrivateKey asn1.RawValue
PublicKey asn1.RawValue
}
func marshalPKCS8SM9SignPrivateKey(k *sm9.SignPrivateKey) ([]byte, error) {
var privKey pkcs8
privKey.Algo = pkix.AlgorithmIdentifier{
Algorithm: oidSM9Sign,
Parameters: asn1.NullRawValue,
}
key := sm9PrivateKey{}
privans1, err := k.MarshalASN1()
if err != nil {
return nil, err
}
pubasn1, err := k.MasterPublic().MarshalASN1()
if err != nil {
return nil, err
}
key.PrivateKey.FullBytes = privans1
key.PublicKey.FullBytes = pubasn1
if privKey.PrivateKey, err = asn1.Marshal(key); err != nil {
return nil, errors.New("x509: failed to marshal sm9 sign private key while building PKCS#8: " + err.Error())
}
return asn1.Marshal(privKey)
}
func marshalPKCS8SM9EncPrivateKey(k *sm9.EncryptPrivateKey) ([]byte, error) {
var privKey pkcs8
privKey.Algo = pkix.AlgorithmIdentifier{
Algorithm: oidSM9Enc,
Parameters: asn1.NullRawValue,
}
key := sm9PrivateKey{}
privans1, err := k.MarshalASN1()
if err != nil {
return nil, err
}
pubasn1, err := k.MasterPublic().MarshalASN1()
if err != nil {
return nil, err
}
key.PrivateKey.FullBytes = privans1
key.PublicKey.FullBytes = pubasn1
if privKey.PrivateKey, err = asn1.Marshal(key); err != nil {
return nil, errors.New("x509: failed to marshal sm9 encrypt private key while building PKCS#8: " + err.Error())
}
return asn1.Marshal(privKey)
}
func marshalPKCS8ECPrivateKey(k *ecdsa.PrivateKey) ([]byte, error) { func marshalPKCS8ECPrivateKey(k *ecdsa.PrivateKey) ([]byte, error) {
var privKey pkcs8 var privKey pkcs8
oid, ok := oidFromNamedCurve(k.Curve) oid, ok := oidFromNamedCurve(k.Curve)

View File

@ -14,6 +14,7 @@ import (
"testing" "testing"
"github.com/emmansun/gmsm/sm2" "github.com/emmansun/gmsm/sm2"
"github.com/emmansun/gmsm/sm9"
) )
// Generated using: // Generated using:
@ -155,3 +156,57 @@ func TestMarshalPKCS8SM2PrivateKey(t *testing.T) {
} }
fmt.Printf("%s\n", hex.EncodeToString(res)) fmt.Printf("%s\n", hex.EncodeToString(res))
} }
func TestMarshalPKCS8SM9SignPrivateKey(t *testing.T) {
masterKey, err := sm9.GenerateSignMasterKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
privateKey, err := masterKey.GenerateUserKey([]byte("emmansun"), 0x01)
if err != nil {
t.Fatal(err)
}
res, err := MarshalPKCS8PrivateKey(privateKey)
if err != nil {
t.Fatal(err)
}
privateKey1, err := ParsePKCS8PrivateKey(res)
if err != nil {
t.Fatal(err)
}
privateKey2, ok := privateKey1.(*sm9.SignPrivateKey)
if !ok {
t.Fatalf("not expected key")
}
if !privateKey.PrivateKey.Equal(privateKey2.PrivateKey) ||
!privateKey.MasterPublicKey.Equal(privateKey2.MasterPublicKey) {
t.Fatalf("not same key")
}
}
func TestMarshalPKCS8SM9EncPrivateKey(t *testing.T) {
masterKey, err := sm9.GenerateEncryptMasterKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
privateKey, err := masterKey.GenerateUserKey([]byte("emmansun"), 0x01)
if err != nil {
t.Fatal(err)
}
res, err := MarshalPKCS8PrivateKey(privateKey)
if err != nil {
t.Fatal(err)
}
privateKey1, err := ParsePKCS8PrivateKey(res)
if err != nil {
t.Fatal(err)
}
privateKey2, ok := privateKey1.(*sm9.EncryptPrivateKey)
if !ok {
t.Fatalf("not expected key")
}
if !privateKey.PrivateKey.Equal(privateKey2.PrivateKey) ||
!privateKey.MasterPublicKey.Equal(privateKey2.MasterPublicKey) {
t.Fatalf("not same key")
}
}