X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=src%2Fcypherpunks.ru%2Fnncp%2Fpkt.go;h=c24dad39cca7ed510fe4cad1fe857f805804c69b;hb=535d386941ae38abbaa8e1a6df69a5e739058011;hp=aa7368d96036e7387423ae83e7ee8762875e18cd;hpb=c30215635e9a3bac86766077846725d9b0378f63;p=nncp.git diff --git a/src/cypherpunks.ru/nncp/pkt.go b/src/cypherpunks.ru/nncp/pkt.go index aa7368d..c24dad3 100644 --- a/src/cypherpunks.ru/nncp/pkt.go +++ b/src/cypherpunks.ru/nncp/pkt.go @@ -20,25 +20,26 @@ package nncp import ( "bytes" - "crypto/cipher" "crypto/rand" "crypto/subtle" + "encoding/binary" "errors" - "hash" "io" + "chacha20" "github.com/davecgh/go-xdr/xdr2" "golang.org/x/crypto/blake2b" "golang.org/x/crypto/curve25519" "golang.org/x/crypto/ed25519" - "golang.org/x/crypto/hkdf" "golang.org/x/crypto/nacl/box" - "golang.org/x/crypto/twofish" ) type PktType uint8 const ( + EncBlkSize = 128 * (1 << 10) + KDFXOFSize = 2*(32+64) + 32 + PktTypeFile PktType = iota PktTypeFreq PktType = iota PktTypeMail PktType = iota @@ -55,7 +56,7 @@ const ( var ( MagicNNCPPv1 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'P', 0, 0, 1} - MagicNNCPEv2 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 2} + MagicNNCPEv3 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 3} BadMagic error = errors.New("Unknown magic number") BadPktType error = errors.New("Unknown packet type") @@ -105,7 +106,7 @@ func init() { panic(err) } pktEnc := PktEnc{ - Magic: MagicNNCPEv2, + Magic: MagicNNCPEv3, Nice: 123, Sender: dummyId, Recipient: dummyId, @@ -134,14 +135,6 @@ func NewPkt(typ PktType, path string) (*Pkt, error) { return &pkt, nil } -func blake256() hash.Hash { - h, err := blake2b.New256(nil) - if err != nil { - panic(err) - } - return h -} - type DevZero struct{} func (d DevZero) Read(b []byte) (n int, err error) { @@ -151,6 +144,35 @@ func (d DevZero) Read(b []byte) (n int, err error) { return } +func ae(keyEnc *[32]byte, r io.Reader, w io.Writer) (int, error) { + var blkCtr uint64 + ciphNonce := new([16]byte) + ciphCtr := ciphNonce[8:] + buf := make([]byte, EncBlkSize) + var n int + var written int + var err error + for { + n, err = io.ReadFull(r, buf) + if err != nil { + if err == io.EOF { + break + } + if err != io.ErrUnexpectedEOF { + return written + n, err + } + } + written += n + blkCtr++ + binary.BigEndian.PutUint64(ciphCtr, blkCtr) + chacha20.XORKeyStream(buf[:n], buf[:n], ciphNonce, keyEnc) + if _, err = w.Write(buf[:n]); err != nil { + return written, err + } + } + return written, nil +} + func PktEncWrite(our *NodeOur, their *Node, pkt *Pkt, nice uint8, size, padSize int64, data io.Reader, out io.Writer) error { pubEph, prvEph, err := box.GenerateKey(rand.Reader) if err != nil { @@ -161,7 +183,7 @@ func PktEncWrite(our *NodeOur, their *Node, pkt *Pkt, nice uint8, size, padSize return err } tbs := PktTbs{ - Magic: MagicNNCPEv2, + Magic: MagicNNCPEv3, Nice: nice, Sender: our.Id, Recipient: their.Id, @@ -174,7 +196,7 @@ func PktEncWrite(our *NodeOur, their *Node, pkt *Pkt, nice uint8, size, padSize signature := new([ed25519.SignatureSize]byte) copy(signature[:], ed25519.Sign(our.SignPrv, tbsBuf.Bytes())) pktEnc := PktEnc{ - Magic: MagicNNCPEv2, + Magic: MagicNNCPEv3, Nice: nice, Sender: our.Id, Recipient: their.Id, @@ -186,83 +208,83 @@ func PktEncWrite(our *NodeOur, their *Node, pkt *Pkt, nice uint8, size, padSize } sharedKey := new([32]byte) curve25519.ScalarMult(sharedKey, prvEph, their.ExchPub) - kdf := hkdf.New(blake256, sharedKey[:], nil, MagicNNCPEv2[:]) - - keyEnc := make([]byte, 32) - if _, err = io.ReadFull(kdf, keyEnc); err != nil { + kdf, err := blake2b.NewXOF(KDFXOFSize, sharedKey[:]) + if err != nil { return err } - keyAuth := make([]byte, 64) - if _, err = io.ReadFull(kdf, keyAuth); err != nil { + if _, err = kdf.Write(MagicNNCPEv3[:]); err != nil { return err } - ciph, err := twofish.NewCipher(keyEnc) - if err != nil { + keyEnc := new([32]byte) + if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil { + return err + } + keyAuth := make([]byte, 64) + if _, err = io.ReadFull(kdf, keyAuth); err != nil { return err } - ctr := cipher.NewCTR(ciph, make([]byte, twofish.BlockSize)) mac, err := blake2b.New256(keyAuth) if err != nil { return err } - mw := io.MultiWriter(out, mac) - ae := &cipher.StreamWriter{S: ctr, W: mw} - usize := uint64(size) - if _, err = xdr.Marshal(ae, &usize); err != nil { + sizeBuf := make([]byte, 8) + binary.BigEndian.PutUint64(sizeBuf, uint64(size)) + chacha20.XORKeyStream(sizeBuf, sizeBuf, new([16]byte), keyEnc) + if _, err = out.Write(sizeBuf); err != nil { + return err + } + if _, err = mac.Write(sizeBuf); err != nil { + return err + } + if _, err = out.Write(mac.Sum(nil)); err != nil { return err } - ae.Close() - out.Write(mac.Sum(nil)) - if _, err = io.ReadFull(kdf, keyEnc); err != nil { + if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil { return err } if _, err = io.ReadFull(kdf, keyAuth); err != nil { return err } - - ciph, err = twofish.NewCipher(keyEnc) + mac, err = blake2b.New256(keyAuth) if err != nil { return err } - ctr = cipher.NewCTR(ciph, make([]byte, twofish.BlockSize)) - mac, err = blake2b.New256(keyAuth) + lr := io.LimitedReader{data, size} + mr := io.MultiReader(&pktBuf, &lr) + mw := io.MultiWriter(out, mac) + fullSize := pktBuf.Len() + int(size) + written, err := ae(keyEnc, mr, mw) if err != nil { return err } - - mw = io.MultiWriter(out, mac) - ae = &cipher.StreamWriter{S: ctr, W: mw} - ae.Write(pktBuf.Bytes()) - if _, err = io.CopyN(ae, data, size); err != nil { + if written != fullSize { + return io.ErrUnexpectedEOF + } + if _, err = out.Write(mac.Sum(nil)); err != nil { return err } - ae.Close() - out.Write(mac.Sum(nil)) - if padSize > 0 { - if _, err = io.ReadFull(kdf, keyEnc); err != nil { + if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil { return err } - ciph, err = twofish.NewCipher(keyEnc) + lr = io.LimitedReader{DevZero{}, padSize} + written, err = ae(keyEnc, &lr, out) if err != nil { return err } - ctr = cipher.NewCTR(ciph, make([]byte, twofish.BlockSize)) - ae = &cipher.StreamWriter{S: ctr, W: out} - if _, err = io.CopyN(ae, DevZero{}, padSize); err != nil { - return err + if written != int(padSize) { + return io.ErrUnexpectedEOF } - ae.Close() } return nil } func TbsVerify(our *NodeOur, their *Node, pktEnc *PktEnc) (bool, error) { tbs := PktTbs{ - Magic: MagicNNCPEv2, + Magic: MagicNNCPEv3, Nice: pktEnc.Nice, Sender: their.Id, Recipient: our.Id, @@ -281,7 +303,7 @@ func PktEncRead(our *NodeOur, nodes map[NodeId]*Node, data io.Reader, out io.Wri if err != nil { return nil, 0, err } - if pktEnc.Magic != MagicNNCPEv2 { + if pktEnc.Magic != MagicNNCPEv3 { return nil, 0, BadMagic } their, known := nodes[*pktEnc.Sender] @@ -300,31 +322,32 @@ func PktEncRead(our *NodeOur, nodes map[NodeId]*Node, data io.Reader, out io.Wri } sharedKey := new([32]byte) curve25519.ScalarMult(sharedKey, our.ExchPrv, pktEnc.ExchPub) - kdf := hkdf.New(blake256, sharedKey[:], nil, MagicNNCPEv2[:]) - - keyEnc := make([]byte, 32) - if _, err = io.ReadFull(kdf, keyEnc); err != nil { + kdf, err := blake2b.NewXOF(KDFXOFSize, sharedKey[:]) + if err != nil { return their, 0, err } - keyAuth := make([]byte, 64) - if _, err = io.ReadFull(kdf, keyAuth); err != nil { + if _, err = kdf.Write(MagicNNCPEv3[:]); err != nil { return their, 0, err } - ciph, err := twofish.NewCipher(keyEnc) - if err != nil { + keyEnc := new([32]byte) + if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil { + return their, 0, err + } + keyAuth := make([]byte, 64) + if _, err = io.ReadFull(kdf, keyAuth); err != nil { return their, 0, err } - ctr := cipher.NewCTR(ciph, make([]byte, twofish.BlockSize)) mac, err := blake2b.New256(keyAuth) if err != nil { return their, 0, err } - tr := io.TeeReader(data, mac) - ae := &cipher.StreamReader{S: ctr, R: tr} - var usize uint64 - if _, err = xdr.Unmarshal(ae, &usize); err != nil { + sizeBuf := make([]byte, 8) + if _, err = io.ReadFull(data, sizeBuf); err != nil { + return their, 0, err + } + if _, err = mac.Write(sizeBuf); err != nil { return their, 0, err } tag := make([]byte, blake2b.Size256) @@ -334,29 +357,29 @@ func PktEncRead(our *NodeOur, nodes map[NodeId]*Node, data io.Reader, out io.Wri if subtle.ConstantTimeCompare(mac.Sum(nil), tag) != 1 { return their, 0, errors.New("Unauthenticated size") } - size := int64(usize) + chacha20.XORKeyStream(sizeBuf, sizeBuf, new([16]byte), keyEnc) + size := int64(binary.BigEndian.Uint64(sizeBuf)) - if _, err = io.ReadFull(kdf, keyEnc); err != nil { + if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil { return their, size, err } if _, err = io.ReadFull(kdf, keyAuth); err != nil { return their, size, err } - - ciph, err = twofish.NewCipher(keyEnc) - if err != nil { - return their, size, err - } - ctr = cipher.NewCTR(ciph, make([]byte, twofish.BlockSize)) mac, err = blake2b.New256(keyAuth) if err != nil { - return their, size, err + return their, 0, err } - tr = io.TeeReader(data, mac) - ae = &cipher.StreamReader{S: ctr, R: tr} - if _, err = io.CopyN(out, ae, PktOverhead+size-8-blake2b.Size256-blake2b.Size256); err != nil { - return their, size, err + fullSize := PktOverhead + size - 8 - 2*blake2b.Size256 + lr := io.LimitedReader{data, fullSize} + tr := io.TeeReader(&lr, mac) + written, err := ae(keyEnc, tr, out) + if err != nil { + return their, int64(written), err + } + if written != int(fullSize) { + return their, int64(written), io.ErrUnexpectedEOF } if _, err = io.ReadFull(data, tag); err != nil { return their, size, err