add some more things
This commit is contained in:
parent
2fd486a6e4
commit
28cb7ecc43
|
@ -2,4 +2,5 @@
|
||||||
|
|
||||||
_A proxy to encrypt the Traccar Freematics protocol._
|
_A proxy to encrypt the Traccar Freematics protocol._
|
||||||
|
|
||||||
|
Inspired by previous work:
|
||||||
https://github.com/rfhigler/Freematics/commit/25cf781ca9fecc3e3082348ce9d28e4d69ff7764
|
https://github.com/rfhigler/Freematics/commit/25cf781ca9fecc3e3082348ce9d28e4d69ff7764
|
||||||
|
|
|
@ -17,8 +17,9 @@ func Decrypt(key, ciphertextMsg []byte) ([]byte, error) {
|
||||||
return nil, errors.New("ciphertext too short")
|
return nil, errors.New("ciphertext too short")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split nonce and ciphertext.
|
// Split the message apart.
|
||||||
nonce, ciphertext, tag := ciphertextMsg[:nonceSize], ciphertextMsg[nonceSize:len(ciphertextMsg)-tagSize], ciphertextMsg[len(ciphertextMsg)-tagSize:]
|
// The order is nonce, ciphertext, and tag. The last two aren't used.
|
||||||
|
nonce, _, _ := ciphertextMsg[:nonceSize], ciphertextMsg[nonceSize:len(ciphertextMsg)-tagSize], ciphertextMsg[len(ciphertextMsg)-tagSize:]
|
||||||
|
|
||||||
return aead.Open(nil, nonce, append(ciphertext, tag...), nil)
|
return aead.Open(nil, nonce, ciphertextMsg[nonceSize:], nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package encryption
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Encrypt(key, plaintextMsg []byte) ([]byte, error) {
|
||||||
|
aead, err := chacha20poly1305.New(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a new nonce for this encryption.
|
||||||
|
nonce := make([]byte, aead.NonceSize())
|
||||||
|
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt the message and append the nonce and the ciphertext.
|
||||||
|
ciphertext := aead.Seal(nonce, nonce, plaintextMsg, nil)
|
||||||
|
return ciphertext, nil
|
||||||
|
}
|
|
@ -73,43 +73,91 @@ func main() {
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
// Address to forward the decrypted messages
|
|
||||||
forwardAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", dest.Address, dest.Port))
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatalln("Error resolving forward address:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
forwardConn, err := net.DialUDP("udp", nil, forwardAddr)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatalln("Error dialing to forward address:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer forwardConn.Close()
|
|
||||||
|
|
||||||
logger.Infof("Listening on 0.0.0.0:%s\n", port)
|
logger.Infof("Listening on 0.0.0.0:%s\n", port)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
buf := make([]byte, 1500) // 1500 is the standard internet MTU
|
buf := make([]byte, 1500) // 1500 is the standard internet MTU.
|
||||||
n, addr, err := conn.ReadFromUDP(buf)
|
n, addr, err := conn.ReadFromUDP(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatalf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf("Error reading from UDP: %s", err)))
|
logger.Fatalf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf("Error reading from UDP: %s", err)))
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward the decrypted message
|
// Handle the message.
|
||||||
go func(addr *net.UDPAddr, buf []byte, n int) {
|
go func(addr *net.UDPAddr, buf []byte, n int) {
|
||||||
plaintext, err := encryption.Decrypt(key, buf[:n]) // Use only the part of the buffer that has data
|
// Do the decryption.
|
||||||
|
var plaintext []byte
|
||||||
|
if len(buf[:n]) > 0 {
|
||||||
|
plaintext, err = encryption.Decrypt(key, buf[:n]) // Use only the part of the buffer that has data.
|
||||||
|
if err != nil {
|
||||||
|
rawHex := hex.EncodeToString(buf[:n])
|
||||||
|
logger.Warnf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf(`Error decrypting message: %s. Length: %d, Raw: "%s"`, err, len(rawHex), rawHex)))
|
||||||
|
// Forward the raw message to the backend without bothering with decryption.
|
||||||
|
plaintext = buf[:n]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
plaintext = buf[:n]
|
||||||
|
}
|
||||||
|
|
||||||
|
forwardAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", dest.Address, dest.Port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf("Error decrypting message: %s", err)))
|
logger.Fatalln("Error resolving forward address:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a new UDP address for listening to the backend server's response.
|
||||||
|
listenAddr, err := net.ResolveUDPAddr("udp", ":0") // Let the OS pick a free port.
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalln("Error resolving listen address:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new UDP listener for the backend server's response.
|
||||||
|
listenConn, err := net.ListenUDP("udp", listenAddr)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalln("Error listening for backend response:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer listenConn.Close()
|
||||||
|
|
||||||
|
// Dial the backend server without binding a local address.
|
||||||
|
forwardConn, err := net.DialUDP("udp", nil, forwardAddr)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalln("Error dialing to forward address:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer forwardConn.Close()
|
||||||
|
|
||||||
|
// Forward the plaintext to the backend.
|
||||||
_, err = forwardConn.Write(plaintext)
|
_, err = forwardConn.Write(plaintext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf("Error forwarding message: %s", err)))
|
logger.Errorf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf("Error forwarding message: %s", err)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read the response from the backend.
|
||||||
|
backendResponse := make([]byte, 1500)
|
||||||
|
n, err = forwardConn.Read(backendResponse)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf("Error reading response from backend server: %s", err)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(backendResponse[:]))
|
||||||
|
|
||||||
|
// Encrypt the backend's response.
|
||||||
|
encryptedBackendResponse, err := encryption.Encrypt(key, backendResponse[:n])
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf("Error encrypting response: %s", err)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward the encrypted backend response to the client.
|
||||||
|
_, err = conn.WriteToUDP(encryptedBackendResponse, addr)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf("Error forwarding response to client: %s", err)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
logger.Infof(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, string(plaintext)))
|
logger.Infof(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, string(plaintext)))
|
||||||
}(addr, buf, n)
|
}(addr, buf, n)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
message = ('Hello, Server! ' + str(time.time())).encode()
|
message = ('Hello, Server! ' + str(time.time())).encode()
|
||||||
|
|
||||||
# The key and nonce
|
# The key and nonce
|
||||||
key = bytes.fromhex('example123')
|
key = bytes.fromhex('d38a3b96a26d0b1139bd30c174884f5dbc8eaaf492493725633ecebfa4ab19e9')
|
||||||
|
|
||||||
# Encrypt the message
|
# Encrypt the message
|
||||||
cipher = ChaCha20_Poly1305.new(key=key)
|
cipher = ChaCha20_Poly1305.new(key=key)
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import socket
|
||||||
|
import binascii
|
||||||
|
|
||||||
|
from Crypto.Cipher import ChaCha20_Poly1305
|
||||||
|
|
||||||
|
# Send an initalization message and decrypt the response.
|
||||||
|
# Use this key: d38a3b96a26d0b1139bd30c174884f5dbc8eaaf492493725633ecebfa4ab19e9
|
||||||
|
|
||||||
|
# The server's address and port
|
||||||
|
server_address = ('localhost', 5171)
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
|
||||||
|
# Convert hex string to bytes
|
||||||
|
ciphertext = binascii.unhexlify('40a7a1ef284e36e65cdb87abdb9aaea7ba4df5ae527b7311ba79a7d7f73729268d5b136c0c701fe366d775315f33e9ef893214fbf26a6ec281c8eadf46663b9d90')
|
||||||
|
|
||||||
|
# Send the encrypted message to the server
|
||||||
|
sock.sendto(ciphertext, server_address)
|
||||||
|
|
||||||
|
# Receive the response from the server
|
||||||
|
response, server = sock.recvfrom(4096)
|
||||||
|
|
||||||
|
# Decrypt that response
|
||||||
|
key = bytes.fromhex('d38a3b96a26d0b1139bd30c174884f5dbc8eaaf492493725633ecebfa4ab19e9')
|
||||||
|
# ChaCha20_Poly1305 nonce size is 12 bytes and tag size is 16 bytes
|
||||||
|
nonce = response[:12]
|
||||||
|
ciphertext_and_tag = response[12:]
|
||||||
|
ciphertext = ciphertext_and_tag[:-16]
|
||||||
|
tag = ciphertext_and_tag[-16:]
|
||||||
|
|
||||||
|
cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
|
||||||
|
plaintext = cipher.decrypt_and_verify(ciphertext, tag)
|
||||||
|
|
||||||
|
print("Decrypted message: ", plaintext)
|
||||||
|
|
||||||
|
sock.close()
|
Loading…
Reference in New Issue