shithub: libdp9ik

ref: 7e77582b6904979700dde6b0cba53f2d91e2b28d

View raw version
package libdp9ik

import (
	"crypto/rand"
	"crypto/sha256"
	"errors"
	"math/big"

	"golang.org/x/crypto/hkdf"
)

type AuthInfo struct {
	Cuid       string /* caller id */
	Suid       string /* server id */
	Capability string /* capability (only valid on server side) */
	Secret     []byte /* secret */
}

type AuthKey struct {
	Des     [Deskeylen]byte  /* DES key from password */
	Aes     [Aeskeylen]byte  /* Aes key from password */
	Pakkey  [Pakkeylen]byte  /* shared key from AuthPak exchange */
	Pakhash [Pakhashlen]byte /* secret hash from AES key and user name */
}

func (ak *AuthKey) Passtokey(pw string) {
	//TODO: p9sk1 DES
	copy(ak.Aes[:], passtoaeskey(pw))
}

func (ak *AuthKey) AuthpakHash(u []byte) error {
	info := []byte("Plan 9 AuthPAK hash")

	H := big.NewInt(0)
	PX := big.NewInt(0)
	PY := big.NewInt(0)
	PZ := big.NewInt(0)
	PT := big.NewInt(0)

	h := make([]byte, 2*Pakslen)

	salt := sha256.Sum256(u)
	hr := hkdf.New(sha256.New, ak.Aes[:], salt[:], info)
	_, err := hr.Read(h)
	if err != nil {
		return err
	}

	c := GPAKCurve
	H = H.SetBytes(h[:Pakslen])
	Spake2ee_h2P(c.P, c.A, c.D, H, PX, PY, PZ, PT)

	n := 0
	move := func(b *big.Int) {
		b.FillBytes(ak.Pakhash[n : n+Pakslen])
		n += Pakslen
	}
	move(PX)
	move(PY)
	move(PZ)
	move(PT)

	H = H.SetBytes(h[Pakslen:])
	Spake2ee_h2P(c.P, c.A, c.D, H, PX, PY, PZ, PT)
	move(PX)
	move(PY)
	move(PZ)
	move(PT)

	return nil
}

type PAKPriv struct {
	Isclient bool
	X        [Pakxlen]byte
	Y        [Pakylen]byte
}

func authpak_new(ak *AuthKey, y []byte, isclient int) (*PAKPriv, error) {
	p := &PAKPriv{}
	p.Isclient = (isclient != 0)

	Y := big.NewInt(0)

	PX := big.NewInt(0)
	PY := big.NewInt(0)
	PZ := big.NewInt(0)
	PT := big.NewInt(0)

	n := 0
	if p.Isclient == false {
		n += Pakplen
	}
	move := func(b *big.Int) {
		b.FillBytes(ak.Pakhash[n : n+Pakslen])
		n += Pakslen
	}
	move(PX)
	move(PY)
	move(PZ)
	move(PT)

	c := GPAKCurve
	X, err := rand.Int(rand.Reader, c.P)
	if err != nil {
		return nil, err
	}

	Spake2ee_1(c.P, c.A, c.D, X, c.X, c.Y, PX, PY, PZ, PT, Y)
	X.FillBytes(p.X[:])
	Y.FillBytes(p.Y[:])

	copy(y, p.Y[:])

	return p, nil
}

func (p *PAKPriv) authpak_finish(ak *AuthKey, y []byte) error {
	info := []byte("Plan 9 AuthPAK Key")
	z := make([]byte, Pakslen)

	X := big.NewInt(0)
	Y := big.NewInt(0)
	Z := big.NewInt(0)
	ok := big.NewInt(0)

	PX := big.NewInt(0)
	PY := big.NewInt(0)
	PZ := big.NewInt(0)
	PT := big.NewInt(0)

	n := 0
	if p.Isclient {
		n += Pakplen
	}
	move := func(b *big.Int) {
		b.FillBytes(ak.Pakhash[n : n+Pakslen])
		n += Pakslen
	}
	move(PX)
	move(PY)
	move(PZ)
	move(PT)

	X.SetBytes(p.X[:])
	Y.SetBytes(y[:Pakylen])

	c := GPAKCurve
	Spake2ee_2(c.P, c.A, c.D, PX, PY, PZ, PT, X, Y, ok, Z)

	if ok.Cmp(big.NewInt(0)) == 0 {
		return errors.New("spake2ee_2 failed")
	}

	Z.FillBytes(z)

	sha := sha256.New()
	if p.Isclient {
		sha.Write(p.Y[:])
		sha.Write(y[:Pakylen])
	} else {
		sha.Write(y[:Pakylen])
		sha.Write(p.Y[:])
	}
	salt := sha.Sum([]byte{})
	hr := hkdf.New(sha256.New, z[:], salt[:], info)
	_, err := hr.Read(ak.Pakkey[:])
	return err
}