diff --git a/pkcs8/kdf_pbkdf2.go b/pkcs8/kdf_pbkdf2.go index d071a1f..d579036 100644 --- a/pkcs8/kdf_pbkdf2.go +++ b/pkcs8/kdf_pbkdf2.go @@ -101,6 +101,7 @@ func newPRFParamFromHash(h Hash) (pkix.AlgorithmIdentifier, error) { type pbkdf2Params struct { Salt []byte IterationCount int + KeyLen int `asn1:"optional"` PRF pkix.AlgorithmIdentifier `asn1:"optional"` } @@ -127,7 +128,7 @@ func (p PBKDF2Opts) DeriveKey(password, salt []byte, size int) ( if err != nil { return nil, nil, err } - params = pbkdf2Params{salt, p.IterationCount, prfParam} + params = pbkdf2Params{salt, p.IterationCount, size, prfParam} return key, params, nil } diff --git a/pkcs8/pkcs8.go b/pkcs8/pkcs8.go index 83926ea..8a936b5 100644 --- a/pkcs8/pkcs8.go +++ b/pkcs8/pkcs8.go @@ -219,7 +219,7 @@ func ParsePrivateKey(der []byte, password []byte) (interface{}, KDFParameters, e key, err := smx509.ParsePKCS8PrivateKey(decryptedKey) 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 } diff --git a/pkcs8/pkcs8_norace_test.go b/pkcs8/pkcs8_norace_test.go index 2443f65..9095998 100644 --- a/pkcs8/pkcs8_norace_test.go +++ b/pkcs8/pkcs8_norace_test.go @@ -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) + }) + } +} diff --git a/sm9/sm9_key.go b/sm9/sm9_key.go index 6691545..d017593 100644 --- a/sm9/sm9_key.go +++ b/sm9/sm9_key.go @@ -1,6 +1,9 @@ package sm9 import ( + "encoding/asn1" + "encoding/pem" + "errors" "io" "math/big" @@ -8,6 +11,7 @@ import ( "github.com/emmansun/gmsm/sm9/bn256" "golang.org/x/crypto/cryptobyte" + cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" ) // SignMasterPrivateKey master private key for sign, generated by KGC @@ -180,6 +184,16 @@ func unmarshalG2(bytes []byte) (*bn256.G2, error) { 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 func (pub *SignMasterPublicKey) UnmarshalASN1(der []byte) error { var bytes []byte @@ -187,12 +201,29 @@ func (pub *SignMasterPublicKey) UnmarshalASN1(der []byte) error { if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() { return errors.New("sm9: invalid sign master public key asn1 data") } - g2, err := unmarshalG2(bytes) - if err != nil { - return err + return pub.UnmarshalRaw(bytes) +} + +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. @@ -242,14 +273,9 @@ func unmarshalG1(bytes []byte) (*bn256.G1, error) { 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. -func (priv *SignPrivateKey) UnmarshalASN1(der []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") - } +func (priv *SignPrivateKey) UnmarshalRaw(bytes []byte) error { g, err := unmarshalG1(bytes) if err != nil { return err @@ -258,6 +284,40 @@ func (priv *SignPrivateKey) UnmarshalASN1(der []byte) error { 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. func GenerateEncryptMasterKey(rand io.Reader) (*EncryptMasterPrivateKey, error) { k, err := randFieldElement(rand) @@ -367,6 +427,33 @@ func (pub *EncryptMasterPublicKey) MarshalCompressedASN1() ([]byte, error) { 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 func (pub *EncryptMasterPublicKey) UnmarshalASN1(der []byte) error { var bytes []byte @@ -374,12 +461,7 @@ func (pub *EncryptMasterPublicKey) UnmarshalASN1(der []byte) error { if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() { return errors.New("sm9: invalid encrypt master public key asn1 data") } - g, err := unmarshalG1(bytes) - if err != nil { - return err - } - pub.MasterPublicKey = g - return nil + return pub.UnmarshalRaw(bytes) } // MasterPublic returns the master public key corresponding to priv. @@ -410,14 +492,9 @@ func (priv *EncryptPrivateKey) MarshalCompressedASN1() ([]byte, error) { 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. -func (priv *EncryptPrivateKey) UnmarshalASN1(der []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") - } +func (priv *EncryptPrivateKey) UnmarshalRaw(bytes []byte) error { g, err := unmarshalG2(bytes) if err != nil { return err @@ -426,6 +503,40 @@ func (priv *EncryptPrivateKey) UnmarshalASN1(der []byte) error { 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 // (exponentiation modulo P - 2, per Euler's theorem). This has better // constant-time properties than Euclid's method (implemented in diff --git a/sm9/sm9_key_test.go b/sm9/sm9_key_test.go index 929c4c9..1a36f53 100644 --- a/sm9/sm9_key_test.go +++ b/sm9/sm9_key_test.go @@ -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) + } +} diff --git a/smx509/pkcs8.go b/smx509/pkcs8.go index 4f5e883..2dfec00 100644 --- a/smx509/pkcs8.go +++ b/smx509/pkcs8.go @@ -8,6 +8,13 @@ import ( "errors" "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 @@ -37,6 +44,9 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) { } 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) { return x509.ParsePKCS8PrivateKey(der) } @@ -57,6 +67,30 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) { 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. // // 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) { case *sm2.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) } +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) { var privKey pkcs8 oid, ok := oidFromNamedCurve(k.Curve) diff --git a/smx509/pkcs8_test.go b/smx509/pkcs8_test.go index 3650bcd..dfacbc4 100644 --- a/smx509/pkcs8_test.go +++ b/smx509/pkcs8_test.go @@ -14,6 +14,7 @@ import ( "testing" "github.com/emmansun/gmsm/sm2" + "github.com/emmansun/gmsm/sm9" ) // Generated using: @@ -155,3 +156,57 @@ func TestMarshalPKCS8SM2PrivateKey(t *testing.T) { } 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") + } +}