Skip to content

Instantly share code, notes, and snippets.

@andy0130tw
Created April 21, 2024 19:12
Show Gist options
  • Save andy0130tw/17776eb909d1b40439ece1a3a650194d to your computer and use it in GitHub Desktop.
Save andy0130tw/17776eb909d1b40439ece1a3a650194d to your computer and use it in GitHub Desktop.
Decrypt Meshtastic packets from MQTT
import * as crypto from 'node:crypto'
import { loadProtobufs } from './pbs.js'
const pbroot = await loadProtobufs()
const Data = pbroot.lookupType('meshtastic.Data')
// Usage: decryptPacket(
// Buffer.from('1PG7OiApB1nwvP+rz05pAQ==', 'base64'),
// {from, id, encrypted})
export function decryptPacket(psk, packet) {
const packetId = packet.id
const fromNodeId = packet.from
const ciphertext = packet.encrypted
// guard against overflows
if (typeof packetId !== 'number' ||
typeof fromNodeId !== 'number')
throw new TypeError('id/from should be in numbers')
const iv = new ArrayBuffer(16)
const ivView = new DataView(iv)
ivView.setUint32(0, packetId, true)
ivView.setUint32(8, fromNodeId, true)
const algo = psk.length === 32 ? 'aes-256-ctr' : 'aes-128-ctr'
const decipher = crypto.createDecipheriv(algo, psk, iv)
let plaintext = decipher.update(ciphertext)
plaintext = Buffer.concat([plaintext, decipher.final()])
try {
return Data.decode(plaintext)
} catch (err) { // i.e. input is incorrect
return null
}
}
import protobuf from 'protobufjs'
/** @type {protobuf.Root} */
let root
export async function loadProtobufs() {
if (root == null) {
let defaultResolve = protobuf.util.path.resolve
protobuf.Root.prototype.resolvePath = function(p, ip, an) {
return defaultResolve('protobufs/xxx', ip, an)
}
try {
root = await protobuf.load('meshtastic/mqtt.proto')
} finally {
protobuf.Root.prototype.resolvePath = defaultResolve
}
}
return root
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment