Browse Source

Encryption

main
Unbewohnte 3 years ago
parent
commit
49b25443fe
  1. 2
      src/addr/local.go
  2. 2
      src/encryption/decrypt.go
  3. 2
      src/encryption/encrypt.go
  4. 159
      src/node/node.go
  5. 30
      src/node/packets.go
  6. 31
      src/node/transfer.go
  7. 4
      src/protocol/headers.go
  8. 33
      src/protocol/packet.go

2
src/addr/outbound.go → src/addr/local.go

@ -5,7 +5,7 @@ import (
)
// Get local IP address; from https://stackoverflow.com/a/37382208
func GetLocalIP() (string, error) {
func GetLocal() (string, error) {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
return "", err

2
src/encryption/decrypt.go

@ -7,7 +7,7 @@ import (
)
// Decrypts encrypted aes data with given key.
// https://www.melvinvivas.com/how-to-encrypt-and-decrypt-data-using-aes/ - very grateful to the author, THANK YOU.
// From https://www.melvinvivas.com/how-to-encrypt-and-decrypt-data-using-aes/
func Decrypt(key, dataToDecrypt []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {

2
src/encryption/encrypt.go

@ -7,7 +7,7 @@ import (
)
// Encrypts given data using aes encryption.
// https://www.melvinvivas.com/how-to-encrypt-and-decrypt-data-using-aes/ - very grateful to the author, THANK YOU.
// From https://www.melvinvivas.com/how-to-encrypt-and-decrypt-data-using-aes/
func Encrypt(key, dataToEncrypt []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {

159
src/node/node.go

@ -14,6 +14,7 @@ import (
"github.com/Unbewohnte/ftu/addr"
"github.com/Unbewohnte/ftu/checksum"
"github.com/Unbewohnte/ftu/encryption"
"github.com/Unbewohnte/ftu/fsys"
"github.com/Unbewohnte/ftu/protocol"
)
@ -42,6 +43,7 @@ type TransferInfo struct {
// Sender and receiver in one type !
type Node struct {
PacketPipe chan *protocol.Packet
ErrorPipe chan error
Mutex *sync.Mutex
IsSending bool
Net *Net
@ -55,6 +57,7 @@ func NewNode(options *NodeOptions) (*Node, error) {
node := Node{
PacketPipe: make(chan *protocol.Packet, 100),
ErrorPipe: make(chan error, 100),
Mutex: mutex,
IsSending: options.IsSending,
Net: &Net{
@ -147,7 +150,7 @@ func (node *Node) Start() {
case true:
// SENDER
localIP, err := addr.GetLocalIP()
localIP, err := addr.GetLocal()
if err != nil {
panic(err)
}
@ -164,82 +167,96 @@ func (node *Node) Start() {
panic(err)
}
// generate and send encryption key
encrKey := encryption.Generate32AESkey()
node.Net.EncryptionKey = encrKey
fmt.Printf("Generated encryption key: %s\n", encrKey)
err = sendEncryptionKey(node.Net.Conn, encrKey)
if err != nil {
panic(err)
}
// listen for incoming packets
go receivePackets(node.Net.Conn, node.PacketPipe)
// send fileoffer
go sendFilePacket(node.Net.Conn, file)
go sendFilePacket(node.Net.Conn, file, node.Net.EncryptionKey)
// mainloop
for {
node.Mutex.Lock()
stopped := node.State.Stopped
node.Mutex.Unlock()
if stopped {
node.Mutex.Lock()
if node.State.Stopped {
node.disconnect()
node.Mutex.Unlock()
break
}
incomingPacket := <-node.PacketPipe
incomingPacket, ok := <-node.PacketPipe
if !ok {
node.State.Stopped = true
}
if node.Net.EncryptionKey != nil {
err = incomingPacket.DecryptBody(node.Net.EncryptionKey)
if err != nil {
panic(err)
}
}
switch incomingPacket.Header {
case protocol.HeaderReady:
node.Mutex.Lock()
node.TransferInfo.Ready = true
node.Mutex.Unlock()
case protocol.HeaderAccept:
node.Mutex.Lock()
node.State.AllowedToTransfer = true
node.Mutex.Unlock()
go fmt.Printf("Transfer allowed. Sending...\n")
fmt.Printf("Transfer allowed. Sending...\n")
case protocol.HeaderDisconnecting:
node.Mutex.Lock()
node.State.Stopped = true
node.Mutex.Unlock()
go fmt.Printf("%s disconnected\n", node.Net.Conn.RemoteAddr())
fmt.Printf("%s disconnected\n", node.Net.Conn.RemoteAddr())
case protocol.HeaderReject:
node.Mutex.Lock()
node.State.Stopped = true
node.Mutex.Unlock()
go fmt.Printf("Transfer rejected. Disconnecting...")
fmt.Printf("Transfer rejected. Disconnecting...")
}
if node.State.AllowedToTransfer {
err = sendPiece(file, node.Net.Conn)
if node.State.AllowedToTransfer || node.TransferInfo.Ready {
err = sendPiece(file, node.Net.Conn, node.Net.EncryptionKey)
if err != nil {
if err == ErrorSentAll {
// the file has been sent fully
fileIDBuff := new(bytes.Buffer)
err = binary.Write(fileIDBuff, binary.BigEndian, file.ID)
if err != nil {
node.Mutex.Lock()
node.State.Stopped = true
node.Mutex.Unlock()
panic(err)
}
protocol.SendPacket(node.Net.Conn, protocol.Packet{
endFilePacket := protocol.Packet{
Header: protocol.HeaderEndfile,
Body: fileIDBuff.Bytes(),
})
}
if node.Net.EncryptionKey != nil {
err = endFilePacket.EncryptBody(node.Net.EncryptionKey)
if err != nil {
panic(err)
}
}
protocol.SendPacket(node.Net.Conn, endFilePacket)
node.Mutex.Lock()
node.State.Stopped = true
node.Mutex.Unlock()
} else {
node.Mutex.Lock()
node.State.Stopped = true
node.Mutex.Unlock()
fmt.Printf("An error occured when sending a piece of \"%s\": %s\n", file.Name, err)
panic(err)
}
}
node.TransferInfo.Ready = false
}
}
@ -257,14 +274,8 @@ func (node *Node) Start() {
// mainloop
for {
node.Mutex.Lock()
stopped := node.State.Stopped
node.Mutex.Unlock()
if stopped {
node.Mutex.Lock()
if node.State.Stopped {
node.disconnect()
node.Mutex.Unlock()
break
}
@ -272,8 +283,15 @@ func (node *Node) Start() {
if !ok {
break
}
if node.Net.EncryptionKey != nil {
err = incomingPacket.DecryptBody(node.Net.EncryptionKey)
if err != nil {
panic(err)
}
}
switch incomingPacket.Header {
case protocol.HeaderFile:
go func() {
file, err := decodeFilePacket(incomingPacket)
@ -311,11 +329,27 @@ func (node *Node) Start() {
file.Path = fullFilePath
file.Open()
node.Mutex.Lock()
node.TransferInfo.AcceptedFiles = append(node.TransferInfo.AcceptedFiles, file)
node.Mutex.Unlock()
// notify the node that we`re ready to transportation
// send aceptance packet
acceptancePacket := protocol.Packet{
Header: protocol.HeaderAccept,
Body: responsePacketFileIDBuffer.Bytes(),
}
if node.Net.EncryptionKey != nil {
err = acceptancePacket.EncryptBody(node.Net.EncryptionKey)
if err != nil {
panic(err)
}
}
err = protocol.SendPacket(node.Net.Conn, acceptancePacket)
if err != nil {
panic(err)
}
// notify the node that we`re ready to transportation. No need
// for encryption because the body is nil
err = protocol.SendPacket(node.Net.Conn, protocol.Packet{
Header: protocol.HeaderReady,
})
@ -323,25 +357,26 @@ func (node *Node) Start() {
panic(err)
}
// send aceptance packet
protocol.SendPacket(node.Net.Conn, protocol.Packet{
Header: protocol.HeaderAccept,
Body: responsePacketFileIDBuffer.Bytes(),
})
} else {
// no
err = protocol.SendPacket(node.Net.Conn, protocol.Packet{
rejectionPacket := protocol.Packet{
Header: protocol.HeaderReject,
Body: responsePacketFileIDBuffer.Bytes(),
})
}
if node.Net.EncryptionKey != nil {
err = rejectionPacket.EncryptBody(node.Net.EncryptionKey)
if err != nil {
panic(err)
}
}
err = protocol.SendPacket(node.Net.Conn, rejectionPacket)
if err != nil {
panic(err)
}
node.Mutex.Lock()
node.State.Stopped = true
node.Mutex.Unlock()
}
}()
@ -354,7 +389,6 @@ func (node *Node) Start() {
panic(err)
}
node.Mutex.Lock()
for _, acceptedFile := range node.TransferInfo.AcceptedFiles {
if acceptedFile.ID == fileID {
// accepted
@ -368,7 +402,6 @@ func (node *Node) Start() {
}
}
}
node.Mutex.Unlock()
err = protocol.SendPacket(node.Net.Conn, protocol.Packet{
Header: protocol.HeaderReady,
@ -385,7 +418,6 @@ func (node *Node) Start() {
panic(err)
}
node.Mutex.Lock()
for index, acceptedFile := range node.TransferInfo.AcceptedFiles {
if acceptedFile.ID == fileID {
// accepted
@ -414,14 +446,23 @@ func (node *Node) Start() {
}
node.State.Stopped = true
node.Mutex.Unlock()
case protocol.HeaderEncryptionKey:
// retrieve the key
packetReader := bytes.NewReader(incomingPacket.Body)
var keySize uint64
binary.Read(packetReader, binary.BigEndian, &keySize)
encrKey := make([]byte, keySize)
packetReader.Read(encrKey)
node.Net.EncryptionKey = encrKey
case protocol.HeaderDisconnecting:
node.Mutex.Lock()
node.State.Stopped = true
node.Mutex.Unlock()
go fmt.Printf("%s disconnected\n", node.Net.Conn.RemoteAddr())
fmt.Printf("%s disconnected\n", node.Net.Conn.RemoteAddr())
}
}

30
src/node/packets.go

@ -10,7 +10,32 @@ import (
"github.com/Unbewohnte/ftu/protocol"
)
// Reads packets from connection in an endless loop, sends them to the channel
// sends an encryption key to the other side
func sendEncryptionKey(connection net.Conn, encrKey []byte) error {
encrKeyPacketBuffer := new(bytes.Buffer)
encrKeyLength := uint64(len(encrKey))
err := binary.Write(encrKeyPacketBuffer, binary.BigEndian, &encrKeyLength)
if err != nil {
return err
}
encrKeyPacketBuffer.Write(encrKey)
err = protocol.SendPacket(connection, protocol.Packet{
Header: protocol.HeaderEncryptionKey,
Body: encrKeyPacketBuffer.Bytes(),
})
if err != nil {
return err
}
return nil
}
// Reads packets from connection in an endless loop, sends them to the channel, if encrKey is not nil -
// decrypts packet`s body beforehand
func receivePackets(connection net.Conn, packetPipe chan *protocol.Packet) error {
for {
if connection == nil {
@ -33,7 +58,8 @@ func receivePackets(connection net.Conn, packetPipe chan *protocol.Packet) error
}
}
// decodes packet with the header FILE into the fsys.File struct
// decodes packet with the header FILE into the fsys.File struct. If encrKey is not nil -
// filepacket`s body will be decrypted beforehand
func decodeFilePacket(filePacket *protocol.Packet) (*fsys.File, error) {
// FILE~(idInBinary)(filenameLengthInBinary)(filename)(filesize)(checksumLengthInBinary)checksum

31
src/node/transfer.go

@ -12,8 +12,8 @@ import (
"github.com/Unbewohnte/ftu/protocol"
)
// sends a notification about the file
func sendFilePacket(connection net.Conn, file *fsys.File) error {
// sends a notification about the file to the other side. If encrKey is not nil - encrypts packet`s body
func sendFilePacket(connection net.Conn, file *fsys.File, encrKey []byte) error {
if connection == nil {
return ErrorNotConnected
}
@ -54,6 +54,15 @@ func sendFilePacket(connection net.Conn, file *fsys.File) error {
filePacket.Body = fPacketBodyBuff.Bytes()
if encrKey != nil {
// if the key is given - encrypt ready-to-go packet
err = filePacket.EncryptBody(encrKey)
if err != nil {
return err
}
}
// and send it
err = protocol.SendPacket(connection, filePacket)
if err != nil {
return err
@ -72,8 +81,9 @@ func sendDirectoryPacket(connection net.Conn, dir *fsys.Directory) error {
}
// sends a piece of file to the connection; The next calls will send
// another piece util the file has been fully sent
func sendPiece(file *fsys.File, connection net.Conn) error {
// another piece util the file has been fully sent. If encrKey is not nil - encrypts each packet with
// this key
func sendPiece(file *fsys.File, connection net.Conn, encrKey []byte) error {
if file.Handler == nil {
fHandler, err := os.Open(file.Path)
if err != nil {
@ -106,9 +116,15 @@ func sendPiece(file *fsys.File, connection net.Conn) error {
// fill the remaining space of packet with the contents of a file
canSendBytes := uint64(protocol.MAXPACKETSIZE) - fileBytesPacket.Size() - uint64(packetBodyBuff.Len())
if encrKey != nil {
// account for padding
canSendBytes -= 32
}
if (file.Size - file.SentBytes) < canSendBytes {
canSendBytes = (file.Size - file.SentBytes)
}
fileBytes := make([]byte, canSendBytes)
read, err := file.Handler.ReadAt(fileBytes, int64(file.SentBytes))
@ -120,6 +136,13 @@ func sendPiece(file *fsys.File, connection net.Conn) error {
fileBytesPacket.Body = packetBodyBuff.Bytes()
if encrKey != nil {
err = fileBytesPacket.EncryptBody(encrKey)
if err != nil {
return err
}
}
// send it to the other side
err = protocol.SendPacket(connection, fileBytesPacket)
if err != nil {

4
src/protocol/headers.go

@ -9,8 +9,8 @@ type Header string
// ENCRKEY.
// The FIRST header to be sent. Sent immediately after the connection has been established
// by sender. Body contains randomly generated by sender aes encryption key.
// ie: ENCRKEY~SUPER_SECURE_ENCRYPTION_KEY_||||
// by sender. Body contains a size of a key and the key itself.
// ie: ENCRKEY~(size)(SUPER SECURE ENCRYPTION KEY)
const HeaderEncryptionKey Header = "ENCRKEY"
// REJECT.

33
src/protocol/packet.go

@ -59,7 +59,7 @@ func BytesToPacket(packetbytes []byte) (*Packet, error) {
}, nil
}
var ErrorExceededMaxPacketsize error = fmt.Errorf("too big packet")
var ErrorExceededMaxPacketsize error = fmt.Errorf("the packet is too big")
// Converts given packet struct into ready-to-transfer bytes, constructed by following the protocol
func (packet *Packet) ToBytes() ([]byte, error) {
@ -86,14 +86,15 @@ func (packet *Packet) ToBytes() ([]byte, error) {
return packetBuffer.Bytes(), nil
}
// Sends given packet to connection, following all the protocol`s rules.
// Sends given packet to connection.
// ALL packets MUST be sent by this method
func SendPacket(connection net.Conn, packet Packet) error {
packetBytes, err := packet.ToBytes()
if err != nil {
return err
}
// fmt.Printf("DEBUG: sending packet %+v\n", packet)
// fmt.Printf("[SEND] packet %+s; len: %d\n", packetBytes[:30], len(packetBytes))
// write the result (ie: (packetsize)(header)~(bodybytes))
connection.Write(packetBytes)
@ -113,6 +114,22 @@ func (packet *Packet) EncryptBody(key []byte) error {
return nil
}
// Decrypts packet`s BODY with AES decryption
func (packet *Packet) DecryptBody(key []byte) error {
if len(packet.Body) == 0 {
return nil
}
decryptedBody, err := encryption.Decrypt(key, packet.Body)
if err != nil {
return err
}
packet.Body = decryptedBody
return nil
}
// Reads a packet from given connection, returns its bytes.
// ASSUMING THAT THE PACKETS ARE SENT BY `SendPacket` function !!!!
func ReadFromConn(connection net.Conn) ([]byte, error) {
@ -143,15 +160,7 @@ func ReadFromConn(connection net.Conn) ([]byte, error) {
packetBuffer.Write(buff[:read])
}
// read the rest of the packet
// packet := make([]byte, packetSize)
// read, err := connection.Read(packet)
// if err != nil {
// return nil, err
// }
// fmt.Printf("DEBUG: read from connection: %s; length: %d\n", packetBuffer.Bytes()[:40], packetBuffer.Len())
// fmt.Printf("DEBUG: read from connection: %s; length: %d\n", packet, len(packet))
// fmt.Printf("[RECV] read from connection: %s; length: %d\n", packetBuffer.Bytes()[:30], packetBuffer.Len())
return packetBuffer.Bytes(), nil
}

Loading…
Cancel
Save