2022-07-15 16:42:39 +08:00
|
|
|
|
package sm2
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"crypto/ecdsa"
|
2022-08-17 11:17:18 +08:00
|
|
|
|
"crypto/subtle"
|
2022-07-15 16:42:39 +08:00
|
|
|
|
"errors"
|
|
|
|
|
"io"
|
|
|
|
|
"math/big"
|
|
|
|
|
|
|
|
|
|
"github.com/emmansun/gmsm/sm3"
|
|
|
|
|
)
|
|
|
|
|
|
2022-11-24 10:18:03 +08:00
|
|
|
|
// This file contains a math/big implementation of SM2 key exchange which is deprecated, please use ecdh instead.
|
|
|
|
|
|
2022-07-15 16:42:39 +08:00
|
|
|
|
// KeyExchange key exchange struct, include internal stat in whole key exchange flow.
|
|
|
|
|
// Initiator's flow will be: NewKeyExchange -> InitKeyExchange -> transmission -> ConfirmResponder
|
|
|
|
|
// Responder's flow will be: NewKeyExchange -> waiting ... -> RepondKeyExchange -> transmission -> ConfirmInitiator
|
|
|
|
|
type KeyExchange struct {
|
|
|
|
|
genSignature bool // control the optional sign/verify step triggered by responsder
|
|
|
|
|
keyLength int // key length
|
|
|
|
|
privateKey *PrivateKey // owner's encryption private key
|
|
|
|
|
z []byte // owner identifiable id
|
|
|
|
|
peerPub *ecdsa.PublicKey // peer public key
|
|
|
|
|
peerZ []byte // peer identifiable id
|
|
|
|
|
r *big.Int // Ephemeral Private Key, random which will be used to compute secret
|
|
|
|
|
secret *ecdsa.PublicKey // Ephemeral Public Key, generated secret which will be passed to peer
|
|
|
|
|
peerSecret *ecdsa.PublicKey // received peer's secret, Ephemeral Public Key
|
|
|
|
|
w2 *big.Int // internal state which will be used when compute the key and signature, 2^w
|
|
|
|
|
w2Minus1 *big.Int // internal state which will be used when compute the key and signature, 2^w – 1
|
|
|
|
|
v *ecdsa.PublicKey // internal state which will be used when compute the key and signature, u/v
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-24 16:53:11 +08:00
|
|
|
|
func destroyBigInt(n *big.Int) {
|
|
|
|
|
if n != nil {
|
|
|
|
|
n.SetInt64(0)
|
2022-08-24 15:15:58 +08:00
|
|
|
|
}
|
2022-08-24 16:53:11 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func destroyPublicKey(pub *ecdsa.PublicKey) {
|
|
|
|
|
if pub != nil {
|
|
|
|
|
destroyBigInt(pub.X)
|
|
|
|
|
destroyBigInt(pub.Y)
|
2022-08-24 15:15:58 +08:00
|
|
|
|
}
|
2022-08-24 16:53:11 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func destroyBytes(bytes []byte) {
|
|
|
|
|
for v := range bytes {
|
|
|
|
|
bytes[v] = 0
|
2022-08-24 15:15:58 +08:00
|
|
|
|
}
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-08-24 16:53:11 +08:00
|
|
|
|
// Destroy clear all internal state and Ephemeral private/public keys.
|
|
|
|
|
func (ke *KeyExchange) Destroy() {
|
|
|
|
|
destroyBytes(ke.z)
|
|
|
|
|
destroyBytes(ke.peerZ)
|
|
|
|
|
destroyBigInt(ke.r)
|
|
|
|
|
destroyPublicKey(ke.v)
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 16:42:39 +08:00
|
|
|
|
// NewKeyExchange create one new KeyExchange object
|
2022-08-13 15:18:47 +08:00
|
|
|
|
//
|
|
|
|
|
// 在部分场景中,在初始 KeyExchange 时暂时没有对端的公开信息(如公钥、UID),这些信息可能需要在后续的交换中得到。
|
2022-08-14 11:10:55 +08:00
|
|
|
|
// 这种情况下,可设置 peerPub、peerUID 参数为 nil,并在合适的时候通过 KeyExchange.SetPeerParameters 方法配置相关参数。
|
|
|
|
|
// 注意 KeyExchange.SetPeerParameters 方法必须要在 KeyExchange.RepondKeyExchange 或 KeyExchange.RepondKeyExchange 方法之前调用。
|
2022-07-15 16:42:39 +08:00
|
|
|
|
func NewKeyExchange(priv *PrivateKey, peerPub *ecdsa.PublicKey, uid, peerUID []byte, keyLen int, genSignature bool) (ke *KeyExchange, err error) {
|
|
|
|
|
ke = &KeyExchange{}
|
|
|
|
|
ke.genSignature = genSignature
|
2022-08-13 15:18:47 +08:00
|
|
|
|
|
2022-07-15 16:42:39 +08:00
|
|
|
|
ke.keyLength = keyLen
|
|
|
|
|
ke.privateKey = priv
|
2022-08-16 11:46:08 +08:00
|
|
|
|
|
|
|
|
|
one := big.NewInt(1)
|
|
|
|
|
/* compute w = [log2(n)/2 - 1] = 127 */
|
2022-07-15 16:42:39 +08:00
|
|
|
|
w := (priv.Params().N.BitLen()+1)/2 - 1
|
2022-08-16 11:46:08 +08:00
|
|
|
|
|
|
|
|
|
/* w2 = 2^w = 0x80000000000000000000000000000000 */
|
|
|
|
|
ke.w2 = (&big.Int{}).Lsh(one, uint(w))
|
|
|
|
|
/* x2minus1 = 2^w - 1 = 0x7fffffffffffffffffffffffffffffff */
|
|
|
|
|
ke.w2Minus1 = (&big.Int{}).Sub(ke.w2, one)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
|
2022-08-13 15:18:47 +08:00
|
|
|
|
if len(uid) == 0 {
|
|
|
|
|
uid = defaultUID
|
|
|
|
|
}
|
2022-11-23 10:20:13 +08:00
|
|
|
|
ke.z, err = CalculateZA(&ke.privateKey.PublicKey, uid)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2022-08-13 15:18:47 +08:00
|
|
|
|
|
2022-08-14 11:10:55 +08:00
|
|
|
|
err = ke.SetPeerParameters(peerPub, peerUID)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2022-08-13 15:18:47 +08:00
|
|
|
|
|
2022-07-15 16:42:39 +08:00
|
|
|
|
ke.secret = &ecdsa.PublicKey{}
|
|
|
|
|
ke.secret.Curve = priv.PublicKey.Curve
|
2022-08-13 15:18:47 +08:00
|
|
|
|
|
2022-07-15 16:42:39 +08:00
|
|
|
|
ke.v = &ecdsa.PublicKey{}
|
|
|
|
|
ke.v.Curve = priv.PublicKey.Curve
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-14 11:10:55 +08:00
|
|
|
|
// SetPeerParameters 设置对端公开信息,该方法用于某些初期状态无法取得对端公开参数的场景。
|
2022-08-13 15:18:47 +08:00
|
|
|
|
// 例如:在TLCP协议中,基于SM2算法ECDHE过程。
|
2022-08-14 11:10:55 +08:00
|
|
|
|
//
|
|
|
|
|
// 注意该方法仅在 NewKeyExchange 没有提供 peerPub、peerUID参数时允许被调用,
|
|
|
|
|
// 且该方法只能调用一次不可重复调用,若多次调用或peerPub、peerUID已经存在则会发生错误。
|
|
|
|
|
func (ke *KeyExchange) SetPeerParameters(peerPub *ecdsa.PublicKey, peerUID []byte) error {
|
2022-08-13 15:18:47 +08:00
|
|
|
|
if peerPub == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if len(peerUID) == 0 {
|
|
|
|
|
peerUID = defaultUID
|
|
|
|
|
}
|
2022-08-14 11:10:55 +08:00
|
|
|
|
if ke.peerPub != nil {
|
|
|
|
|
return errors.New("sm2: 'peerPub' already exists, please do not set it")
|
|
|
|
|
}
|
2022-08-13 15:18:47 +08:00
|
|
|
|
|
2022-08-19 11:39:02 +08:00
|
|
|
|
if peerPub.Curve != ke.privateKey.Curve {
|
2022-08-18 14:49:35 +08:00
|
|
|
|
return errors.New("sm2: peer public key is not expected/supported")
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-13 15:18:47 +08:00
|
|
|
|
var err error
|
|
|
|
|
ke.peerPub = peerPub
|
2022-11-23 10:20:13 +08:00
|
|
|
|
ke.peerZ, err = CalculateZA(ke.peerPub, peerUID)
|
2022-08-13 15:18:47 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
ke.peerSecret = &ecdsa.PublicKey{}
|
|
|
|
|
ke.peerSecret.Curve = peerPub.Curve
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 16:42:39 +08:00
|
|
|
|
func initKeyExchange(ke *KeyExchange, r *big.Int) {
|
|
|
|
|
ke.secret.X, ke.secret.Y = ke.privateKey.ScalarBaseMult(r.Bytes())
|
|
|
|
|
ke.r = r
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-17 11:17:18 +08:00
|
|
|
|
// InitKeyExchange is for initiator's step A1-A3, returns generated Ephemeral Public Key which will be passed to Reponder.
|
2022-07-15 16:42:39 +08:00
|
|
|
|
func (ke *KeyExchange) InitKeyExchange(rand io.Reader) (*ecdsa.PublicKey, error) {
|
|
|
|
|
r, err := randFieldElement(ke.privateKey, rand)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
initKeyExchange(ke, r)
|
|
|
|
|
return ke.secret, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ke *KeyExchange) sign(isResponder bool, prefix byte) []byte {
|
|
|
|
|
var buffer []byte
|
|
|
|
|
hash := sm3.New()
|
|
|
|
|
hash.Write(toBytes(ke.privateKey, ke.v.X))
|
|
|
|
|
if isResponder {
|
|
|
|
|
hash.Write(ke.peerZ)
|
|
|
|
|
hash.Write(ke.z)
|
|
|
|
|
hash.Write(toBytes(ke.privateKey, ke.peerSecret.X))
|
|
|
|
|
hash.Write(toBytes(ke.privateKey, ke.peerSecret.Y))
|
|
|
|
|
hash.Write(toBytes(ke.privateKey, ke.secret.X))
|
|
|
|
|
hash.Write(toBytes(ke.privateKey, ke.secret.Y))
|
|
|
|
|
} else {
|
|
|
|
|
hash.Write(ke.z)
|
|
|
|
|
hash.Write(ke.peerZ)
|
|
|
|
|
hash.Write(toBytes(ke.privateKey, ke.secret.X))
|
|
|
|
|
hash.Write(toBytes(ke.privateKey, ke.secret.Y))
|
|
|
|
|
hash.Write(toBytes(ke.privateKey, ke.peerSecret.X))
|
|
|
|
|
hash.Write(toBytes(ke.privateKey, ke.peerSecret.Y))
|
|
|
|
|
}
|
|
|
|
|
buffer = hash.Sum(nil)
|
|
|
|
|
hash.Reset()
|
|
|
|
|
hash.Write([]byte{prefix})
|
|
|
|
|
hash.Write(toBytes(ke.privateKey, ke.v.Y))
|
|
|
|
|
hash.Write(buffer)
|
|
|
|
|
return hash.Sum(nil)
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-24 15:15:58 +08:00
|
|
|
|
func (ke *KeyExchange) generateSharedKey(isResponder bool) ([]byte, error) {
|
2022-07-15 16:42:39 +08:00
|
|
|
|
var buffer []byte
|
|
|
|
|
buffer = append(buffer, toBytes(ke.privateKey, ke.v.X)...)
|
|
|
|
|
buffer = append(buffer, toBytes(ke.privateKey, ke.v.Y)...)
|
|
|
|
|
if isResponder {
|
|
|
|
|
buffer = append(buffer, ke.peerZ...)
|
|
|
|
|
buffer = append(buffer, ke.z...)
|
|
|
|
|
} else {
|
|
|
|
|
buffer = append(buffer, ke.z...)
|
|
|
|
|
buffer = append(buffer, ke.peerZ...)
|
|
|
|
|
}
|
2024-05-15 08:28:47 +08:00
|
|
|
|
return sm3.Kdf(buffer, ke.keyLength), nil
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-08-24 15:15:58 +08:00
|
|
|
|
// avf is the associative value function.
|
|
|
|
|
func (ke *KeyExchange) avf(x *big.Int) *big.Int {
|
|
|
|
|
t := (&big.Int{}).And(ke.w2Minus1, x)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
t.Add(ke.w2, t)
|
2022-08-24 15:15:58 +08:00
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-24 16:53:11 +08:00
|
|
|
|
// mqv implements SM2-MQV procedure
|
|
|
|
|
func (ke *KeyExchange) mqv() {
|
|
|
|
|
// implicitSig: (sPriv + avf(ePub) * ePriv) mod N
|
2022-08-24 15:15:58 +08:00
|
|
|
|
// Calculate x2`
|
|
|
|
|
t := ke.avf(ke.secret.X)
|
2022-08-17 11:17:18 +08:00
|
|
|
|
|
|
|
|
|
// Calculate tB
|
2022-07-15 16:42:39 +08:00
|
|
|
|
t.Mul(t, ke.r)
|
|
|
|
|
t.Add(t, ke.privateKey.D)
|
|
|
|
|
t.Mod(t, ke.privateKey.Params().N)
|
|
|
|
|
|
2022-08-24 16:53:11 +08:00
|
|
|
|
// new base point: peerPub + [x1](peerSecret)
|
2022-08-17 11:17:18 +08:00
|
|
|
|
// x1` = 2^w + (x & (2^w – 1))
|
2022-08-24 15:15:58 +08:00
|
|
|
|
x1 := ke.avf(ke.peerSecret.X)
|
2022-08-24 16:53:11 +08:00
|
|
|
|
// Point(x, y) = peerPub + [x1](peerSecret)
|
2022-08-24 15:15:58 +08:00
|
|
|
|
x, y := ke.privateKey.ScalarMult(ke.peerSecret.X, ke.peerSecret.Y, x1.Bytes())
|
|
|
|
|
x, y = ke.privateKey.Add(ke.peerPub.X, ke.peerPub.Y, x, y)
|
2022-08-24 16:53:11 +08:00
|
|
|
|
|
|
|
|
|
ke.v.X, ke.v.Y = ke.privateKey.ScalarMult(x, y, t.Bytes())
|
2022-08-24 15:15:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-09-02 14:03:51 +08:00
|
|
|
|
func respondKeyExchange(ke *KeyExchange, rA *ecdsa.PublicKey, r *big.Int) (*ecdsa.PublicKey, []byte, error) {
|
|
|
|
|
if ke.peerPub == nil {
|
|
|
|
|
return nil, nil, errors.New("sm2: no peer public key given")
|
|
|
|
|
}
|
|
|
|
|
if !ke.privateKey.IsOnCurve(rA.X, rA.Y) {
|
|
|
|
|
return nil, nil, errors.New("sm2: invalid initiator's ephemeral public key")
|
|
|
|
|
}
|
|
|
|
|
ke.peerSecret = rA
|
2022-08-24 15:15:58 +08:00
|
|
|
|
// secret = RB = [r]G
|
|
|
|
|
ke.secret.X, ke.secret.Y = ke.privateKey.ScalarBaseMult(r.Bytes())
|
|
|
|
|
ke.r = r
|
2022-07-15 16:42:39 +08:00
|
|
|
|
|
2022-08-24 16:53:11 +08:00
|
|
|
|
ke.mqv()
|
2022-07-15 16:42:39 +08:00
|
|
|
|
if ke.v.X.Sign() == 0 && ke.v.Y.Sign() == 0 {
|
2022-08-17 11:17:18 +08:00
|
|
|
|
return nil, nil, errors.New("sm2: key exchange failed, V is infinity point")
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !ke.genSignature {
|
|
|
|
|
return ke.secret, nil, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ke.secret, ke.sign(true, 0x02), nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-17 11:17:18 +08:00
|
|
|
|
// RepondKeyExchange is for responder's step B1-B8, returns generated Ephemeral Public Key and optional signature
|
|
|
|
|
// depends on KeyExchange.genSignature value.
|
|
|
|
|
//
|
|
|
|
|
// It will check if there are peer's public key and validate the peer's Ephemeral Public Key.
|
2022-07-15 16:42:39 +08:00
|
|
|
|
func (ke *KeyExchange) RepondKeyExchange(rand io.Reader, rA *ecdsa.PublicKey) (*ecdsa.PublicKey, []byte, error) {
|
|
|
|
|
r, err := randFieldElement(ke.privateKey, rand)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nil, err
|
|
|
|
|
}
|
2022-09-02 14:03:51 +08:00
|
|
|
|
return respondKeyExchange(ke, rA, r)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-08-24 15:15:58 +08:00
|
|
|
|
// ConfirmResponder for initiator's step A4-A10, returns keying data and optional signature.
|
2022-08-17 11:17:18 +08:00
|
|
|
|
//
|
|
|
|
|
// It will check if there are peer's public key and validate the peer's Ephemeral Public Key.
|
|
|
|
|
//
|
|
|
|
|
// If the peer's signature is not empty, then it will also validate the peer's
|
2022-08-17 11:36:50 +08:00
|
|
|
|
// signature and return generated signature depends on KeyExchange.genSignature value.
|
2022-08-24 15:15:58 +08:00
|
|
|
|
func (ke *KeyExchange) ConfirmResponder(rB *ecdsa.PublicKey, sB []byte) ([]byte, []byte, error) {
|
2022-08-13 15:18:47 +08:00
|
|
|
|
if ke.peerPub == nil {
|
2022-08-24 15:15:58 +08:00
|
|
|
|
return nil, nil, errors.New("sm2: no peer public key given")
|
2022-08-13 15:18:47 +08:00
|
|
|
|
}
|
2022-07-15 16:42:39 +08:00
|
|
|
|
if !ke.privateKey.IsOnCurve(rB.X, rB.Y) {
|
2022-08-24 15:15:58 +08:00
|
|
|
|
return nil, nil, errors.New("sm2: invalid responder's ephemeral public key")
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|
|
|
|
|
ke.peerSecret = rB
|
2022-08-16 11:46:08 +08:00
|
|
|
|
|
2022-08-24 16:53:11 +08:00
|
|
|
|
ke.mqv()
|
2022-07-15 16:42:39 +08:00
|
|
|
|
if ke.v.X.Sign() == 0 && ke.v.Y.Sign() == 0 {
|
2022-08-24 15:15:58 +08:00
|
|
|
|
return nil, nil, errors.New("sm2: key exchange failed, U is infinity point")
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|
2022-08-24 16:53:11 +08:00
|
|
|
|
|
2022-07-15 16:42:39 +08:00
|
|
|
|
if len(sB) > 0 {
|
|
|
|
|
buffer := ke.sign(false, 0x02)
|
2022-08-17 11:17:18 +08:00
|
|
|
|
if subtle.ConstantTimeCompare(buffer, sB) != 1 {
|
2022-08-24 15:15:58 +08:00
|
|
|
|
return nil, nil, errors.New("sm2: invalid responder's signature")
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-24 15:15:58 +08:00
|
|
|
|
key, err := ke.generateSharedKey(false)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-17 11:36:50 +08:00
|
|
|
|
if !ke.genSignature {
|
2022-08-24 15:15:58 +08:00
|
|
|
|
return key, nil, nil
|
2022-08-17 11:36:50 +08:00
|
|
|
|
}
|
2022-08-24 15:15:58 +08:00
|
|
|
|
return key, ke.sign(false, 0x03), nil
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ConfirmInitiator for responder's step B10
|
2022-08-24 15:15:58 +08:00
|
|
|
|
func (ke *KeyExchange) ConfirmInitiator(s1 []byte) ([]byte, error) {
|
|
|
|
|
if s1 != nil {
|
|
|
|
|
buffer := ke.sign(true, 0x03)
|
|
|
|
|
if subtle.ConstantTimeCompare(buffer, s1) != 1 {
|
|
|
|
|
return nil, errors.New("sm2: invalid initiator's signature")
|
|
|
|
|
}
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|
2022-08-24 15:15:58 +08:00
|
|
|
|
return ke.generateSharedKey(true)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|