Last active
April 6, 2024 10:36
-
-
Save wheresalice/40ddd16e9757f923e896cd77fbf3a458 to your computer and use it in GitHub Desktop.
Decrypt meshtastic messages from mqtt in go, borrowing from https://github.com/pdxlocations/Meshtastic-MQTT-Connect/blob/main/meshtastic-mqtt-connect.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
pb "buf.build/gen/go/meshtastic/protobufs/protocolbuffers/go/meshtastic" | |
"crypto/aes" | |
"crypto/cipher" | |
"encoding/base64" | |
"encoding/binary" | |
"encoding/hex" | |
"fmt" | |
"github.com/charmbracelet/log" | |
"github.com/crypto-smoke/meshtastic-go/mqtt" | |
"google.golang.org/protobuf/proto" | |
"strings" | |
) | |
func main() { | |
client := mqtt.NewClient("tcp://mqtt.meshtastic.org:1883", "meshdev", "large4cats", "msh") | |
err := client.Connect() | |
if err != nil { | |
log.Fatal(err) | |
} | |
client.Handle("LongFast", channelHandler("LongFast")) | |
log.Info("Started") | |
select {} | |
} | |
func channelHandler(channel string) mqtt.HandlerFunc { | |
return func(m mqtt.Message) { | |
var env pb.ServiceEnvelope | |
err := proto.Unmarshal(m.Payload, &env) | |
if err != nil { | |
log.Fatal("failed unmarshalling to service envelope", "err", err, "payload", hex.EncodeToString(m.Payload)) | |
return | |
} | |
nonce := generateNonce(env.Packet.Id, env.Packet.From) | |
key, err := generateKey("1PG7OiApB1nwvP+rz05pAQ==") | |
if err != nil { | |
log.Fatal(err) | |
} | |
decodedMessage, err := decode(key, env.Packet.GetEncrypted(), nonce) | |
if err != nil { | |
log.Fatal(err) | |
} | |
//log.Println(decodedMessage.String()) | |
log.Info(processMessage(decodedMessage), "topic", m.Topic, "channel", channel, "portnum", decodedMessage.Portnum.String()) | |
} | |
} | |
func processMessage(message pb.Data) string { | |
if message.Portnum == pb.PortNum_NODEINFO_APP { | |
var user = pb.User{} | |
proto.Unmarshal(message.Payload, &user) | |
return user.String() | |
} | |
if message.Portnum == pb.PortNum_POSITION_APP { | |
var pos = pb.Position{} | |
proto.Unmarshal(message.Payload, &pos) | |
return pos.String() | |
} | |
if message.Portnum == pb.PortNum_TELEMETRY_APP { | |
var t = pb.Telemetry{} | |
proto.Unmarshal(message.Payload, &t) | |
return t.String() | |
} | |
if message.Portnum == pb.PortNum_NEIGHBORINFO_APP { | |
var n = pb.NeighborInfo{} | |
proto.Unmarshal(message.Payload, &n) | |
return n.String() | |
} | |
if message.Portnum == pb.PortNum_STORE_FORWARD_APP { | |
var s = pb.StoreAndForward{} | |
proto.Unmarshal(message.Payload, &s) | |
return s.String() | |
} | |
return fmt.Sprintf("unknown message type") | |
} | |
func generateKey(key string) ([]byte, error) { | |
// Pad the key with '=' characters to ensure it's a valid base64 string | |
padding := (4 - len(key)%4) % 4 | |
paddedKey := key + strings.Repeat("=", padding) | |
// Replace '-' with '+' and '_' with '/' | |
replacedKey := strings.ReplaceAll(paddedKey, "-", "+") | |
replacedKey = strings.ReplaceAll(replacedKey, "_", "/") | |
// Decode the base64-encoded key | |
return base64.StdEncoding.DecodeString(replacedKey) | |
} | |
func generateNonce(packetId uint32, node uint32) []byte { | |
packetNonce := make([]byte, 8) | |
nodeNonce := make([]byte, 8) | |
binary.LittleEndian.PutUint32(packetNonce, packetId) | |
binary.LittleEndian.PutUint32(nodeNonce, node) | |
return append(packetNonce, nodeNonce...) | |
} | |
func decode(encryptionKey []byte, encryptedData []byte, nonce []byte) (pb.Data, error) { | |
var message pb.Data | |
ciphertext := encryptedData | |
block, err := aes.NewCipher(encryptionKey) | |
if err != nil { | |
return message, err | |
} | |
stream := cipher.NewCTR(block, nonce) | |
plaintext := make([]byte, len(ciphertext)) | |
stream.XORKeyStream(plaintext, ciphertext) | |
err = proto.Unmarshal(plaintext, &message) | |
return message, err | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment