2022-01-09 13:05:36 +10:30
|
|
|
package secure
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/rand"
|
2022-01-13 14:26:16 +10:30
|
|
|
"encoding/binary"
|
2022-01-09 13:05:36 +10:30
|
|
|
"errors"
|
2022-01-13 14:26:16 +10:30
|
|
|
"io"
|
2022-01-09 13:05:36 +10:30
|
|
|
"net"
|
2022-01-26 08:49:54 +10:30
|
|
|
"time"
|
2022-01-09 13:05:36 +10:30
|
|
|
|
2022-01-16 20:35:35 +10:30
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
|
2022-01-09 13:05:36 +10:30
|
|
|
"golang.org/x/crypto/nacl/box"
|
|
|
|
)
|
|
|
|
|
|
|
|
type SecureMessage struct {
|
|
|
|
Msg []byte
|
2022-01-13 14:26:16 +10:30
|
|
|
Size uint16
|
2022-01-09 13:05:36 +10:30
|
|
|
Nonce [24]byte
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *SecureMessage) toByteArray() []byte {
|
2022-01-13 14:26:16 +10:30
|
|
|
length := []byte{0x0, 0x0}
|
|
|
|
binary.BigEndian.PutUint16(length, uint16(len(s.Msg)))
|
|
|
|
out := append(s.Nonce[:], length...)
|
|
|
|
out = append(out, s.Msg[:]...)
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
|
|
|
func DeterminePacketSize(data []byte) uint16 {
|
|
|
|
// first 24 bytes are the nonce, then the size
|
|
|
|
if len(data) < 26 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
size := binary.BigEndian.Uint16(data[24:26])
|
|
|
|
size += 26 // add the length header and the nonce
|
|
|
|
return size
|
2022-01-09 13:05:36 +10:30
|
|
|
}
|
|
|
|
|
|
|
|
func ConstructSecureMessage(sm []byte) SecureMessage {
|
|
|
|
var nonce [24]byte
|
|
|
|
nonceArray := sm[:24]
|
2022-01-13 14:26:16 +10:30
|
|
|
size := binary.BigEndian.Uint16(sm[24:26])
|
2022-01-09 13:05:36 +10:30
|
|
|
copy(nonce[:], nonceArray)
|
|
|
|
|
|
|
|
// Trim out all unnecessary bytes
|
2022-01-13 14:26:16 +10:30
|
|
|
// msg := bytes.Trim(sm[24:], "\x00")
|
2022-01-09 13:05:36 +10:30
|
|
|
|
2022-01-13 14:26:16 +10:30
|
|
|
return SecureMessage{Msg: sm[26 : 26+size], Size: size, Nonce: nonce}
|
2022-01-09 13:05:36 +10:30
|
|
|
}
|
|
|
|
|
|
|
|
type SecureConnection struct {
|
2022-01-15 18:20:31 +10:30
|
|
|
// Conn *net.TCPConn
|
|
|
|
Conn io.ReadWriteCloser
|
2022-01-09 13:05:36 +10:30
|
|
|
SharedKey *[32]byte
|
2022-01-13 14:26:16 +10:30
|
|
|
Buffer *bytes.Buffer
|
2022-01-09 13:05:36 +10:30
|
|
|
}
|
|
|
|
|
|
|
|
func (s *SecureConnection) Read(p []byte) (int, error) {
|
2022-01-13 22:20:35 +10:30
|
|
|
message := make([]byte, 2048)
|
2022-01-09 13:05:36 +10:30
|
|
|
// Read the message from the buffer
|
2022-01-13 14:26:16 +10:30
|
|
|
eof := false
|
|
|
|
|
2022-01-13 22:20:35 +10:30
|
|
|
outputBytes := make([]byte, 0)
|
|
|
|
|
2022-01-09 13:05:36 +10:30
|
|
|
n, err := s.Conn.Read(message)
|
|
|
|
|
2022-01-13 14:26:16 +10:30
|
|
|
if err != nil && err != io.EOF {
|
2022-01-16 20:35:35 +10:30
|
|
|
log.Errorf("read: error in connection read %v", err)
|
2022-01-13 14:26:16 +10:30
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
if err == io.EOF {
|
|
|
|
eof = true
|
|
|
|
}
|
|
|
|
s.Buffer.Write(message[:n])
|
|
|
|
|
2022-01-13 22:20:35 +10:30
|
|
|
for {
|
2022-01-13 14:26:16 +10:30
|
|
|
|
2022-01-13 22:20:35 +10:30
|
|
|
actualPacketEnd := DeterminePacketSize(s.Buffer.Bytes())
|
|
|
|
if actualPacketEnd == 0 {
|
|
|
|
break
|
|
|
|
}
|
2022-01-09 13:05:36 +10:30
|
|
|
|
2022-01-14 09:21:57 +10:30
|
|
|
// our buffer contains a partial packet
|
2022-01-13 22:20:35 +10:30
|
|
|
if int(actualPacketEnd) > len(s.Buffer.Bytes()) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2022-01-14 09:21:57 +10:30
|
|
|
encryptedBytes := make([]byte, actualPacketEnd)
|
|
|
|
n, err := s.Buffer.Read(encryptedBytes)
|
|
|
|
if err != nil && err != io.EOF {
|
2022-01-16 20:35:35 +10:30
|
|
|
log.Errorf("failed to get encrypted bytes from buffer?")
|
2022-01-14 09:21:57 +10:30
|
|
|
return 0, errors.New("failed to get encrypted bytes from buffer")
|
|
|
|
}
|
|
|
|
if n != int(actualPacketEnd) {
|
2022-01-16 20:35:35 +10:30
|
|
|
log.Errorf("failed to get right number of encrypted bytes from buffer")
|
2022-01-14 09:21:57 +10:30
|
|
|
return 0, errors.New("failed to get right number of encrypted bytes from buffer")
|
|
|
|
|
|
|
|
}
|
|
|
|
secureMessage := ConstructSecureMessage(encryptedBytes)
|
2022-01-13 22:20:35 +10:30
|
|
|
// log.Printf("Secure message from wire bytes: \n nonce: %v\n msg: %v\n size: %d\n", secureMessage.Nonce, secureMessage.Msg, secureMessage.Size)
|
|
|
|
decryptedMessage, ok := box.OpenAfterPrecomputation(nil, secureMessage.Msg, &secureMessage.Nonce, s.SharedKey)
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
return 0, errors.New("problem decrypting the message")
|
|
|
|
}
|
|
|
|
|
|
|
|
outputBytes = append(outputBytes, decryptedMessage...)
|
2022-01-09 13:05:36 +10:30
|
|
|
|
2022-01-13 22:20:35 +10:30
|
|
|
if eof && s.Buffer.Len() == 0 {
|
2022-01-16 20:35:35 +10:30
|
|
|
log.Debugf("returning the final packet")
|
2022-01-13 22:20:35 +10:30
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
err = io.EOF
|
|
|
|
if !eof {
|
|
|
|
err = nil
|
2022-01-13 14:26:16 +10:30
|
|
|
}
|
|
|
|
|
2022-01-13 22:20:35 +10:30
|
|
|
copy(p, outputBytes)
|
|
|
|
|
|
|
|
return len(outputBytes), err
|
2022-01-09 13:05:36 +10:30
|
|
|
}
|
|
|
|
|
|
|
|
func (s *SecureConnection) Write(p []byte) (int, error) {
|
|
|
|
var nonce [24]byte
|
|
|
|
|
|
|
|
// Create a new nonce for each message sent
|
|
|
|
rand.Read(nonce[:])
|
2022-01-16 20:35:35 +10:30
|
|
|
|
2022-01-09 13:05:36 +10:30
|
|
|
encryptedMessage := box.SealAfterPrecomputation(nil, p, &nonce, s.SharedKey)
|
|
|
|
sm := SecureMessage{Msg: encryptedMessage, Nonce: nonce}
|
|
|
|
|
|
|
|
// Write it to the connection
|
2022-01-13 14:26:16 +10:30
|
|
|
wireBytes := sm.toByteArray()
|
2022-01-16 20:35:35 +10:30
|
|
|
|
2022-01-13 14:26:16 +10:30
|
|
|
return s.Conn.Write(wireBytes)
|
2022-01-09 13:05:36 +10:30
|
|
|
}
|
|
|
|
|
|
|
|
func Handshake(conn *net.TCPConn) *[32]byte {
|
|
|
|
var peerKey, sharedKey [32]byte
|
|
|
|
|
|
|
|
publicKey, privateKey, _ := box.GenerateKey(rand.Reader)
|
|
|
|
|
|
|
|
conn.Write(publicKey[:])
|
|
|
|
|
|
|
|
peerKeyArray := make([]byte, 32)
|
|
|
|
conn.Read(peerKeyArray)
|
|
|
|
copy(peerKey[:], peerKeyArray)
|
|
|
|
|
|
|
|
box.Precompute(&sharedKey, &peerKey, privateKey)
|
|
|
|
|
|
|
|
return &sharedKey
|
|
|
|
}
|
2022-01-13 14:26:16 +10:30
|
|
|
|
|
|
|
type OperationTypeEnum byte
|
|
|
|
|
|
|
|
const (
|
|
|
|
OperationTypeSend OperationTypeEnum = iota
|
2022-01-14 23:30:14 +10:30
|
|
|
OperationTypeList
|
2022-01-15 14:04:13 +10:30
|
|
|
OperationTypeReceive
|
2022-01-13 14:26:16 +10:30
|
|
|
)
|
|
|
|
|
2022-01-16 12:58:11 +10:30
|
|
|
// PacketStartRequest is sent from the client to the server at the beginning
|
2022-01-13 14:26:16 +10:30
|
|
|
// to authenticate and annonce the requested particular operation
|
2022-01-16 12:58:11 +10:30
|
|
|
type PacketStartRequest struct {
|
2022-01-13 14:26:16 +10:30
|
|
|
OperationType OperationTypeEnum
|
|
|
|
ClientName string
|
|
|
|
ProtocolVersion string
|
|
|
|
AuthToken string
|
|
|
|
}
|
|
|
|
|
2022-01-16 12:58:11 +10:30
|
|
|
type PacketStartResponseEnum byte
|
|
|
|
|
|
|
|
const (
|
|
|
|
// Client can connect
|
|
|
|
PacketStartResponseEnumOK PacketStartResponseEnum = iota
|
|
|
|
// Client using wrong protocol version
|
|
|
|
PacketStartResponseEnumWrongProtocol
|
|
|
|
// Client supplied bad auth token
|
|
|
|
PacketStartResponseEnumBadAuthToken
|
|
|
|
)
|
|
|
|
|
|
|
|
type PacketStartResponse struct {
|
|
|
|
Response PacketStartResponseEnum
|
|
|
|
}
|
|
|
|
|
2022-01-13 14:26:16 +10:30
|
|
|
type PacketSendDataStart struct {
|
|
|
|
Filename string
|
|
|
|
TotalSize uint32
|
|
|
|
}
|
2022-01-15 14:04:13 +10:30
|
|
|
type PacketSendDataNext struct {
|
|
|
|
Size uint16
|
|
|
|
Data []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// PacketReceiveDataStart is sent from the server to the client when
|
|
|
|
// the client asks for a file to be sent to them.
|
|
|
|
type PacketReceiveDataStartRequest struct {
|
|
|
|
Id uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
type PacketReceiveDataStartResponseEnum byte
|
|
|
|
|
|
|
|
const (
|
|
|
|
// File transfer can begin
|
|
|
|
ReceiveDataStartResponseOK PacketReceiveDataStartResponseEnum = iota
|
|
|
|
// No such file by index
|
|
|
|
ReceiveDataStartResponseNotFound
|
|
|
|
)
|
|
|
|
|
|
|
|
// PacketReceiveDataStartResponse is the response to the above packet.
|
|
|
|
type PacketReceiveDataStartResponse struct {
|
|
|
|
Status PacketReceiveDataStartResponseEnum
|
|
|
|
Filename string
|
|
|
|
Kind string
|
|
|
|
TotalSize uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
type PacketReceiveDataNext struct {
|
|
|
|
Size uint16
|
|
|
|
Data []byte
|
|
|
|
Last bool
|
|
|
|
}
|
2022-01-13 14:26:16 +10:30
|
|
|
|
2022-01-14 23:30:14 +10:30
|
|
|
type PacketListData struct {
|
2022-01-26 08:49:54 +10:30
|
|
|
Id uint32
|
|
|
|
Filename string
|
|
|
|
FileSize uint32
|
|
|
|
Timestamp time.Time
|
|
|
|
Kind string
|
2022-01-14 23:30:14 +10:30
|
|
|
}
|