285 lines
8.6 KiB
Go
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
|
|
|
|
}
|