Add RBR850 support#15
Open
chrisbraddock wants to merge 1 commit into
Open
Conversation
The RBR850 (firmware V7.2.x) uses a different scheme than the existing
musl/uclibc XOR cipher, reversed from FUN_001392ec in /usr/sbin/httpd.
The .cfg file is always exactly 131096 bytes: a 24-byte big-endian
header followed by a 131072-byte body. The whole buffer (header
included) is DES-ECB encrypted in 8-byte blocks with a different key
per block, derived from a rolling 32-bit counter seeded at 0x72677456
("Ntgr" LE + 8) and the string "NtgrBak\0", incremented by 8 per block.
The header carries a 16-bit IP-style checksum self-validating to 0xffff
over the plaintext, a HW-version-derived magic, and a version field.
Since the header is ciphertext we can't peek at a plaintext magic to
dispatch. Decrypt routes to the new path by file size.
The decrypted body has a 32-byte firmware-internal prefix and trailing
0xff NAND-erase padding. The prefix is stashed in a new optional
Metadata.RawPrefix field so re-encrypted backups are byte-compatible
with the device; the suffix is reconstructed from the fixed file size.
Existing decrypted.json fixtures for other devices parse unchanged
since RawPrefix is json:",omitempty".
Also fixes a latent bug in ToJSON: bytes.Split on '=' errored on any
value containing '='. Switch to SplitN(..., 2) so the key is the prefix
up to the first '=' and the rest is the value. Closes Fysac#10.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Confirmed working on RBR840 (firmware V7.2.x). File is the same 131096-byte DES-ECB format — decrypted cleanly to 1700+ config entries including DHCP reservations, port forwarding rules, and DDNS credentials. The dispatch-by-file-size approach handles the RBR840 without any additional changes needed. |
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds support for the NETGEAR Orbi RBR850 (firmware V7.2.x). The RBR850 uses a different cipher than the existing musl/uclibc XOR scheme, reversed from
FUN_001392ecin/usr/sbin/httpd:0x72677456("Ntgr"LE + 8) and the constant"NtgrBak\0", incremented by 8 per blockDecryptdispatches by file size rather than plaintext magic0xffffover the plaintextCloses #10.
Changes
cfg/rbr850.go(new): cipher, key derivation, header codec, checksum, decrypt/encrypt helpers. Usescrypto/desfrom the stdlib; no new module deps.cfg/cfg.go: newRngRBR850sentinel (follows the looseRngconvention fromoverrides.go); file-size gate inDecrypt; cipher branch inEncrypt.Metadata.RawPrefix []byte(new,json:",omitempty"): preserves the 32-byte firmware-internal prefix that sits at the start of the decrypted RBR850 body so re-encrypted backups round-trip cleanly. Zero-impact on other devices (omitempty).ToJSONbugfix: switchbytes.Spliton=→bytes.SplitN(..., 2). The old behavior errored on any config value containing=(which exists in the wild — e.g., opaque token strings). Single-line change, benefits all devices.cfg/rbr850_test.go(new): known-answer tests for block-key derivation, header codec round-trip, checksum self-validation, full encrypt/decrypt round-trip, and dispatch-by-size.cfg/testdata/RBR850/(new): synthesized fixture (plausible NVRAM-shaped keys with fake values, no real-device secrets) following the existingRBR50/RBR760layout.cfg_test.go:RBR850added to thedevicesslice;TestChecksumskips RBR850 since it splices plaintextHeader.Bytes()into the ciphertext — incompatible with an encrypted-header cipher.README.md: new "RBR850" subsection under "Encryption Scheme" documenting the DES-rolling-key scheme and theraw_prefixmetadata field.Test plan
go test ./...— all existing devices (RBR50, RBR760) plus RBR850 passgo vet ./...andgofmt -l .cleanTestEncryptDecrypt) exercises RBR850 via the shareddevicestabledecrypt → encrypt → decryptproduces byte-identical JSON outputNotes
.cfgfiles are ~99.99% byte-identical to the device's original (3 plaintext bytes differ: 2 in the header checksum because the 3rd byte at thek=v/0xff-fill boundary shifts by 1 NUL — the device uses its own padding convention rather than the existingchunkSize-aligned one). The JSON, the config map, and the cleaned body bytes all round-trip losslessly. Device should accept the re-encrypted file since the 1-byte shift is in the NAND-erase padding region.FUN_00138ee4) isn't reversed; users re-encrypting should keepreal_magicfrom the decrypted JSON unchanged.🤖 Generated with Claude Code