SM9: supplement comment and sample test case

This commit is contained in:
Sun Yimin 2022-06-16 08:46:28 +08:00 committed by GitHub
parent 14af2513d8
commit 3320de17b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 25 deletions

View File

@ -16,6 +16,8 @@ import (
"golang.org/x/crypto/cryptobyte/asn1" "golang.org/x/crypto/cryptobyte/asn1"
) )
// SM9 ASN.1 format reference: Information security technology - SM9 cryptographic algorithm application specification
var bigOne = big.NewInt(1) var bigOne = big.NewInt(1)
type hashMode byte type hashMode byte
@ -84,6 +86,7 @@ func randFieldElement(rand io.Reader) (k *big.Int, err error) {
return return
} }
// Pair generate the basepoint once
func (pub *SignMasterPublicKey) Pair() *GT { func (pub *SignMasterPublicKey) Pair() *GT {
pub.pairOnce.Do(func() { pub.pairOnce.Do(func() {
pub.basePoint = Pair(Gen1, pub.MasterPublicKey) pub.basePoint = Pair(Gen1, pub.MasterPublicKey)
@ -116,6 +119,7 @@ func (pub *SignMasterPublicKey) generatorTable() *[32 * 2]gtTable {
return pub.table return pub.table
} }
// ScalarBaseMult compute basepoint^r with precomputed table
func (pub *SignMasterPublicKey) ScalarBaseMult(r *big.Int) *GT { func (pub *SignMasterPublicKey) ScalarBaseMult(r *big.Int) *GT {
scalar := normalizeScalar(r.Bytes()) scalar := normalizeScalar(r.Bytes())
tables := pub.generatorTable() tables := pub.generatorTable()
@ -176,6 +180,7 @@ func Sign(rand io.Reader, priv *SignPrivateKey, hash []byte) (h *big.Int, s *G1,
// Sign signs digest with user's DSA key, reading randomness from rand. The opts argument // Sign signs digest with user's DSA key, reading randomness from rand. The opts argument
// is not currently used but, in keeping with the crypto.Signer interface. // is not currently used but, in keeping with the crypto.Signer interface.
// The result is SM9Signature ASN.1 format.
func (priv *SignPrivateKey) Sign(rand io.Reader, hash []byte, opts crypto.SignerOpts) ([]byte, error) { func (priv *SignPrivateKey) Sign(rand io.Reader, hash []byte, opts crypto.SignerOpts) ([]byte, error) {
h, s, err := Sign(rand, priv, hash) h, s, err := Sign(rand, priv, hash)
if err != nil { if err != nil {
@ -194,7 +199,7 @@ func (priv *SignPrivateKey) Sign(rand io.Reader, hash []byte, opts crypto.Signer
} }
// SignASN1 signs a hash (which should be the result of hashing a larger message) // SignASN1 signs a hash (which should be the result of hashing a larger message)
// using the private key, priv. It returns the ASN.1 encoded signature. // using the private key, priv. It returns the ASN.1 encoded signature of type SM9Signature.
func SignASN1(rand io.Reader, priv *SignPrivateKey, hash []byte) ([]byte, error) { func SignASN1(rand io.Reader, priv *SignPrivateKey, hash []byte) ([]byte, error) {
return priv.Sign(rand, hash, nil) return priv.Sign(rand, hash, nil)
} }
@ -225,7 +230,7 @@ func Verify(pub *SignMasterPublicKey, uid []byte, hid byte, hash []byte, h *big.
return h.Cmp(h2) == 0 return h.Cmp(h2) == 0
} }
// VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the // VerifyASN1 verifies the ASN.1 encoded signature of type SM9Signature, sig, of hash using the
// public key, pub. Its return value records whether the signature is valid. // public key, pub. Its return value records whether the signature is valid.
func VerifyASN1(pub *SignMasterPublicKey, uid []byte, hid byte, hash, sig []byte) bool { func VerifyASN1(pub *SignMasterPublicKey, uid []byte, hid byte, hash, sig []byte) bool {
var ( var (
@ -260,6 +265,7 @@ func (pub *SignMasterPublicKey) Verify(uid []byte, hid byte, hash, sig []byte) b
return VerifyASN1(pub, uid, hid, hash, sig) return VerifyASN1(pub, uid, hid, hash, sig)
} }
// Pair generate the basepoint once
func (pub *EncryptMasterPublicKey) Pair() *GT { func (pub *EncryptMasterPublicKey) Pair() *GT {
pub.pairOnce.Do(func() { pub.pairOnce.Do(func() {
pub.basePoint = Pair(pub.MasterPublicKey, Gen2) pub.basePoint = Pair(pub.MasterPublicKey, Gen2)
@ -292,6 +298,7 @@ func (pub *EncryptMasterPublicKey) generatorTable() *[32 * 2]gtTable {
return pub.table return pub.table
} }
// ScalarBaseMult compute basepoint^r with precomputed table
func (pub *EncryptMasterPublicKey) ScalarBaseMult(r *big.Int) *GT { func (pub *EncryptMasterPublicKey) ScalarBaseMult(r *big.Int) *GT {
scalar := normalizeScalar(r.Bytes()) scalar := normalizeScalar(r.Bytes())
tables := pub.generatorTable() tables := pub.generatorTable()
@ -346,7 +353,7 @@ func WrapKey(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte,
return return
} }
// WrapKey wrap key and marshal the cipher as ASN1 format. // WrapKey wrap key and marshal the cipher as ASN1 format, SM9PublicKey1 definition.
func (pub *EncryptMasterPublicKey) WrapKey(rand io.Reader, uid []byte, hid byte, kLen int) ([]byte, []byte, error) { func (pub *EncryptMasterPublicKey) WrapKey(rand io.Reader, uid []byte, hid byte, kLen int) ([]byte, []byte, error) {
key, cipher, err := WrapKey(rand, pub, uid, hid, kLen) key, cipher, err := WrapKey(rand, pub, uid, hid, kLen)
if err != nil { if err != nil {
@ -360,7 +367,7 @@ func (pub *EncryptMasterPublicKey) WrapKey(rand io.Reader, uid []byte, hid byte,
} }
// WrapKeyASN1 wrap key and marshal the result of SM9KeyPackage as ASN1 format. according // WrapKeyASN1 wrap key and marshal the result of SM9KeyPackage as ASN1 format. according
// SM9 cryptographic algorithm application specification // SM9 cryptographic algorithm application specification, SM9KeyPackage defnition.
func (pub *EncryptMasterPublicKey) WrapKeyASN1(rand io.Reader, uid []byte, hid byte, kLen int) ([]byte, error) { func (pub *EncryptMasterPublicKey) WrapKeyASN1(rand io.Reader, uid []byte, hid byte, kLen int) ([]byte, error) {
key, cipher, err := WrapKey(rand, pub, uid, hid, kLen) key, cipher, err := WrapKey(rand, pub, uid, hid, kLen)
if err != nil { if err != nil {
@ -416,6 +423,8 @@ func UnwrapKey(priv *EncryptPrivateKey, uid []byte, cipher *G1, kLen int) ([]byt
return key, nil return key, nil
} }
// UnwrapKey unwrap key from cipherDer, user id and aligned key length.
// cipherDer is SM9PublicKey1 format according SM9 cryptographic algorithm application specification.
func (priv *EncryptPrivateKey) UnwrapKey(uid, cipherDer []byte, kLen int) ([]byte, error) { func (priv *EncryptPrivateKey) UnwrapKey(uid, cipherDer []byte, kLen int) ([]byte, error) {
var bytes []byte var bytes []byte
input := cryptobyte.String(cipherDer) input := cryptobyte.String(cipherDer)
@ -447,13 +456,13 @@ func Encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte,
} }
// EncryptASN1 encrypt plaintext and output ciphertext with ASN.1 format according // EncryptASN1 encrypt plaintext and output ciphertext with ASN.1 format according
// SM9 cryptographic algorithm application specification // SM9 cryptographic algorithm application specification, SM9Cipher definition.
func EncryptASN1(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte) ([]byte, error) { func EncryptASN1(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte) ([]byte, error) {
return pub.Encrypt(rand, uid, hid, plaintext) return pub.Encrypt(rand, uid, hid, plaintext)
} }
// Encrypt encrypt plaintext and output ciphertext with ASN.1 format according // Encrypt encrypt plaintext and output ciphertext with ASN.1 format according
// SM9 cryptographic algorithm application specification // SM9 cryptographic algorithm application specification, SM9Cipher definition.
func (pub *EncryptMasterPublicKey) Encrypt(rand io.Reader, uid []byte, hid byte, plaintext []byte) ([]byte, error) { func (pub *EncryptMasterPublicKey) Encrypt(rand io.Reader, uid []byte, hid byte, plaintext []byte) ([]byte, error) {
key, cipher, err := WrapKey(rand, pub, uid, hid, len(plaintext)+sm3.Size) key, cipher, err := WrapKey(rand, pub, uid, hid, len(plaintext)+sm3.Size)
if err != nil { if err != nil {
@ -504,7 +513,7 @@ func Decrypt(priv *EncryptPrivateKey, uid, ciphertext []byte) ([]byte, error) {
} }
// DecryptASN1 decrypt chipher, ciphertext should be with ASN.1 format according // DecryptASN1 decrypt chipher, ciphertext should be with ASN.1 format according
// SM9 cryptographic algorithm application specification // SM9 cryptographic algorithm application specification, SM9Cipher definition.
func DecryptASN1(priv *EncryptPrivateKey, uid, ciphertext []byte) ([]byte, error) { func DecryptASN1(priv *EncryptPrivateKey, uid, ciphertext []byte) ([]byte, error) {
if len(ciphertext) <= 32+65 { if len(ciphertext) <= 32+65 {
return nil, errors.New("sm9: invalid ciphertext length") return nil, errors.New("sm9: invalid ciphertext length")

View File

@ -9,40 +9,46 @@ import (
"golang.org/x/crypto/cryptobyte" "golang.org/x/crypto/cryptobyte"
) )
// SignMasterPrivateKey master private key for sign, generated by KGC
type SignMasterPrivateKey struct { type SignMasterPrivateKey struct {
SignMasterPublicKey SignMasterPublicKey // master public key
D *big.Int D *big.Int // master private key
} }
// SignMasterPublicKey master public key for sign, generated by KGC
type SignMasterPublicKey struct { type SignMasterPublicKey struct {
MasterPublicKey *G2 MasterPublicKey *G2 // master public key
pairOnce sync.Once pairOnce sync.Once
basePoint *GT basePoint *GT // the result of Pair(Gen1, pub.MasterPublicKey)
tableGenOnce sync.Once tableGenOnce sync.Once
table *[32 * 2]gtTable table *[32 * 2]gtTable // precomputed basePoint^n
} }
// SignPrivateKey user private key for sign, generated by KGC
type SignPrivateKey struct { type SignPrivateKey struct {
PrivateKey *G1 PrivateKey *G1 // user private key
SignMasterPublicKey SignMasterPublicKey // master public key
} }
// EncryptMasterPrivateKey master private key for encryption, generated by KGC
type EncryptMasterPrivateKey struct { type EncryptMasterPrivateKey struct {
EncryptMasterPublicKey EncryptMasterPublicKey // master public key
D *big.Int D *big.Int // master private key
} }
// EncryptMasterPublicKey master private key for encryption, generated by KGC
type EncryptMasterPublicKey struct { type EncryptMasterPublicKey struct {
MasterPublicKey *G1 MasterPublicKey *G1 // public key
pairOnce sync.Once pairOnce sync.Once
basePoint *GT basePoint *GT // the result of Pair(pub.MasterPublicKey, Gen2)
tableGenOnce sync.Once tableGenOnce sync.Once
table *[32 * 2]gtTable table *[32 * 2]gtTable // precomputed basePoint^n
} }
// EncryptPrivateKey user private key for encryption, generated by KGC
type EncryptPrivateKey struct { type EncryptPrivateKey struct {
PrivateKey *G2 PrivateKey *G2 // user private key
EncryptMasterPublicKey EncryptMasterPublicKey // master public key
} }
// GenerateSignMasterKey generates a master public and private key pair for DSA usage. // GenerateSignMasterKey generates a master public and private key pair for DSA usage.

View File

@ -39,7 +39,9 @@ func TestSignMasterPublicKeyMarshalASN1(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if masterKey.MasterPublicKey.p.x != pub2.MasterPublicKey.p.x || masterKey.MasterPublicKey.p.y != pub2.MasterPublicKey.p.y || masterKey.MasterPublicKey.p.z != pub2.MasterPublicKey.p.z { if masterKey.MasterPublicKey.p.x != pub2.MasterPublicKey.p.x ||
masterKey.MasterPublicKey.p.y != pub2.MasterPublicKey.p.y ||
masterKey.MasterPublicKey.p.z != pub2.MasterPublicKey.p.z {
t.Errorf("not same") t.Errorf("not same")
} }
} }
@ -64,7 +66,8 @@ func TestSignUserPrivateKeyMarshalASN1(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if userKey.PrivateKey.p.x != userKey2.PrivateKey.p.x || userKey.PrivateKey.p.y != userKey2.PrivateKey.p.y { if userKey.PrivateKey.p.x != userKey2.PrivateKey.p.x ||
userKey.PrivateKey.p.y != userKey2.PrivateKey.p.y {
t.Errorf("not same") t.Errorf("not same")
} }
} }
@ -102,7 +105,8 @@ func TestEncryptMasterPublicKeyMarshalASN1(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if masterKey.MasterPublicKey.p.x != pub2.MasterPublicKey.p.x || masterKey.MasterPublicKey.p.y != pub2.MasterPublicKey.p.y { if masterKey.MasterPublicKey.p.x != pub2.MasterPublicKey.p.x ||
masterKey.MasterPublicKey.p.y != pub2.MasterPublicKey.p.y {
t.Errorf("not same") t.Errorf("not same")
} }
} }
@ -127,7 +131,9 @@ func TestEncryptUserPrivateKeyMarshalASN1(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if userKey.PrivateKey.p.x != userKey2.PrivateKey.p.x || userKey.PrivateKey.p.y != userKey2.PrivateKey.p.y || userKey.PrivateKey.p.z != userKey2.PrivateKey.p.z { if userKey.PrivateKey.p.x != userKey2.PrivateKey.p.x ||
userKey.PrivateKey.p.y != userKey2.PrivateKey.p.y ||
userKey.PrivateKey.p.z != userKey2.PrivateKey.p.z {
t.Errorf("not same") t.Errorf("not same")
} }
} }

View File

@ -78,6 +78,45 @@ func TestSignASN1(t *testing.T) {
} }
} }
// SM9 Appendix A
func TestSignSM9Sample(t *testing.T) {
expectedH := bigFromHex("823c4b21e4bd2dfe1ed92c606653e996668563152fc33f55d7bfbb9bd9705adb")
expectedS := "0473bf96923ce58b6ad0e13e9643a406d8eb98417c50ef1b29cef9adb48b6d598c856712f1c2e0968ab7769f42a99586aed139d5b8b3e15891827cc2aced9baa05"
hash := []byte("Chinese IBS standard")
hid := byte(0x01)
uid := []byte("Alice")
r := bigFromHex("033c8616b06704813203dfd00965022ed15975c662337aed648835dc4b1cbe")
masterKey := new(SignMasterPrivateKey)
masterKey.D = bigFromHex("0130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4")
masterKey.MasterPublicKey = new(G2).ScalarBaseMult(masterKey.D)
userKey, err := masterKey.GenerateUserKey(uid, hid)
if err != nil {
t.Fatal(err)
}
w := userKey.SignMasterPublicKey.ScalarBaseMult(r)
var buffer []byte
buffer = append(buffer, hash...)
buffer = append(buffer, w.Marshal()...)
h := hashH2(buffer)
if h.Cmp(expectedH) != 0 {
t.Fatal("not same h")
}
l := new(big.Int).Sub(r, h)
if l.Sign() < 0 {
l.Add(l, Order)
}
s := new(G1).ScalarMult(userKey.PrivateKey, l)
if hex.EncodeToString(s.MarshalUncompressed()) != expectedS {
t.Fatal("not same S")
}
}
func TestWrapKey(t *testing.T) { func TestWrapKey(t *testing.T) {
masterKey, err := GenerateEncryptMasterKey(rand.Reader) masterKey, err := GenerateEncryptMasterKey(rand.Reader)
hid := byte(0x01) hid := byte(0x01)
@ -161,6 +200,7 @@ func TestUnmarshalSM9KeyPackage(t *testing.T) {
} }
} }
// SM9 Appendix C
func TestWrapKeySM9Sample(t *testing.T) { func TestWrapKeySM9Sample(t *testing.T) {
expectedKey := "4ff5cf86d2ad40c8f4bac98d76abdbde0c0e2f0a829d3f911ef5b2bce0695480" expectedKey := "4ff5cf86d2ad40c8f4bac98d76abdbde0c0e2f0a829d3f911ef5b2bce0695480"
masterKey := new(EncryptMasterPrivateKey) masterKey := new(EncryptMasterPrivateKey)
@ -209,6 +249,7 @@ func TestWrapKeySM9Sample(t *testing.T) {
} }
} }
// SM9 Appendix D
func TestEncryptSM9Sample(t *testing.T) { func TestEncryptSM9Sample(t *testing.T) {
plaintext := []byte("Chinese IBE standard") plaintext := []byte("Chinese IBE standard")
expectedCiphertext := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0ba672387bcd6de5016a158a52bb2e7fc429197bcab70b25afee37a2b9db9f3671b5f5b0e951489682f3e64e1378cdd5da9513b1c" expectedCiphertext := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0ba672387bcd6de5016a158a52bb2e7fc429197bcab70b25afee37a2b9db9f3671b5f5b0e951489682f3e64e1378cdd5da9513b1c"