Skip to content

CLI tool to change the network key of PCAP files#53

Merged
puddly merged 2 commits into
devfrom
puddly/rekey-tool
Jul 24, 2026
Merged

CLI tool to change the network key of PCAP files#53
puddly merged 2 commits into
devfrom
puddly/rekey-tool

Conversation

@puddly

@puddly puddly commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

This is a small utility to make it easier to publicly share PCAP files captured from production networks. It decrypts traffic with a provided network key and then re-encrypts that same traffic with a different key. It also rewrites APS "Transport-Key" commands that directly emit the old key. For ease of use, the second key is injected as a fake "Transport Key" command at the top of the capture so that Wireshark automatically uses it.

Note: this tool won't anonymize packet captures. IEEE addresses, NWK addresses, device-specific unique link key traffic, extended PAN IDs, nearby 802.15.4 network traffic (including non-Zigbee networks), etc. will still be present.

cargo run -p ziggurat-tools --bin pcap-rekey \
    capture.pcap rekeyed.pcap --old-key AA:BB:... --new-key 11:22:...

Copilot AI review requested due to automatic review settings July 23, 2026 19:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new standalone CLI utility (pcap-rekey) under the new ziggurat-tools crate to help sanitize Zigbee packet captures for sharing by re-encrypting NWK-secured traffic under a replacement network key and rewriting APS Transport-Key commands that leak the old key. The tool also optionally injects a synthetic Transport-Key command so Wireshark can learn the new key automatically.

Changes:

  • Introduce pcap-rekey CLI that reads/writes pcapng and rekeys NWK-secured frames while leaving foreign networks untouched.
  • Add new ziggurat-tools crate definition and dependencies (clap/anyhow/pcap-file).
  • Update Cargo.lock for the new crate/dependencies.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 5 comments.

File Description
crates/ziggurat-tools/src/bin/pcap_rekey.rs Implements the pcapng rekeying CLI, including NWK decrypt/re-encrypt, APS Transport-Key rewrite, and optional key injection for Wireshark.
crates/ziggurat-tools/Cargo.toml Defines the new ziggurat-tools crate and registers the pcap-rekey binary with required dependencies.
Cargo.lock Adds lockfile entries for ziggurat-tools and new transitive dependencies (e.g., pcap-file).
Comments suppressed due to low confidence (1)

crates/ziggurat-tools/src/bin/pcap_rekey.rs:56

  • Similarly, --new-key help text should state it expects hex, since parse_key rejects non-hex input.
    /// The network key to re-encrypt the capture with.
    #[arg(long, value_parser = parse_key)]
    new_key: Key,

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +91 to +93
fn main() -> Result<()> {
let args = Args::parse();

Comment on lines +195 to +205
Block::EnhancedPacket(EnhancedPacketBlock {
interface_id: original.interface_id,
timestamp: original.timestamp,
original_len: new_data.len() as u32,
data: Cow::Owned(new_data),
options: original
.options
.iter()
.map(|option| option.clone().into_owned())
.collect(),
})
Comment on lines +333 to +339
// Unsecured join frame: rewrite a cleartext Transport-Key command if it carries the key.
if encrypted.nwk_header.frame_control.frame_type != NwkFrameType::Data {
return None;
}
let new_aps =
rewrite_transport_key(&encrypted.ciphertext, old_key, new_key, aps_transport_key)?;
*aps_rewrites += 1;
Comment on lines +50 to +52
/// The current network key protecting the capture.
#[arg(long, value_parser = parse_key)]
old_key: Key,
Comment on lines +241 to +266
fn rekey_packet(
link_type: LinkType,
data: &[u8],
old_key: &Key,
new_key: &Key,
aps_transport_key: &Key,
aps_rewrites: &mut u64,
) -> Option<Vec<u8>> {
match link_type {
LinkType::Raw => rekey_phy(data, old_key, new_key, aps_transport_key, aps_rewrites),
LinkType::Tap => {
let header_len = tap_header_len(data)?;
let new_phy = rekey_phy(
&data[header_len..],
old_key,
new_key,
aps_transport_key,
aps_rewrites,
)?;

let mut out = data[..header_len].to_vec();
out.extend(new_phy);
Some(out)
}
}
}
@MattWestb

Copy link
Copy Markdown

I think its not deleting / masking the network key then joining new or old devices ??
But i think its great not need posting network keys for production networks !!!

GWDP !!!!

@puddly

puddly commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

I think its not deleting / masking the network key then joining new or old devices ??

It replaces the network key within the APS Transport Key command so joining should be covered too!

@puddly
puddly merged commit 2b7836b into dev Jul 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants