shithub: libdp9ik

ref: 7e77582b6904979700dde6b0cba53f2d91e2b28d

View raw version
package libdp9ik

import (
	"crypto/rand"
	"errors"
	"fmt"
	"io"
	"log"
	"strings"
)

const (
	dp9ik = "dp9ik"
	p9sk1 = "p9sk1"

	Anamelen  = 28
	Aerrlen   = 64
	Domlen    = 48
	Deskeylen = 7
	Aeskeylen = 16

	Challen   = 8
	Netchlen  = 16
	Configlen = 14
	Secretlen = 32
	Passwdlen = 28

	Noncelen = 32

	Pakkeylen  = 32
	Pakslen    = (448 + 7) / 8
	Pakplen    = 4 * Pakslen
	Pakhashlen = 2 * Pakplen
	Pakxlen    = Pakslen
	Pakylen    = Pakslen

	Tickreqlen    = 3*Anamelen + Challen + Domlen + 1
	Maxticketlen  = 12 + Challen + 2*Anamelen + Noncelen + 16
	Maxauthentlen = 12 + Challen + Noncelen + 16
)

var (
	ErrNoProto = errors.New("server did not offer dp9ik or p9sk1")
	ErrNoDom   = errors.New("server did not offer a dom")
)

func Getastickets(asfd io.ReadWriter, ak *AuthKey, tr *TicketReq, y []byte, tbuf []byte) error {
	if y != nil {
		//dp9ik
		tr.Which = AuthPAK
		tr.asrequest(asfd)
		_, err := asfd.Write(y[:Pakylen])
		if err != nil {
			return err
		}
		p, err := authpak_new(ak, tbuf, 1)
		if err != nil {
			return err
		}
		_, err = asfd.Write(tbuf[:Pakylen])
		if err != nil {
			return err
		}
		err = asrdresp(asfd, tbuf)
		if err != nil {
			return err
		}
		copy(y, tbuf[:Pakylen])
		err = p.authpak_finish(ak, tbuf[Pakylen:])
		if err != nil {
			return err
		}
	}
	tr.Which = AuthTreq

	return nil
}

func P9any(fd io.ReadWriter, asfd io.ReadWriter, user, pass string) (*AuthInfo, error) {
	y := make([]byte, Pakylen)
	buf := make([]byte, 1024)
	_, err := fd.Read(buf)
	if err != nil {
		return nil, err
	}

	protos := strings.Split(string(buf), " ")
	var proto, dom string
	//Take the latter proto if two are present, this will prefer dp9ik if available
	for _, s := range protos {
		dp := strings.Split(s, "@")
		if len(dp) < 2 {
			return nil, ErrNoDom
		}
		dom = dp[1]
		proto = dp[0]
	}
	if proto != dp9ik && proto != p9sk1 {
		return nil, ErrNoProto
	}
	_, err = fd.Write([]byte(fmt.Sprintf("%s %s", proto, dom)))
	if err != nil {
		return nil, err
	}

	crand := make([]byte, 2*Noncelen)
	cchal := make([]byte, Challen)
	_, err = rand.Read(crand)
	if err != nil {
		return nil, err
	}
	_, err = rand.Read(cchal)
	if err != nil {
		return nil, err
	}
	_, err = fd.Write(cchal)
	if err != nil {
		return nil, err
	}

	n := Tickreqlen
	if proto == dp9ik {
		n += Pakylen
	}
	trbuf := make([]byte, n)
	_, err = fd.Read(trbuf)
	if err != nil {
		return nil, err
	}
	tr := &TicketReq{}
	tr.UnmarshalBinary(trbuf)

	ak := &AuthKey{}
	ak.Passtokey(pass)
	if proto == dp9ik {
		ak.AuthpakHash([]byte(pass))
	}

	copy(tr.Hostid[:], []byte(user))
	copy(tr.Uid[:], []byte(user))

	tbuf := make([]byte, 2*Maxticketlen+Maxauthentlen+Pakylen)
	if proto == dp9ik {
		copy(y[:Pakylen], trbuf[Tickreqlen:])
		err := Getastickets(asfd, ak, tr, y, tbuf)
		if err != nil {
			return nil, err
		}
	}

	t := &Ticket{}
	t.UnmarshalBinary(tbuf)
	log.Println(t.Num, AuthTc)
	if t.Num != AuthTc {
		log.Fatal("disaster, password mismatch")
	}

	return nil, nil
}