Assume PSK AQ== always. Keep encrypted payload if it fails to decrypt. Code to decrypt a message:
require"base64"require"meshtastic"require"openssl"# === Inputs from your packet ===cipher_b64="Q1R7tgI5yXzMXu/3"psk_b64="Nmh7EooP2Tsc+7pvPwXLcEDDuYhk+fBo2GLnbA1Y1sg="packet_id=3_915_687_257from_id="!9e95cf60"# === Decode key and ciphertext ===key=Base64.decode64(psk_b64)# 32 bytes -> AES-256ciphertext=Base64.decode64(cipher_b64)# === Derive numeric node id from Meshtastic-style string ===hex_str=from_id.sub(/^!/,"")# "9e95cf60"from_node=hex_str.to_i(16)# 0x9e95cf60# === Build nonce exactly like Meshtastic CryptoEngine ===# Little-endian 64-bit packet ID + little-endian 32-bit node ID + 4 zero bytesnonce=[packet_id].pack("Q<")# uint64, little-endiannonce+=[from_node].pack("L<")# uint32, little-endiannonce+="\x00"*4# extraNonce == 0 for PSK channel msgsraise"Nonce must be 16 bytes"unlessnonce.bytesize==16raise"Key must be 32 bytes"unlesskey.bytesize==32# === AES-256-CTR decrypt ===cipher=OpenSSL::Cipher.new("aes-256-ctr")cipher.decryptcipher.key=keycipher.iv=nonceplaintext=cipher.update(ciphertext)+cipher.final# At this point `plaintext` is the raw Meshtastic protobuf payloadplaintext=plaintext.bytes.pack("C*")data=Meshtastic::Data.decode(plaintext)msg=data.payload.dup.force_encoding("UTF-8")msg==="Nabend"
Assume PSK `AQ==` always. Keep encrypted payload if it fails to decrypt. Code to decrypt a message:
```ruby
require "base64"
require "meshtastic"
require "openssl"
# === Inputs from your packet ===
cipher_b64 = "Q1R7tgI5yXzMXu/3"
psk_b64 = "Nmh7EooP2Tsc+7pvPwXLcEDDuYhk+fBo2GLnbA1Y1sg="
packet_id = 3_915_687_257
from_id = "!9e95cf60"
# === Decode key and ciphertext ===
key = Base64.decode64(psk_b64) # 32 bytes -> AES-256
ciphertext = Base64.decode64(cipher_b64)
# === Derive numeric node id from Meshtastic-style string ===
hex_str = from_id.sub(/^!/, "") # "9e95cf60"
from_node = hex_str.to_i(16) # 0x9e95cf60
# === Build nonce exactly like Meshtastic CryptoEngine ===
# Little-endian 64-bit packet ID + little-endian 32-bit node ID + 4 zero bytes
nonce = [packet_id].pack("Q<") # uint64, little-endian
nonce += [from_node].pack("L<") # uint32, little-endian
nonce += "\x00" * 4 # extraNonce == 0 for PSK channel msgs
raise "Nonce must be 16 bytes" unless nonce.bytesize == 16
raise "Key must be 32 bytes" unless key.bytesize == 32
# === AES-256-CTR decrypt ===
cipher = OpenSSL::Cipher.new("aes-256-ctr")
cipher.decrypt
cipher.key = key
cipher.iv = nonce
plaintext = cipher.update(ciphertext) + cipher.final
# At this point `plaintext` is the raw Meshtastic protobuf payload
plaintext = plaintext.bytes.pack("C*")
data = Meshtastic::Data.decode(plaintext)
msg = data.payload.dup.force_encoding("UTF-8")
msg === "Nabend"
```
<!-- github-sync-id:3664364144 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Assume PSK
AQ==always. Keep encrypted payload if it fails to decrypt. Code to decrypt a message: