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 // 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") conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil { if err != nil {
return "", err return "", err

2
src/encryption/decrypt.go

@ -7,7 +7,7 @@ import (
) )
// Decrypts encrypted aes data with given key. // 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) { func Decrypt(key, dataToDecrypt []byte) ([]byte, error) {
block, err := aes.NewCipher(key) block, err := aes.NewCipher(key)
if err != nil { if err != nil {

2
src/encryption/encrypt.go

@ -7,7 +7,7 @@ import (
) )
// Encrypts given data using aes encryption. // 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) { func Encrypt(key, dataToEncrypt []byte) ([]byte, error) {
block, err := aes.NewCipher(key) block, err := aes.NewCipher(key)
if err != nil { if err != nil {

159
src/node/node.go

@ -14,6 +14,7 @@ import (
"github.com/Unbewohnte/ftu/addr" "github.com/Unbewohnte/ftu/addr"
"github.com/Unbewohnte/ftu/checksum" "github.com/Unbewohnte/ftu/checksum"
"github.com/Unbewohnte/ftu/encryption"
"github.com/Unbewohnte/ftu/fsys" "github.com/Unbewohnte/ftu/fsys"
"github.com/Unbewohnte/ftu/protocol" "github.com/Unbewohnte/ftu/protocol"
) )
@ -42,6 +43,7 @@ type TransferInfo struct {
// Sender and receiver in one type ! // Sender and receiver in one type !
type Node struct { type Node struct {
PacketPipe chan *protocol.Packet PacketPipe chan *protocol.Packet
ErrorPipe chan error
Mutex *sync.Mutex Mutex *sync.Mutex
IsSending bool IsSending bool
Net *Net Net *Net
@ -55,6 +57,7 @@ func NewNode(options *NodeOptions) (*Node, error) {
node := Node{ node := Node{
PacketPipe: make(chan *protocol.Packet, 100), PacketPipe: make(chan *protocol.Packet, 100),
ErrorPipe: make(chan error, 100),
Mutex: mutex, Mutex: mutex,
IsSending: options.IsSending, IsSending: options.IsSending,
Net: &Net{ Net: &Net{
@ -147,7 +150,7 @@ func (node *Node) Start() {
case true: case true:
// SENDER // SENDER
localIP, err := addr.GetLocalIP() localIP, err := addr.GetLocal()
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -164,82 +167,96 @@ func (node *Node) Start() {
panic(err) 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 // listen for incoming packets
go receivePackets(node.Net.Conn, node.PacketPipe) go receivePackets(node.Net.Conn, node.PacketPipe)
// send fileoffer // send fileoffer
go sendFilePacket(node.Net.Conn, file) go sendFilePacket(node.Net.Conn, file, node.Net.EncryptionKey)
// mainloop // mainloop
for { for {
node.Mutex.Lock() if node.State.Stopped {
stopped := node.State.Stopped
node.Mutex.Unlock()
if stopped {
node.Mutex.Lock()
node.disconnect() node.disconnect()
node.Mutex.Unlock()
break 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 { switch incomingPacket.Header {
case protocol.HeaderReady: case protocol.HeaderReady:
node.Mutex.Lock()
node.TransferInfo.Ready = true node.TransferInfo.Ready = true
node.Mutex.Unlock()
case protocol.HeaderAccept: case protocol.HeaderAccept:
node.Mutex.Lock()
node.State.AllowedToTransfer = true node.State.AllowedToTransfer = true
node.Mutex.Unlock()
go fmt.Printf("Transfer allowed. Sending...\n") fmt.Printf("Transfer allowed. Sending...\n")
case protocol.HeaderDisconnecting: case protocol.HeaderDisconnecting:
node.Mutex.Lock()
node.State.Stopped = true 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: case protocol.HeaderReject:
node.Mutex.Lock()
node.State.Stopped = true node.State.Stopped = true
node.Mutex.Unlock()
go fmt.Printf("Transfer rejected. Disconnecting...") fmt.Printf("Transfer rejected. Disconnecting...")
} }
if node.State.AllowedToTransfer { if node.State.AllowedToTransfer || node.TransferInfo.Ready {
err = sendPiece(file, node.Net.Conn) err = sendPiece(file, node.Net.Conn, node.Net.EncryptionKey)
if err != nil { if err != nil {
if err == ErrorSentAll { if err == ErrorSentAll {
// the file has been sent fully // the file has been sent fully
fileIDBuff := new(bytes.Buffer) fileIDBuff := new(bytes.Buffer)
err = binary.Write(fileIDBuff, binary.BigEndian, file.ID) err = binary.Write(fileIDBuff, binary.BigEndian, file.ID)
if err != nil { if err != nil {
node.Mutex.Lock() panic(err)
node.State.Stopped = true
node.Mutex.Unlock()
} }
protocol.SendPacket(node.Net.Conn, protocol.Packet{ endFilePacket := protocol.Packet{
Header: protocol.HeaderEndfile, Header: protocol.HeaderEndfile,
Body: fileIDBuff.Bytes(), 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.State.Stopped = true
node.Mutex.Unlock()
} else { } else {
node.Mutex.Lock()
node.State.Stopped = true node.State.Stopped = true
node.Mutex.Unlock()
fmt.Printf("An error occured when sending a piece of \"%s\": %s\n", file.Name, err) fmt.Printf("An error occured when sending a piece of \"%s\": %s\n", file.Name, err)
panic(err) panic(err)
} }
} }
node.TransferInfo.Ready = false
} }
} }
@ -257,14 +274,8 @@ func (node *Node) Start() {
// mainloop // mainloop
for { for {
node.Mutex.Lock() if node.State.Stopped {
stopped := node.State.Stopped
node.Mutex.Unlock()
if stopped {
node.Mutex.Lock()
node.disconnect() node.disconnect()
node.Mutex.Unlock()
break break
} }
@ -272,8 +283,15 @@ func (node *Node) Start() {
if !ok { if !ok {
break break
} }
if node.Net.EncryptionKey != nil {
err = incomingPacket.DecryptBody(node.Net.EncryptionKey)
if err != nil {
panic(err)
}
}
switch incomingPacket.Header { switch incomingPacket.Header {
case protocol.HeaderFile: case protocol.HeaderFile:
go func() { go func() {
file, err := decodeFilePacket(incomingPacket) file, err := decodeFilePacket(incomingPacket)
@ -311,11 +329,27 @@ func (node *Node) Start() {
file.Path = fullFilePath file.Path = fullFilePath
file.Open() file.Open()
node.Mutex.Lock()
node.TransferInfo.AcceptedFiles = append(node.TransferInfo.AcceptedFiles, file) 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{ err = protocol.SendPacket(node.Net.Conn, protocol.Packet{
Header: protocol.HeaderReady, Header: protocol.HeaderReady,
}) })
@ -323,25 +357,26 @@ func (node *Node) Start() {
panic(err) panic(err)
} }
// send aceptance packet
protocol.SendPacket(node.Net.Conn, protocol.Packet{
Header: protocol.HeaderAccept,
Body: responsePacketFileIDBuffer.Bytes(),
})
} else { } else {
// no // no
err = protocol.SendPacket(node.Net.Conn, protocol.Packet{ rejectionPacket := protocol.Packet{
Header: protocol.HeaderReject, Header: protocol.HeaderReject,
Body: responsePacketFileIDBuffer.Bytes(), 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 { if err != nil {
panic(err) panic(err)
} }
node.Mutex.Lock()
node.State.Stopped = true node.State.Stopped = true
node.Mutex.Unlock()
} }
}() }()
@ -354,7 +389,6 @@ func (node *Node) Start() {
panic(err) panic(err)
} }
node.Mutex.Lock()
for _, acceptedFile := range node.TransferInfo.AcceptedFiles { for _, acceptedFile := range node.TransferInfo.AcceptedFiles {
if acceptedFile.ID == fileID { if acceptedFile.ID == fileID {
// accepted // accepted
@ -368,7 +402,6 @@ func (node *Node) Start() {
} }
} }
} }
node.Mutex.Unlock()
err = protocol.SendPacket(node.Net.Conn, protocol.Packet{ err = protocol.SendPacket(node.Net.Conn, protocol.Packet{
Header: protocol.HeaderReady, Header: protocol.HeaderReady,
@ -385,7 +418,6 @@ func (node *Node) Start() {
panic(err) panic(err)
} }
node.Mutex.Lock()
for index, acceptedFile := range node.TransferInfo.AcceptedFiles { for index, acceptedFile := range node.TransferInfo.AcceptedFiles {
if acceptedFile.ID == fileID { if acceptedFile.ID == fileID {
// accepted // accepted
@ -414,14 +446,23 @@ func (node *Node) Start() {
} }
node.State.Stopped = true 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: case protocol.HeaderDisconnecting:
node.Mutex.Lock()
node.State.Stopped = true 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" "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 { func receivePackets(connection net.Conn, packetPipe chan *protocol.Packet) error {
for { for {
if connection == nil { 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) { func decodeFilePacket(filePacket *protocol.Packet) (*fsys.File, error) {
// FILE~(idInBinary)(filenameLengthInBinary)(filename)(filesize)(checksumLengthInBinary)checksum // FILE~(idInBinary)(filenameLengthInBinary)(filename)(filesize)(checksumLengthInBinary)checksum

31
src/node/transfer.go

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

4
src/protocol/headers.go

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

33
src/protocol/packet.go

@ -59,7 +59,7 @@ func BytesToPacket(packetbytes []byte) (*Packet, error) {
}, nil }, 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 // Converts given packet struct into ready-to-transfer bytes, constructed by following the protocol
func (packet *Packet) ToBytes() ([]byte, error) { func (packet *Packet) ToBytes() ([]byte, error) {
@ -86,14 +86,15 @@ func (packet *Packet) ToBytes() ([]byte, error) {
return packetBuffer.Bytes(), nil 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 // ALL packets MUST be sent by this method
func SendPacket(connection net.Conn, packet Packet) error { func SendPacket(connection net.Conn, packet Packet) error {
packetBytes, err := packet.ToBytes() packetBytes, err := packet.ToBytes()
if err != nil { if err != nil {
return err 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)) // write the result (ie: (packetsize)(header)~(bodybytes))
connection.Write(packetBytes) connection.Write(packetBytes)
@ -113,6 +114,22 @@ func (packet *Packet) EncryptBody(key []byte) error {
return nil 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. // Reads a packet from given connection, returns its bytes.
// ASSUMING THAT THE PACKETS ARE SENT BY `SendPacket` function !!!! // ASSUMING THAT THE PACKETS ARE SENT BY `SendPacket` function !!!!
func ReadFromConn(connection net.Conn) ([]byte, error) { func ReadFromConn(connection net.Conn) ([]byte, error) {
@ -143,15 +160,7 @@ func ReadFromConn(connection net.Conn) ([]byte, error) {
packetBuffer.Write(buff[:read]) packetBuffer.Write(buff[:read])
} }
// read the rest of the packet // fmt.Printf("[RECV] read from connection: %s; length: %d\n", packetBuffer.Bytes()[:30], packetBuffer.Len())
// 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))
return packetBuffer.Bytes(), nil return packetBuffer.Bytes(), nil
} }

Loading…
Cancel
Save