Merge pull request #73 from Trisia/main

SM2密钥交换方法初始化
This commit is contained in:
Sun Yimin 2022-08-14 11:22:52 +08:00 committed by GitHub
commit c37e143c66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 191 additions and 4 deletions

View File

@ -35,10 +35,14 @@ func (ke *KeyExchange) GetSharedKey() []byte {
}
// NewKeyExchange create one new KeyExchange object
//
// 在部分场景中,在初始 KeyExchange 时暂时没有对端的公开信息如公钥、UID这些信息可能需要在后续的交换中得到。
// 这种情况下,可设置 peerPub、peerUID 参数为 nil并在合适的时候通过 KeyExchange.SetPeerParameters 方法配置相关参数。
// 注意 KeyExchange.SetPeerParameters 方法必须要在 KeyExchange.RepondKeyExchange 或 KeyExchange.RepondKeyExchange 方法之前调用。
func NewKeyExchange(priv *PrivateKey, peerPub *ecdsa.PublicKey, uid, peerUID []byte, keyLen int, genSignature bool) (ke *KeyExchange, err error) {
ke = &KeyExchange{}
ke.genSignature = genSignature
ke.peerPub = peerPub
ke.keyLength = keyLen
ke.privateKey = priv
w := (priv.Params().N.BitLen()+1)/2 - 1
@ -48,24 +52,55 @@ func NewKeyExchange(priv *PrivateKey, peerPub *ecdsa.PublicKey, uid, peerUID []b
x2minus1 := (&big.Int{}).Sub(x2, big.NewInt(1))
ke.w2Minus1 = x2minus1
if len(uid) == 0 {
uid = defaultUID
}
ke.z, err = calculateZA(&ke.privateKey.PublicKey, uid)
if err != nil {
return nil, err
}
ke.peerZ, err = calculateZA(ke.peerPub, peerUID)
err = ke.SetPeerParameters(peerPub, peerUID)
if err != nil {
return nil, err
}
ke.secret = &ecdsa.PublicKey{}
ke.secret.Curve = priv.PublicKey.Curve
ke.peerSecret = &ecdsa.PublicKey{}
ke.peerSecret.Curve = peerPub.Curve
ke.v = &ecdsa.PublicKey{}
ke.v.Curve = priv.PublicKey.Curve
return
}
// SetPeerParameters 设置对端公开信息,该方法用于某些初期状态无法取得对端公开参数的场景。
// 例如在TLCP协议中基于SM2算法ECDHE过程。
//
// 注意该方法仅在 NewKeyExchange 没有提供 peerPub、peerUID参数时允许被调用
// 且该方法只能调用一次不可重复调用若多次调用或peerPub、peerUID已经存在则会发生错误。
func (ke *KeyExchange) SetPeerParameters(peerPub *ecdsa.PublicKey, peerUID []byte) error {
if peerPub == nil {
return nil
}
if len(peerUID) == 0 {
peerUID = defaultUID
}
if ke.peerPub != nil {
return errors.New("sm2: 'peerPub' already exists, please do not set it")
}
var err error
ke.peerPub = peerPub
ke.peerZ, err = calculateZA(ke.peerPub, peerUID)
if err != nil {
return err
}
ke.peerSecret = &ecdsa.PublicKey{}
ke.peerSecret.Curve = peerPub.Curve
return nil
}
func initKeyExchange(ke *KeyExchange, r *big.Int) {
ke.secret.X, ke.secret.Y = ke.privateKey.ScalarBaseMult(r.Bytes())
ke.r = r
@ -154,6 +189,9 @@ func respondKeyExchange(ke *KeyExchange, r *big.Int, rA *ecdsa.PublicKey) (*ecds
// RepondKeyExchange when responder receive rA, for responder's step B1-B8
func (ke *KeyExchange) RepondKeyExchange(rand io.Reader, rA *ecdsa.PublicKey) (*ecdsa.PublicKey, []byte, error) {
if ke.peerPub == nil {
return nil, nil, errors.New("sm2: peer public not set, you probable need call KeyExchange.SetPeerParameters")
}
if !ke.privateKey.IsOnCurve(rA.X, rA.Y) {
return nil, nil, errors.New("sm2: received invalid random from initiator")
}
@ -167,6 +205,9 @@ func (ke *KeyExchange) RepondKeyExchange(rand io.Reader, rA *ecdsa.PublicKey) (*
// ConfirmResponder for initiator's step A4-A10
func (ke *KeyExchange) ConfirmResponder(rB *ecdsa.PublicKey, sB []byte) ([]byte, error) {
if ke.peerPub == nil {
return nil, errors.New("sm2: peer public not set, you probable need call KeyExchange.SetPeerParameters")
}
if !ke.privateKey.IsOnCurve(rB.X, rB.Y) {
return nil, errors.New("sm2: received invalid random from responder")
}

View File

@ -3,6 +3,7 @@ package sm2
import (
"crypto/rand"
"encoding/hex"
"errors"
"testing"
)
@ -41,3 +42,148 @@ func TestKeyExchangeSample(t *testing.T) {
t.Errorf("got different key")
}
}
func TestSetPeerParameters(t *testing.T) {
priv1, _ := GenerateKey(rand.Reader)
priv2, _ := GenerateKey(rand.Reader)
uidA := []byte("Alice")
uidB := []byte("Bob")
initiator, err := NewKeyExchange(priv1, nil, uidA, uidB, 32, true)
if err != nil {
t.Fatal(err)
}
responder, err := NewKeyExchange(priv2, nil, uidB, uidA, 32, true)
if err != nil {
t.Fatal(err)
}
rA, err := initiator.InitKeyExchange(rand.Reader)
if err != nil {
t.Fatal(err)
}
// 设置对端参数
err = initiator.SetPeerParameters(&priv2.PublicKey, uidB)
if err != nil {
t.Fatal(err)
}
err = responder.SetPeerParameters(&priv1.PublicKey, uidA)
if err != nil {
t.Fatal(err)
}
rB, s2, err := responder.RepondKeyExchange(rand.Reader, rA)
if err != nil {
t.Fatal(err)
}
s1, err := initiator.ConfirmResponder(rB, s2)
if err != nil {
t.Fatal(err)
}
err = responder.ConfirmInitiator(s1)
if err != nil {
t.Fatal(err)
}
if hex.EncodeToString(initiator.key) != hex.EncodeToString(responder.key) {
t.Errorf("got different key")
}
}
func TestKeyExchange_SetPeerParameters(t *testing.T) {
priv1, _ := GenerateKey(rand.Reader)
priv2, _ := GenerateKey(rand.Reader)
uidA := []byte("Alice")
uidB := []byte("Bob")
initiator, err := NewKeyExchange(priv1, nil, uidA, nil, 32, true)
if err != nil {
t.Fatal(err)
}
responder, err := NewKeyExchange(priv2, nil, uidB, nil, 32, true)
if err != nil {
t.Fatal(err)
}
rA, err := initiator.InitKeyExchange(rand.Reader)
if err != nil {
t.Fatal(err)
}
// 设置对端参数
err = initiator.SetPeerParameters(&priv2.PublicKey, uidB)
if err != nil {
t.Fatal(err)
}
err = responder.SetPeerParameters(&priv1.PublicKey, uidA)
if err != nil {
t.Fatal(err)
}
rB, s2, err := responder.RepondKeyExchange(rand.Reader, rA)
if err != nil {
t.Fatal(err)
}
s1, err := initiator.ConfirmResponder(rB, s2)
if err != nil {
t.Fatal(err)
}
err = responder.ConfirmInitiator(s1)
if err != nil {
t.Fatal(err)
}
if hex.EncodeToString(initiator.key) != hex.EncodeToString(responder.key) {
t.Errorf("got different key")
}
}
func TestKeyExchange_SetPeerParameters_ErrCase(t *testing.T) {
priv1, _ := GenerateKey(rand.Reader)
priv2, _ := GenerateKey(rand.Reader)
uidA := []byte("Alice")
uidB := []byte("Bob")
initiator, err := NewKeyExchange(priv1, nil, uidA, nil, 32, true)
if err != nil {
t.Fatal(err)
}
responder, err := NewKeyExchange(priv2, &priv1.PublicKey, uidB, uidA, 32, true)
if err != nil {
t.Fatal(err)
}
rA, err := initiator.InitKeyExchange(rand.Reader)
if err != nil {
t.Fatal(err)
}
rB, s2, err := responder.RepondKeyExchange(rand.Reader, rA)
if err != nil {
t.Fatal(err)
}
_, err = initiator.ConfirmResponder(rB, s2)
if err == nil {
t.Fatal(errors.New("expect call ConfirmResponder got a error, but not"))
}
err = initiator.SetPeerParameters(&priv2.PublicKey, uidB)
if err != nil {
t.Fatal(err)
}
err = initiator.SetPeerParameters(&priv2.PublicKey, uidB)
if err == nil {
t.Fatal(errors.New("expect call SetPeerParameters repeat got a error, but not"))
}
err = responder.SetPeerParameters(&priv1.PublicKey, uidA)
if err == nil {
t.Fatal(errors.New("expect responder call SetPeerParameters got a error, but not"))
}
}