X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=src%2Fpkt.go;h=bd3fb23e0669f0699ad5e599bee1e38eb56bbac3;hb=ab7c7eca0e53661f0ba904c2a6ba752990bea367;hp=4dea1bf3713ab939c0f17fa8c37b267ebd82a9f2;hpb=1c773d7a2acd7fef4b7b1567b59e1601a79d55fe;p=nncp.git diff --git a/src/pkt.go b/src/pkt.go index 4dea1bf..bd3fb23 100644 --- a/src/pkt.go +++ b/src/pkt.go @@ -26,25 +26,25 @@ import ( "io" xdr "github.com/davecgh/go-xdr/xdr2" - "golang.org/x/crypto/blake2b" "golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/curve25519" "golang.org/x/crypto/ed25519" "golang.org/x/crypto/nacl/box" "golang.org/x/crypto/poly1305" + "lukechampine.com/blake3" ) type PktType uint8 const ( EncBlkSize = 128 * (1 << 10) - KDFXOFSize = chacha20poly1305.KeySize * 2 PktTypeFile PktType = iota PktTypeFreq PktType = iota PktTypeExec PktType = iota PktTypeTrns PktType = iota PktTypeExecFat PktType = iota + PktTypeArea PktType = iota MaxPathSize = 1<<8 - 1 @@ -54,10 +54,7 @@ const ( ) var ( - MagicNNCPPv3 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'P', 0, 0, 3} - MagicNNCPEv4 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 4} - BadMagic error = errors.New("Unknown magic number") - BadPktType error = errors.New("Unknown packet type") + BadPktType error = errors.New("Unknown packet type") PktOverhead int64 PktEncOverhead int64 @@ -98,12 +95,12 @@ func init() { PktOverhead = int64(n) buf.Reset() - dummyId, err := NodeIdFromString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") + dummyId, err := NodeIdFromString(DummyB32Id) if err != nil { panic(err) } pktEnc := PktEnc{ - Magic: MagicNNCPEv4, + Magic: MagicNNCPEv5.B, Sender: dummyId, Recipient: dummyId, } @@ -119,7 +116,7 @@ func NewPkt(typ PktType, nice uint8, path []byte) (*Pkt, error) { return nil, errors.New("Too long path") } pkt := Pkt{ - Magic: MagicNNCPPv3, + Magic: MagicNNCPPv3.B, Type: typ, Nice: nice, PathLen: uint8(len(path)), @@ -128,14 +125,23 @@ func NewPkt(typ PktType, nice uint8, path []byte) (*Pkt, error) { return &pkt, nil } +func ctrIncr(b []byte) { + for i := len(b) - 1; i >= 0; i-- { + b[i]++ + if b[i] != 0 { + return + } + } + panic("counter overflow") +} + func aeadProcess( aead cipher.AEAD, - nonce []byte, + nonce, ad []byte, doEncrypt bool, r io.Reader, w io.Writer, ) (int, error) { - var blkCtr uint64 ciphCtr := nonce[len(nonce)-8:] buf := make([]byte, EncBlkSize+aead.Overhead()) var toRead []byte @@ -159,12 +165,11 @@ func aeadProcess( } } readBytes += n - blkCtr++ - binary.BigEndian.PutUint64(ciphCtr, blkCtr) + ctrIncr(ciphCtr) if doEncrypt { - toWrite = aead.Seal(buf[:0], nonce, buf[:n], nil) + toWrite = aead.Seal(buf[:0], nonce, buf[:n], ad) } else { - toWrite, err = aead.Open(buf[:0], nonce, buf[:n], nil) + toWrite, err = aead.Open(buf[:0], nonce, buf[:n], ad) if err != nil { return readBytes, err } @@ -192,17 +197,17 @@ func PktEncWrite( size, padSize int64, data io.Reader, out io.Writer, -) error { +) ([]byte, error) { pubEph, prvEph, err := box.GenerateKey(rand.Reader) if err != nil { - return err + return nil, err } var pktBuf bytes.Buffer if _, err := xdr.Marshal(&pktBuf, pkt); err != nil { - return err + return nil, err } tbs := PktTbs{ - Magic: MagicNNCPEv4, + Magic: MagicNNCPEv5.B, Nice: nice, Sender: our.Id, Recipient: their.Id, @@ -210,75 +215,67 @@ func PktEncWrite( } var tbsBuf bytes.Buffer if _, err = xdr.Marshal(&tbsBuf, &tbs); err != nil { - return err + return nil, err } signature := new([ed25519.SignatureSize]byte) copy(signature[:], ed25519.Sign(our.SignPrv, tbsBuf.Bytes())) pktEnc := PktEnc{ - Magic: MagicNNCPEv4, + Magic: MagicNNCPEv5.B, Nice: nice, Sender: our.Id, Recipient: their.Id, ExchPub: *pubEph, Sign: *signature, } - if _, err = xdr.Marshal(out, &pktEnc); err != nil { - return err + ad := blake3.Sum256(tbsBuf.Bytes()) + tbsBuf.Reset() + if _, err = xdr.Marshal(&tbsBuf, &pktEnc); err != nil { + return nil, err + } + pktEncRaw := tbsBuf.Bytes() + if _, err = out.Write(pktEncRaw); err != nil { + return nil, err } sharedKey := new([32]byte) curve25519.ScalarMult(sharedKey, prvEph, their.ExchPub) - kdf, err := blake2b.NewXOF(KDFXOFSize, sharedKey[:]) - if err != nil { - return err - } - if _, err = kdf.Write(MagicNNCPEv4[:]); err != nil { - return err - } key := make([]byte, chacha20poly1305.KeySize) - if _, err = io.ReadFull(kdf, key); err != nil { - return err - } + blake3.DeriveKey(key, string(MagicNNCPEv5.B[:]), sharedKey[:]) aead, err := chacha20poly1305.New(key) if err != nil { - return err + return nil, err } nonce := make([]byte, aead.NonceSize()) fullSize := pktBuf.Len() + int(size) sizeBuf := make([]byte, 8+aead.Overhead()) binary.BigEndian.PutUint64(sizeBuf, uint64(sizeWithTags(int64(fullSize)))) - if _, err = out.Write(aead.Seal(sizeBuf[:0], nonce, sizeBuf[:8], nil)); err != nil { - return err + if _, err = out.Write(aead.Seal(sizeBuf[:0], nonce, sizeBuf[:8], ad[:])); err != nil { + return nil, err } lr := io.LimitedReader{R: data, N: size} mr := io.MultiReader(&pktBuf, &lr) - written, err := aeadProcess(aead, nonce, true, mr, out) + written, err := aeadProcess(aead, nonce, ad[:], true, mr, out) if err != nil { - return err + return nil, err } if written != fullSize { - return io.ErrUnexpectedEOF + return nil, io.ErrUnexpectedEOF } if padSize > 0 { - if _, err = io.ReadFull(kdf, key); err != nil { - return err - } - kdf, err = blake2b.NewXOF(blake2b.OutputLengthUnknown, key) - if err != nil { - return err - } - if _, err = io.CopyN(out, kdf, padSize); err != nil { - return err + blake3.DeriveKey(key, string(MagicNNCPEv5.B[:])+" PAD", sharedKey[:]) + xof := blake3.New(32, key).XOF() + if _, err = io.CopyN(out, xof, padSize); err != nil { + return nil, err } } - return nil + return pktEncRaw, nil } -func TbsVerify(our *NodeOur, their *Node, pktEnc *PktEnc) (bool, error) { +func TbsPrepare(our *NodeOur, their *Node, pktEnc *PktEnc) []byte { tbs := PktTbs{ - Magic: MagicNNCPEv4, + Magic: MagicNNCPEv5.B, Nice: pktEnc.Nice, Sender: their.Id, Recipient: our.Id, @@ -286,9 +283,14 @@ func TbsVerify(our *NodeOur, their *Node, pktEnc *PktEnc) (bool, error) { } var tbsBuf bytes.Buffer if _, err := xdr.Marshal(&tbsBuf, &tbs); err != nil { - return false, err + panic(err) } - return ed25519.Verify(their.SignPub, tbsBuf.Bytes(), pktEnc.Sign[:]), nil + return tbsBuf.Bytes() +} + +func TbsVerify(our *NodeOur, their *Node, pktEnc *PktEnc) ([]byte, bool, error) { + tbs := TbsPrepare(our, their, pktEnc) + return tbs, ed25519.Verify(their.SignPub, tbs, pktEnc.Sign[:]), nil } func PktEncRead( @@ -296,66 +298,84 @@ func PktEncRead( nodes map[NodeId]*Node, data io.Reader, out io.Writer, -) (*Node, int64, error) { + signatureVerify bool, + sharedKeyCached []byte, +) ([]byte, *Node, int64, error) { var pktEnc PktEnc _, err := xdr.Unmarshal(data, &pktEnc) if err != nil { - return nil, 0, err + return nil, nil, 0, err + } + switch pktEnc.Magic { + case MagicNNCPEv1.B: + err = MagicNNCPEv1.TooOld() + case MagicNNCPEv2.B: + err = MagicNNCPEv2.TooOld() + case MagicNNCPEv3.B: + err = MagicNNCPEv3.TooOld() + case MagicNNCPEv4.B: + err = MagicNNCPEv4.TooOld() + case MagicNNCPEv5.B: + default: + err = BadMagic } - if pktEnc.Magic != MagicNNCPEv4 { - return nil, 0, BadMagic - } - their, known := nodes[*pktEnc.Sender] - if !known { - return nil, 0, errors.New("Unknown sender") - } - if *pktEnc.Recipient != *our.Id { - return nil, 0, errors.New("Invalid recipient") - } - verified, err := TbsVerify(our, their, &pktEnc) if err != nil { - return nil, 0, err + return nil, nil, 0, err } - if !verified { - return their, 0, errors.New("Invalid signature") + if *pktEnc.Recipient != *our.Id { + return nil, nil, 0, errors.New("Invalid recipient") + } + var tbsRaw []byte + var their *Node + if signatureVerify { + their = nodes[*pktEnc.Sender] + if their == nil { + return nil, nil, 0, errors.New("Unknown sender") + } + var verified bool + tbsRaw, verified, err = TbsVerify(our, their, &pktEnc) + if err != nil { + return nil, nil, 0, err + } + if !verified { + return nil, their, 0, errors.New("Invalid signature") + } + } else { + tbsRaw = TbsPrepare(our, &Node{Id: pktEnc.Sender}, &pktEnc) } + ad := blake3.Sum256(tbsRaw) sharedKey := new([32]byte) - curve25519.ScalarMult(sharedKey, our.ExchPrv, &pktEnc.ExchPub) - kdf, err := blake2b.NewXOF(KDFXOFSize, sharedKey[:]) - if err != nil { - return their, 0, err - } - if _, err = kdf.Write(MagicNNCPEv4[:]); err != nil { - return their, 0, err + if sharedKeyCached == nil { + curve25519.ScalarMult(sharedKey, our.ExchPrv, &pktEnc.ExchPub) + } else { + copy(sharedKey[:], sharedKeyCached) } key := make([]byte, chacha20poly1305.KeySize) - if _, err = io.ReadFull(kdf, key); err != nil { - return their, 0, err - } + blake3.DeriveKey(key, string(MagicNNCPEv5.B[:]), sharedKey[:]) aead, err := chacha20poly1305.New(key) if err != nil { - return their, 0, err + return sharedKey[:], their, 0, err } nonce := make([]byte, aead.NonceSize()) sizeBuf := make([]byte, 8+aead.Overhead()) if _, err = io.ReadFull(data, sizeBuf); err != nil { - return their, 0, err + return sharedKey[:], their, 0, err } - sizeBuf, err = aead.Open(sizeBuf[:0], nonce, sizeBuf, nil) + sizeBuf, err = aead.Open(sizeBuf[:0], nonce, sizeBuf, ad[:]) if err != nil { - return their, 0, err + return sharedKey[:], their, 0, err } size := int64(binary.BigEndian.Uint64(sizeBuf)) lr := io.LimitedReader{R: data, N: size} - written, err := aeadProcess(aead, nonce, false, &lr, out) + written, err := aeadProcess(aead, nonce, ad[:], false, &lr, out) if err != nil { - return their, int64(written), err + return sharedKey[:], their, int64(written), err } if written != int(size) { - return their, int64(written), io.ErrUnexpectedEOF + return sharedKey[:], their, int64(written), io.ErrUnexpectedEOF } - return their, size, nil + return sharedKey[:], their, size, nil }