mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-27 04:36:19 +08:00
SM9: supplement comment and sample test case
This commit is contained in:
parent
14af2513d8
commit
3320de17b8
23
sm9/sm9.go
23
sm9/sm9.go
@ -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")
|
||||||
|
@ -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.
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user