From d74a2ec40e57496cc44136db6525079cf0f41f01 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Fri, 13 Jan 2017 00:09:49 +0300 Subject: [PATCH] Encrypt actual packet size, hide it --- src/cypherpunks.ru/nncp/cmd/nncp-pkt/main.go | 6 +- src/cypherpunks.ru/nncp/pkt.go | 83 +++++++++++++++++--- src/cypherpunks.ru/nncp/pkt_test.go | 6 +- 3 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/cypherpunks.ru/nncp/cmd/nncp-pkt/main.go b/src/cypherpunks.ru/nncp/cmd/nncp-pkt/main.go index f11b1b8..222750d 100644 --- a/src/cypherpunks.ru/nncp/cmd/nncp-pkt/main.go +++ b/src/cypherpunks.ru/nncp/cmd/nncp-pkt/main.go @@ -62,7 +62,7 @@ func main() { } var err error - beginning := make([]byte, nncp.PktOverhead-blake2b.Size256) + beginning := make([]byte, nncp.PktOverhead - 8 - 2*blake2b.Size256) if _, err = io.ReadFull(os.Stdin, beginning); err != nil { log.Fatalln("Not enough data to read") } @@ -130,8 +130,8 @@ func main() { return } fmt.Printf( - "Packet type: encrypted\nNiceness: %d\nSender: %s\nPayload size: %s (%d bytes)\n", - pktEnc.Nice, pktEnc.Sender, humanize.IBytes(pktEnc.Size), pktEnc.Size, + "Packet type: encrypted\nNiceness: %d\nSender: %s\n", + pktEnc.Nice, pktEnc.Sender, ) return } diff --git a/src/cypherpunks.ru/nncp/pkt.go b/src/cypherpunks.ru/nncp/pkt.go index 2f24034..2802085 100644 --- a/src/cypherpunks.ru/nncp/pkt.go +++ b/src/cypherpunks.ru/nncp/pkt.go @@ -74,7 +74,6 @@ type PktTbs struct { Recipient *NodeId Sender *NodeId ExchPub *[32]byte - Size uint64 } type PktEnc struct { @@ -83,7 +82,6 @@ type PktEnc struct { Sender *NodeId ExchPub *[32]byte Sign *[ed25519.SignatureSize]byte - Size uint64 } func init() { @@ -96,7 +94,7 @@ func init() { if err != nil { panic(err) } - PktOverhead = int64(n) + blake2b.Size256 + PktOverhead = 8 + blake2b.Size256 + int64(n) + blake2b.Size256 buf.Reset() dummyId, err := NodeIdFromString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") @@ -109,7 +107,6 @@ func init() { Sender: dummyId, ExchPub: new([32]byte), Sign: new([ed25519.SignatureSize]byte), - Size: 123, } n, err = xdr.Marshal(&buf, pktEnc) if err != nil { @@ -156,7 +153,6 @@ func PktEncWrite(our *NodeOur, their *Node, pkt *Pkt, nice uint8, size int64, da Recipient: their.Id, Sender: our.Id, ExchPub: pubEph, - Size: uint64(size + PktOverhead), } var tbsBuf bytes.Buffer if _, err = xdr.Marshal(&tbsBuf, &tbs); err != nil { @@ -170,7 +166,6 @@ func PktEncWrite(our *NodeOur, their *Node, pkt *Pkt, nice uint8, size int64, da Sender: our.Id, ExchPub: pubEph, Sign: signature, - Size: tbs.Size, } if _, err = xdr.Marshal(out, &pktEnc); err != nil { return err @@ -178,6 +173,16 @@ func PktEncWrite(our *NodeOur, their *Node, pkt *Pkt, nice uint8, size int64, da sharedKey := new([32]byte) curve25519.ScalarMult(sharedKey, prvEph, their.ExchPub) kdf := hkdf.New(blake256, sharedKey[:], nil, MagicNNCPEv1[:]) + + // Derive keys + keyEnc4Size := make([]byte, 32) + if _, err = io.ReadFull(kdf, keyEnc4Size); err != nil { + return err + } + keyAuth4Size := make([]byte, 64) + if _, err = io.ReadFull(kdf, keyAuth4Size); err != nil { + return err + } keyEnc := make([]byte, 32) if _, err = io.ReadFull(kdf, keyEnc); err != nil { return err @@ -186,6 +191,17 @@ func PktEncWrite(our *NodeOur, their *Node, pkt *Pkt, nice uint8, size int64, da if _, err = io.ReadFull(kdf, keyAuth); err != nil { return err } + + // Initialize ciphers and MACs + ciph4Size, err := twofish.NewCipher(keyEnc4Size) + if err != nil { + return err + } + ctr4Size := cipher.NewCTR(ciph4Size, make([]byte, twofish.BlockSize)) + mac4Size, err := blake2b.New256(keyAuth4Size) + if err != nil { + return err + } ciph, err := twofish.NewCipher(keyEnc) if err != nil { return err @@ -195,8 +211,17 @@ func PktEncWrite(our *NodeOur, their *Node, pkt *Pkt, nice uint8, size int64, da if err != nil { return err } - mw := io.MultiWriter(out, mac) - ae := &cipher.StreamWriter{S: ctr, W: mw} + + mw := io.MultiWriter(out, mac4Size) + ae := &cipher.StreamWriter{S: ctr4Size, W: mw} + usize := uint64(size) + if _, err = xdr.Marshal(ae, &usize); err != nil { + return err + } + out.Write(mac4Size.Sum(nil)) + + mw = io.MultiWriter(out, mac) + ae = &cipher.StreamWriter{S: ctr, W: mw} ae.Write(pktBuf.Bytes()) if _, err = io.CopyN(ae, data, int64(size)); err != nil { return err @@ -213,7 +238,6 @@ func TbsVerify(our *NodeOur, their *Node, pktEnc *PktEnc) (bool, error) { Recipient: our.Id, Sender: their.Id, ExchPub: pktEnc.ExchPub, - Size: pktEnc.Size, } var tbsBuf bytes.Buffer if _, err := xdr.Marshal(&tbsBuf, &tbs); err != nil { @@ -245,6 +269,16 @@ 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, MagicNNCPEv1[:]) + + // Derive keys + keyEnc4Size := make([]byte, 32) + if _, err = io.ReadFull(kdf, keyEnc4Size); err != nil { + return their, err + } + keyAuth4Size := make([]byte, 64) + if _, err = io.ReadFull(kdf, keyAuth4Size); err != nil { + return their, err + } keyEnc := make([]byte, 32) if _, err = io.ReadFull(kdf, keyEnc); err != nil { return their, err @@ -253,6 +287,17 @@ func PktEncRead(our *NodeOur, nodes map[NodeId]*Node, data io.Reader, out io.Wri if _, err = io.ReadFull(kdf, keyAuth); err != nil { return their, err } + + // Initialize ciphers and MACs + ciph4Size, err := twofish.NewCipher(keyEnc4Size) + if err != nil { + return their, err + } + ctr4Size := cipher.NewCTR(ciph4Size, make([]byte, twofish.BlockSize)) + mac4Size, err := blake2b.New256(keyAuth4Size) + if err != nil { + return their, err + } ciph, err := twofish.NewCipher(keyEnc) if err != nil { return their, err @@ -262,15 +307,29 @@ func PktEncRead(our *NodeOur, nodes map[NodeId]*Node, data io.Reader, out io.Wri if err != nil { return their, err } - trA := io.TeeReader(data, mac) - ae := &cipher.StreamReader{S: ctr, R: trA} - if _, err = io.CopyN(out, ae, int64(pktEnc.Size)-blake2b.Size256); err != nil { + + tr := io.TeeReader(data, mac4Size) + ae := &cipher.StreamReader{S: ctr4Size, R: tr} + var usize uint64 + if _, err = xdr.Unmarshal(ae, &usize); err != nil { return their, err } tag := make([]byte, blake2b.Size256) if _, err = io.ReadFull(data, tag); err != nil { return their, err } + if subtle.ConstantTimeCompare(mac4Size.Sum(nil), tag) != 1 { + return their, errors.New("Unauthenticated payload") + } + + tr = io.TeeReader(data, mac) + ae = &cipher.StreamReader{S: ctr, R: tr} + if _, err = io.CopyN(out, ae, PktOverhead+int64(usize)-8-blake2b.Size256-blake2b.Size256); err != nil { + return their, err + } + if _, err = io.ReadFull(data, tag); err != nil { + return their, err + } if subtle.ConstantTimeCompare(mac.Sum(nil), tag) != 1 { return their, errors.New("Unauthenticated payload") } diff --git a/src/cypherpunks.ru/nncp/pkt_test.go b/src/cypherpunks.ru/nncp/pkt_test.go index 8ed0502..ec58785 100644 --- a/src/cypherpunks.ru/nncp/pkt_test.go +++ b/src/cypherpunks.ru/nncp/pkt_test.go @@ -56,9 +56,6 @@ func TestPktEncWrite(t *testing.T) { if *pktEnc.Sender != *nodeOur.Id { return false } - if pktEnc.Size != uint64(ct.Len()) { - return false - } return true } if err := quick.Check(f, nil); err != nil { @@ -75,7 +72,7 @@ func TestPktEncRead(t *testing.T) { if err != nil { panic(err) } - f := func(path string, pathSize uint8, data [1 << 16]byte, size uint16) bool { + f := func(path string, pathSize uint8, data [1 << 16]byte, size uint16, junk []byte) bool { dataR := bytes.NewReader(data[:]) var ct bytes.Buffer if len(path) > int(pathSize) { @@ -89,6 +86,7 @@ func TestPktEncRead(t *testing.T) { if err != nil { return false } + ct.Write(junk) var pt bytes.Buffer nodes := make(map[NodeId]*Node) nodes[*node1.Id] = node1.Their() -- 2.44.0