diff options
author | Christian Pointner <equinox@anytun.org> | 2017-09-02 03:24:41 +0200 |
---|---|---|
committer | Christian Pointner <equinox@anytun.org> | 2017-09-02 03:24:41 +0200 |
commit | 10212b0f9e7c5b2e3166d927cadbc4824f494bd3 (patch) | |
tree | 744951c3f1ae6b30b58d5432959c0ac33313f88d /satp | |
parent | make interface config more modular (diff) |
addes first simple satp packets
Diffstat (limited to 'satp')
-rw-r--r-- | satp/packet.go | 146 | ||||
-rw-r--r-- | satp/packet_test.go | 187 |
2 files changed, 333 insertions, 0 deletions
diff --git a/satp/packet.go b/satp/packet.go new file mode 100644 index 0000000..a24b69a --- /dev/null +++ b/satp/packet.go @@ -0,0 +1,146 @@ +// +// Copyright (c) 2017 anygone contributors (see AUTHORS file) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of anygone nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +package satp + +import ( + "bytes" + "encoding/binary" + "errors" +) + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | sequence number | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | +// | sender ID | MUX | | +// +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+ | +// | | payload type | | | +// | +-------------------------------+ | | +// | | .... payload ... | | +// | | +-------------------------------+ | +// | | | padding (OPT) | pad count(OPT)| | +// +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+-+ +// | : authentication tag (RECOMMENDED) : | +// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | +// | | +// +- Encrypted Portion Authenticated Portion ---+ + +type PlainPacket struct { + Type uint16 + Payload []byte +} + +func NewPlainPacket(PayloadType uint16) (pp *PlainPacket) { + pp = &PlainPacket{} + pp.Type = PayloadType + return +} + +func (pp *PlainPacket) MarshalBinary() (data []byte, err error) { + buf := &bytes.Buffer{} + if err = binary.Write(buf, binary.BigEndian, pp.Type); err != nil { + return + } + buf.Write(pp.Payload) // returned error is always nil + return buf.Bytes(), nil +} + +func (pp *PlainPacket) UnmarshalBinary(data []byte) (err error) { + buf := bytes.NewReader(data) + if err = binary.Read(buf, binary.BigEndian, &(pp.Type)); err != nil { + return + } + if buf.Len() > 0 { + pp.Payload = make([]byte, buf.Len()) + buf.Read(pp.Payload) + } + return +} + +type EncryptedPacket struct { + SequenceNumber uint32 + SenderID uint16 + Mux uint16 + Payload []byte + AuthTag []byte +} + +func NewEncryptedPacket(AuthTagLength uint) (ep *EncryptedPacket) { + ep = &EncryptedPacket{} + ep.AuthTag = make([]byte, AuthTagLength) + return +} + +func (ep *EncryptedPacket) MarshalBinary() (data []byte, err error) { + buf := &bytes.Buffer{} + if err = binary.Write(buf, binary.BigEndian, ep.SequenceNumber); err != nil { + return + } + if err = binary.Write(buf, binary.BigEndian, ep.SenderID); err != nil { + return + } + if err = binary.Write(buf, binary.BigEndian, ep.Mux); err != nil { + return + } + if len(ep.Payload) >= 2 { // Payload must at least have a payload type which is a uint16 -> 2 bytes + buf.Write(ep.Payload) // returned error is always nil + } else { + return nil, errors.New("Unable to marshal packet: payload is empty/too short") + } + + if len(ep.AuthTag) > 0 { + buf.Write(ep.AuthTag) // returned error is always nil + } + return buf.Bytes(), nil +} + +func (ep *EncryptedPacket) UnmarshalBinary(data []byte) (err error) { + buf := bytes.NewReader(data) + if err = binary.Read(buf, binary.BigEndian, &(ep.SequenceNumber)); err != nil { + return + } + if err = binary.Read(buf, binary.BigEndian, &(ep.SenderID)); err != nil { + return + } + if err = binary.Read(buf, binary.BigEndian, &(ep.Mux)); err != nil { + return + } + + if (buf.Len() - len(ep.AuthTag)) < 2 { // 2 bytes payload type + length of AuthTag must be left on buffer + return errors.New("Unable to unmarshal packet: too short") + } + + ep.Payload = make([]byte, buf.Len()-len(ep.AuthTag)) + buf.Read(ep.Payload) + buf.Read(ep.AuthTag) + return +} diff --git a/satp/packet_test.go b/satp/packet_test.go new file mode 100644 index 0000000..5fce4f4 --- /dev/null +++ b/satp/packet_test.go @@ -0,0 +1,187 @@ +// +// Copyright (c) 2017 anygone contributors (see AUTHORS file) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of anygone nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +package satp + +import ( + "bytes" + "reflect" + "testing" +) + +func TestPlainPacketMarshal(t *testing.T) { + testvectors := []struct { + packet PlainPacket + valid bool + expected []byte + }{ + { + PlainPacket{}, true, + []byte{0x0, 0x0}, + }, + { + PlainPacket{Payload: []byte{0x0, 0x0, 0x0}}, true, + []byte{0x0, 0x0, 0x0, 0x0, 0x0}, + }, + // TODO: much more test vectors + } + + for _, vector := range testvectors { + result, err := vector.packet.MarshalBinary() + if vector.valid { + if err != nil { + t.Fatal("unexpected error:", err) + } + if bytes.Compare(vector.expected, result) != 0 { + t.Fatalf("resulting packet is invalid is: '%v', should be '%v'", result, vector.expected) + } + } else { + if err == nil { + t.Fatalf("marshalling '%+v' should give an error", vector.packet) + } + } + } +} + +func TestPlainPacketUnmarshal(t *testing.T) { + testvectors := []struct { + data []byte + valid bool + expected PlainPacket + }{ + { + []byte{}, + false, PlainPacket{}, + }, + { + []byte{0x0}, + false, PlainPacket{}, + }, + { + []byte{0x0, 0x0}, + true, PlainPacket{}, + }, + { + []byte{0x0, 0x0, 0x0}, + true, PlainPacket{Payload: []byte{0x0}}, + }, + { + []byte{0x0, 0x0, 0x0, 0x01}, + true, PlainPacket{Payload: []byte{0x0, 0x01}}, + }, + // TODO: much more test vectors + } + + for _, vector := range testvectors { + var result PlainPacket + err := result.UnmarshalBinary(vector.data) + if vector.valid { + if err != nil { + t.Fatal("unexpected error:", err) + } + if !reflect.DeepEqual(vector.expected, result) { + t.Fatalf("unmarshalled packet is wrong: is '%+v', should be '%+v'", result, vector.expected) + } + } else { + if err == nil { + t.Fatalf("unmarshalling '%+v' should give an error", vector.data) + } + } + } +} + +func TestEncryptedPacketMarshal(t *testing.T) { + testvectors := []struct { + packet EncryptedPacket + valid bool + expected []byte + }{ + { + EncryptedPacket{}, false, + []byte{}, + }, + { + EncryptedPacket{Payload: []byte{0x0, 0x0}}, true, + []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + }, + // TODO: much more test vectors + } + + for _, vector := range testvectors { + result, err := vector.packet.MarshalBinary() + if vector.valid { + if err != nil { + t.Fatal("unexpected error:", err) + } + if bytes.Compare(vector.expected, result) != 0 { + t.Fatalf("resulting packet is invalid is: '%v', should be '%v'", result, vector.expected) + } + } else { + if err == nil { + t.Fatalf("marshalling '%+v' should give an error", vector.packet) + } + } + } +} + +func TestEncryptedPacketUnmarshal(t *testing.T) { + testvectors := []struct { + data []byte + valid bool + expected EncryptedPacket + }{ + { + []byte{}, + false, EncryptedPacket{}, + }, + { + []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + true, EncryptedPacket{Payload: []byte{0x0, 0x0}}, + }, + // TODO: much more test vectors + } + + for _, vector := range testvectors { + var result EncryptedPacket + err := result.UnmarshalBinary(vector.data) + if vector.valid { + if err != nil { + t.Fatal("unexpected error:", err) + } + if !reflect.DeepEqual(vector.expected, result) { + t.Fatalf("unmarshalled packet is wrong: is '%+v', should be '%+v'", result, vector.expected) + } + } else { + if err == nil { + t.Fatalf("unmarshalling '%+v' should give an error", vector.data) + } + } + } +} |