// // 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 ( "encoding/binary" "errors" "io" ) // // 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 ---+ // const ( PACKET_BUFFER_SIZE = 16384 ) var ( ErrTooShort = errors.New("packet is too short") ) type PlainPacket struct { buffer [PACKET_BUFFER_SIZE]byte header []byte payload []byte } func NewPlainPacket() (pp *PlainPacket) { pp = &PlainPacket{} pp.header = pp.buffer[:2:2] pp.payload = pp.buffer[2:2] return } func (pp *PlainPacket) SetPayloadType(payloadType uint16) { binary.BigEndian.PutUint16(pp.header, payloadType) return } func (pp *PlainPacket) GetPayloadType() (payloadType uint16) { return binary.BigEndian.Uint16(pp.header) } func (pp *PlainPacket) getPacket() (data []byte) { return pp.buffer[:len(pp.header)+len(pp.payload)] } func (pp *PlainPacket) ReadFrom(r io.Reader) (int64, error) { n, err := r.Read(pp.payload[:cap(pp.payload)]) if err != nil && err != io.EOF { return 0, err } pp.payload = pp.payload[:n] return int64(n), nil } func (pp *PlainPacket) WriteTo(w io.Writer) (int64, error) { n, err := w.Write(pp.payload) return int64(n), err } type EncryptedPacket struct { buffer [PACKET_BUFFER_SIZE]byte header []byte payload []byte authTag []byte } func NewEncryptedPacket() (ep *EncryptedPacket) { ep = &EncryptedPacket{} ep.header = ep.buffer[:8:8] ep.payload = ep.buffer[8:8] ep.authTag = nil return } func (ep *EncryptedPacket) SetAuthTagLength(length int) error { total := len(ep.payload) + len(ep.authTag) if length <= 0 { ep.payload = ep.payload[:total] ep.authTag = nil return nil } if length > (total - 2) { // minimal payload length = 2 (Payload Type) return ErrTooShort } ep.payload = ep.payload[:total-length] ep.authTag = ep.buffer[len(ep.header)+len(ep.payload) : len(ep.header)+total] return nil } func (ep *EncryptedPacket) GetAuthTagLength() int { return len(ep.authTag) } func (ep *EncryptedPacket) SetSequenceNumber(sequenceNumber uint32) { binary.BigEndian.PutUint32(ep.header[:4], sequenceNumber) return } func (ep *EncryptedPacket) GetSequenceNumber() (sequenceNumber uint32) { return binary.BigEndian.Uint32(ep.header[:4]) } func (ep *EncryptedPacket) SetSenderID(senderID uint16) { binary.BigEndian.PutUint16(ep.header[4:6], senderID) return } func (ep *EncryptedPacket) GetSenderID() (senderID uint16) { return binary.BigEndian.Uint16(ep.header[4:6]) } func (ep *EncryptedPacket) SetMux(mux uint16) { binary.BigEndian.PutUint16(ep.header[6:8], mux) return } func (ep *EncryptedPacket) GetMux() (mux uint16) { return binary.BigEndian.Uint16(ep.header[6:8]) } func (ep *EncryptedPacket) ReadFrom(r io.Reader) (int64, error) { n, err := r.Read(ep.buffer[:]) if err != nil && err != io.EOF { return 0, err } if n < len(ep.header)+2+len(ep.authTag) { // minimal payload length = 2 (Payload Type) return 0, ErrTooShort } ep.payload = ep.payload[:n-len(ep.header)] err = ep.SetAuthTagLength(len(ep.authTag)) return int64(n), err } func (ep *EncryptedPacket) getPacket() (data []byte) { return ep.buffer[:len(ep.header)+len(ep.payload)+len(ep.authTag)] } func (ep *EncryptedPacket) WriteTo(w io.Writer) (int64, error) { n, err := w.Write(ep.getPacket()) return int64(n), err }