249 lines
5.5 KiB
Go
249 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"golang.org/x/crypto/chacha20poly1305"
|
|
)
|
|
|
|
const HeaderSize int = 32 + 1 + 4 + 4
|
|
const SecureHeaderSize int = 1 + 42 + 32 + 4
|
|
|
|
type SessionID [32]byte
|
|
|
|
type SecurePacket struct {
|
|
isRsa byte // 0 = false everything else is true
|
|
nonce [24]byte
|
|
sid SessionID
|
|
dataLength uint32
|
|
encryptedData []byte
|
|
}
|
|
|
|
type Packet struct {
|
|
// headerLength uint32
|
|
sid SessionID
|
|
flag HeaderFlag
|
|
sync uint32
|
|
dataLength uint32
|
|
data []byte
|
|
}
|
|
|
|
func NewSymetricSecurePacket(key [32]byte, pck *Packet) *SecurePacket {
|
|
sid := pck.sid
|
|
data := pck.ToBytes()
|
|
aead, err := chacha20poly1305.NewX(key[:])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
nonce := make([]byte, 24)
|
|
if _, err = rand.Read(nonce); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
encrypted := make([]byte, len(data)+aead.Overhead())
|
|
encrypted = aead.Seal(nil, nonce, data, nil)
|
|
|
|
return &SecurePacket{
|
|
isRsa: 0,
|
|
nonce: [24]byte(nonce),
|
|
sid: sid,
|
|
dataLength: uint32(len(encrypted)),
|
|
encryptedData: encrypted,
|
|
}
|
|
}
|
|
|
|
func SecurePacketFromBytes(bytes []byte) SecurePacket {
|
|
isRsa := bytes[0]
|
|
nonce := bytes[1:25]
|
|
sid := SessionID(bytes[25:57])
|
|
length := binary.LittleEndian.Uint32(bytes[57:61])
|
|
enc := bytes[61 : 61+length]
|
|
|
|
return SecurePacket{
|
|
isRsa: isRsa,
|
|
nonce: [24]byte(nonce),
|
|
sid: sid,
|
|
encryptedData: enc,
|
|
dataLength: length,
|
|
}
|
|
}
|
|
|
|
func (secPck *SecurePacket) ToBytes() []byte {
|
|
arr := make([]byte, SecureHeaderSize+len(secPck.encryptedData))
|
|
arr[0] = secPck.isRsa
|
|
copy(arr[1:25], secPck.nonce[:])
|
|
copy(arr[25:57], secPck.sid[:])
|
|
binary.LittleEndian.PutUint32(arr[57:61], secPck.dataLength)
|
|
copy(arr[61:], secPck.encryptedData)
|
|
|
|
return arr
|
|
}
|
|
|
|
func (secPck *SecurePacket) ExtractPacket(key [32]byte) (*Packet, error) {
|
|
aead, err := chacha20poly1305.NewX(key[:])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
data, err := aead.Open(nil, secPck.nonce[:], secPck.encryptedData, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
packet := PacketFromBytes(data)
|
|
return &packet, nil
|
|
}
|
|
|
|
func NewRsaPacket(sid SessionID, key [32]byte) *SecurePacket {
|
|
return &SecurePacket{
|
|
isRsa: 1,
|
|
nonce: [24]byte(make([]byte, 24)),
|
|
sid: sid,
|
|
encryptedData: key[:],
|
|
}
|
|
}
|
|
|
|
func (secPck *SecurePacket) ExtractKey( /*RSA HERE LATER*/ ) []byte {
|
|
return secPck.encryptedData[:32]
|
|
}
|
|
|
|
func PacketFromBytes(bytes []byte) Packet {
|
|
flag := HeaderFlag(bytes[0])
|
|
sid := SessionID(bytes[1:33])
|
|
sync := binary.LittleEndian.Uint32(bytes[33:37])
|
|
dataLength := binary.LittleEndian.Uint32(bytes[37:41])
|
|
pck := Packet{
|
|
sid: sid,
|
|
flag: flag,
|
|
sync: sync,
|
|
dataLength: dataLength,
|
|
data: bytes[HeaderSize : HeaderSize+int(dataLength)],
|
|
}
|
|
return pck
|
|
}
|
|
|
|
func NewAck(pckToAck *Packet) *Packet {
|
|
data := make([]byte, 4)
|
|
binary.LittleEndian.PutUint32(data, pckToAck.sync)
|
|
return &Packet{
|
|
sid: pckToAck.sid,
|
|
flag: Ack,
|
|
sync: pckToAck.sync + 1,
|
|
dataLength: uint32(4),
|
|
data: data,
|
|
}
|
|
}
|
|
|
|
func NewRequest(path string) *Packet {
|
|
data := []byte(path)
|
|
buf := make([]byte, 32)
|
|
_, err := rand.Read(buf)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return &Packet{
|
|
sid: SessionID(buf),
|
|
flag: Request,
|
|
sync: 0,
|
|
dataLength: uint32(len(data)),
|
|
data: data,
|
|
}
|
|
}
|
|
|
|
func (pck *Packet) GetUint32Payload() (uint32, error) {
|
|
flag := pck.flag
|
|
if flag != PTE && flag != Ack && flag != End && flag != Resend {
|
|
return 0, errors.New(fmt.Sprintf("Can not get Sync from Packet Type with flag: %v", flag))
|
|
}
|
|
return binary.LittleEndian.Uint32(pck.data), nil
|
|
}
|
|
|
|
func (pck *Packet) GetFilePath() (string, error) {
|
|
if pck.flag != Request {
|
|
return "", errors.New("Can not get FilePath from Packet that is not Request")
|
|
}
|
|
return string(pck.data), nil
|
|
}
|
|
|
|
func NewResendFile(resendPck *Packet, data []byte) *Packet {
|
|
sync, _ := resendPck.GetUint32Payload()
|
|
return &Packet{
|
|
sid: resendPck.sid,
|
|
flag: File,
|
|
sync: sync,
|
|
dataLength: uint32(len(data)),
|
|
data: data,
|
|
}
|
|
}
|
|
|
|
func NewFile(lastPck *Packet, data []byte) *Packet {
|
|
return &Packet{
|
|
sid: lastPck.sid,
|
|
flag: File,
|
|
sync: lastPck.sync + 1,
|
|
dataLength: uint32(len(data)),
|
|
data: data,
|
|
}
|
|
}
|
|
|
|
func NewEnd(lastFilePck *Packet) *Packet {
|
|
data := make([]byte, 4)
|
|
binary.LittleEndian.PutUint32(data, lastFilePck.sync)
|
|
return &Packet{
|
|
sid: lastFilePck.sid,
|
|
flag: End,
|
|
sync: lastFilePck.sync + 1,
|
|
dataLength: uint32(4),
|
|
data: data,
|
|
}
|
|
}
|
|
|
|
func NewResend(sync uint32, lastPck *Packet) *Packet {
|
|
data := make([]byte, 4)
|
|
binary.LittleEndian.PutUint32(data, sync)
|
|
return &Packet{
|
|
sid: lastPck.sid,
|
|
flag: Resend,
|
|
sync: lastPck.sync + 1,
|
|
dataLength: uint32(4),
|
|
data: data,
|
|
}
|
|
}
|
|
|
|
func NewPte(fileSize uint32, lastPck *Packet) *Packet {
|
|
data := make([]byte, 4)
|
|
binary.LittleEndian.PutUint32(data, fileSize)
|
|
return &Packet{
|
|
sid: lastPck.sid,
|
|
flag: PTE,
|
|
sync: lastPck.sync + 1,
|
|
dataLength: uint32(4),
|
|
data: data,
|
|
}
|
|
}
|
|
|
|
func (pck *Packet) ToBytes() []byte {
|
|
arr := make([]byte, HeaderSize+int(pck.dataLength))
|
|
arr[0] = byte(pck.flag)
|
|
copy(arr[1:33], pck.sid[:])
|
|
binary.LittleEndian.PutUint32(arr[33:37], pck.sync)
|
|
binary.LittleEndian.PutUint32(arr[37:41], pck.dataLength)
|
|
copy(arr[41:], pck.data)
|
|
|
|
return arr
|
|
}
|
|
|
|
type HeaderFlag uint8
|
|
|
|
const (
|
|
Request HeaderFlag = iota
|
|
PTE HeaderFlag = iota
|
|
Ack HeaderFlag = iota
|
|
File HeaderFlag = iota
|
|
End HeaderFlag = iota
|
|
Resend HeaderFlag = iota
|
|
)
|