Files
xgcl/sm/sm2/keyexchange.go
T
2026-05-27 23:03:00 +08:00

285 lines
8.6 KiB
Go

package sm2
import (
"io"
"math/big"
"xdx.jelly/xgcl/gerrors"
"xdx.jelly/xgcl/gmath"
"xdx.jelly/xgcl/grand"
)
var wMask *big.Int
var w int
func initKeyExchange() {
w = (Curve().Params().N.BitLen()+1)/2 - 1
wMask = big.NewInt(1)
wMask.Lsh(wMask, uint(w))
wMask.Sub(wMask, gmath.BigInt1)
}
var XBar = computeXBar
func computeXBar(x *big.Int) *big.Int {
xBar := new(big.Int).And(x, wMask)
xBar.SetBit(xBar, w, 1)
return xBar
}
// ///////////////////////////////////// 包函数的方式,不绑定方法到struct上
type ExchgParameters struct {
PrivateKey *PrivateKey // ra and Ra = [ra]·G or rb and Rb = [rb]·G
IsSponsor bool
}
func (p *ExchgParameters) PublicKey() *PublicKey {
// return p.privateKey.PublicKey.X, p.privateKey.PublicKey.Y
return &p.PrivateKey.PublicKey
}
// SharedKey generate shared key.
func (p *ExchgParameters) SharedKey(sk *PrivateKey, peerPk *PublicKey, peerPublicKey *PublicKey) (*big.Int, *big.Int, error) {
xBar1 := XBar(p.PrivateKey.X)
xBar2 := XBar(peerPublicKey.X)
t := new(big.Int).Mul(xBar1, p.PrivateKey.D)
t.Add(sk.D, t)
t.Mod(t, Curve().Params().N)
x, y := Curve().ScalarMult(peerPublicKey.X, peerPublicKey.Y, xBar2.Bytes())
x, y = Curve().Add(x, y, peerPk.X, peerPk.Y)
x, y = Curve().ScalarMult(x, y, t.Bytes())
if gmath.IsBigInt0(x) && gmath.IsBigInt0(y) {
return nil, nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "U/V is infinity point")
}
return x, y, nil
}
// GenerateAgreementData 发起方调用
func GenerateAgreementData(rand io.Reader) (*ExchgParameters, error) {
r, err := GenerateKey(Curve(), rand)
if err != nil {
return nil, err
}
return &ExchgParameters{
PrivateKey: r,
IsSponsor: true,
}, err
}
// GenerateAgreementDataAndKey 响应方调用生成临时公钥及协商密钥
// Za、Zb由PreComputeWithIdAndPubkey计算
func GenerateAgreementDataAndKey(
id []byte,
privateKey *PrivateKey,
peerId []byte,
peerPublicKey *PublicKey,
peerParam *PublicKey,
keyLength int, rand io.Reader) ([]byte, *ExchgParameters, error) {
r, err := GenerateAgreementData(rand)
r.IsSponsor = false
if err != nil {
return nil, nil, err
}
key, err := GenerateSharedKey(r, id, privateKey, peerId, peerPublicKey, peerParam, keyLength)
return key, r, nil
}
// GenerateSharedKey 发起方调用生成协商密钥。
func GenerateSharedKey(
r *ExchgParameters,
id []byte,
privateKey *PrivateKey,
peerId []byte,
peerPublicKey *PublicKey,
peerParam *PublicKey,
keyLength int) ([]byte, error) {
if !peerParam.IsValid() {
return nil, gerrors.WithAnnotating(ErrInvalidPublicKey, "peer's temp param is not a valid curve point")
}
if !peerPublicKey.IsValid() {
return nil, gerrors.WithAnnotating(ErrInvalidPublicKey, "peer's public key is not a valid curve point")
}
x, y, err := r.SharedKey(privateKey, peerPublicKey, peerParam)
if err != nil {
return nil, gerrors.ChainErrors(ErrKeyExchangeFailed, err)
}
key := make([]byte, keyLength)
if r.IsSponsor {
Kdf(key, gmath.BigIntToNByte(x, byteSize),
gmath.BigIntToNByte(y, byteSize),
PreComputeWithIdAndPubkey(id, &privateKey.PublicKey),
PreComputeWithIdAndPubkey(peerId, peerPublicKey),
)
} else {
Kdf(key, gmath.BigIntToNByte(x, byteSize),
gmath.BigIntToNByte(y, byteSize),
PreComputeWithIdAndPubkey(peerId, peerPublicKey),
PreComputeWithIdAndPubkey(id, &privateKey.PublicKey),
)
}
return key, nil
}
// Sponsor holds a sponsor's key pairs and temp key pairs, context data.
// Sponsor对象可以重复使用
type Sponsor struct {
KeyBits uint32
z []byte
r *PrivateKey // sponsor's temp private key
privateKey *PrivateKey
publicKey *PublicKey
tempKeyOfSponsor *PublicKey
tempKeyOfResponsor *PublicKey
}
// NewSponsor make a copy of privateKey, so Clear will not change the input privateKey
// 若id=nil, 则使用默认id。
func NewSponsor(id []byte, privateKey *PrivateKey) *Sponsor {
pk := GenPublicKey(privateKey)
return &Sponsor{
z: PreComputeWithIdAndPubkey(id, pk),
privateKey: NewPrivateKey().Set(privateKey),
publicKey: pk,
tempKeyOfSponsor: NewPublicKey(),
tempKeyOfResponsor: NewPublicKey(),
}
}
// Clear 无论成功与否,最后调用Clear
func (s *Sponsor) Clear() {
s.privateKey.Clear()
}
// Responsor hold a responsor's key pairs and id
// Responsor对象可以重复使用
type Responsor struct {
z []byte
privateKey *PrivateKey
publicKey *PublicKey
}
// NewResponsor return a responsor's instance
func NewResponsor(id []byte, privateKey *PrivateKey) *Responsor {
pk := GenPublicKey(privateKey)
return &Responsor{
z: PreComputeWithIdAndPubkey(id, pk),
privateKey: NewPrivateKey().Set(privateKey),
publicKey: pk,
}
}
// Clear 无论成功与否,最后调用Clear
func (rs *Responsor) Clear() {
rs.privateKey.Clear()
}
// A is sponsor and B is responsor
//////////////////////
// 发起方函数
// GenerateAgreementData 发起方首先调用,za先计算好
// Za、Zb由PreComputeWithIdAndPubkey计算
// 输出tempPubkey需转化为[]byte
func (s *Sponsor) GenerateAgreementData(rnd []byte) (tempKeyOfSponsor *PublicKey, err error) {
if len(rnd) < byteSize {
rnd = make([]byte, byteSize)
if _, err := grand.GenerateRandom(rnd); err != nil {
return nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "generate random numbers failed")
}
}
// return error never happen
s.r, _ = GenPrivateKey(rnd[:byteSize])
tempKeyOfSponsor = GenPublicKey(s.r)
s.tempKeyOfSponsor.Set(tempKeyOfSponsor)
return tempKeyOfSponsor, nil
}
// GenerateKey 发起方调用生成协商密钥。
func (s *Sponsor) GenerateKey(idOfResponsor []byte, pubkeyOfResponsor, tempKeyOfResponsor *PublicKey, keyLength int) (outKey []byte, err error) {
if !tempKeyOfResponsor.IsValid() {
return nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "responsor's temp param is not a valid curve point")
}
if !pubkeyOfResponsor.IsValid() {
return nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "responsor's public key is not a valid curve point")
}
xBar1 := computeXBar(s.tempKeyOfSponsor.X)
xBar2 := computeXBar(tempKeyOfResponsor.X)
ta := new(big.Int).Mul(xBar1, s.r.D)
ta.Mod(ta, sm2Curve.Params().N)
// fmt.Println("x1ra= ", ta.Text(16))
ta.Add(s.privateKey.D, ta)
ta.Mod(ta, sm2Curve.Params().N)
ux, uy := sm2Curve.ScalarMult(tempKeyOfResponsor.X, tempKeyOfResponsor.Y, xBar2.Bytes())
ux, uy = sm2Curve.Add(ux, uy, pubkeyOfResponsor.X, pubkeyOfResponsor.Y)
// fmt.Println("x2Rb= ", ux.Text(16), uy.Text(16))
ux, uy = sm2Curve.ScalarMult(ux, uy, ta.Bytes())
// fmt.Println("发起方U= ", ux.Text(16), uy.Text(16))
// U = O?
if gmath.IsBigInt0(ux) && gmath.IsBigInt0(uy) {
return nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "U/V is infinity point")
}
outKey = make([]byte, keyLength)
zb := PreComputeWithIdAndPubkey(idOfResponsor, pubkeyOfResponsor)
Kdf(outKey, gmath.BigIntToNByte(ux, byteSize), gmath.BigIntToNByte(uy, byteSize), s.z, zb)
return outKey, nil
}
// 响应方
// GenerateAgreementDataAndKey 响应方调用生成临时公钥及协商密钥
// Za、Zb由PreComputeWithIdAndPubkey计算
func (rs *Responsor) GenerateAgreementDataAndKey(idOfSponsor []byte, pubkeyOfSponsor, tempKeyOfSponsor *PublicKey, keyLength int, rnd []byte) (outKey []byte, tempKeyOfResponsor *PublicKey, err error) {
if len(rnd) < byteSize {
rnd = make([]byte, byteSize)
if _, err := grand.GenerateRandom(rnd); err != nil {
return nil, nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "generate random numbers failed")
}
}
rb, _ := GenPrivateKey(rnd[:byteSize])
tempKeyOfResponsor = GenPublicKey(rb)
if !tempKeyOfSponsor.IsValid() {
return nil, nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "responsor's temp param is not a valid curve point")
}
if !pubkeyOfSponsor.IsValid() {
return nil, nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "responsor's public key is not a valid curve point")
}
xBar1 := computeXBar(tempKeyOfSponsor.X)
xBar2 := computeXBar(tempKeyOfResponsor.X)
tb := new(big.Int).Mul(xBar2, rb.D)
tb.Mod(tb, sm2Curve.Params().N)
tb.Add(rs.privateKey.D, tb)
tb.Mod(tb, sm2Curve.Params().N)
vx, vy := sm2Curve.ScalarMult(tempKeyOfSponsor.X, tempKeyOfSponsor.Y, xBar1.Bytes())
vx, vy = sm2Curve.Add(vx, vy, pubkeyOfSponsor.X, pubkeyOfSponsor.Y)
vx, vy = sm2Curve.ScalarMult(vx, vy, tb.Bytes())
// U = O?
if gmath.IsBigInt0(vx) && gmath.IsBigInt0(vy) {
return nil, nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "U/V is infinity point")
}
za := PreComputeWithIdAndPubkey(idOfSponsor, pubkeyOfSponsor)
outKey = make([]byte, keyLength)
Kdf(outKey, gmath.BigIntToNByte(vx, byteSize), gmath.BigIntToNByte(vy, byteSize), za, rs.z)
return outKey, tempKeyOfResponsor, nil
}