Synology PAT/SPK Encrypted Archive Decryption
tip
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Overview
Several Synology devices (DSM/BSM NAS, BeeStation, …) distribute their firmware and application packages in encrypted PAT / SPK archives. Those archives can be decrypted offline with nothing but the public download files thanks to hard-coded keys embedded inside the official extraction libraries.
This page documents, step-by-step, how the encrypted format works and how to fully recover the clear-text TAR that sits inside each package. The procedure is based on Synacktiv research performed during Pwn2Own Ireland 2024 and implemented in the open-source tool synodecrypt
.
⚠️ The format is exactly the same for both
*.pat
(system update) and*.spk
(application) archives – they only differ in the pair of hard-coded keys that are selected.
1. Grab the archive
The firmware/application update can normally be downloaded from Synology’s public portal:
$ wget https://archive.synology.com/download/Os/BSM/BSM_BST150-4T_65374.pat
2. Dump the PAT structure (optional)
*.pat
images are themselves a cpio bundle that embeds several files (boot loader, kernel, rootfs, packages…). The free utility patology
is convenient to inspect that wrapper:
$ python3 patology.py --dump -i BSM_BST150-4T_65374.pat
[…]
$ ls
DiskCompatibilityDB.tar hda1.tgz rd.bin packages/ …
For *.spk
you can directly jump to step 3.
3. Extract the Synology extraction libraries
The real decryption logic lives in:
/usr/syno/sbin/synoarchive
→ main CLI wrapper/usr/lib/libsynopkg.so.1
→ calls the wrapper from DSM UIlibsynocodesign.so
→ contains the cryptographic implementation
Both binaries are present in the system rootfs (hda1.tgz
) and in the compressed init-rd (rd.bin
). If you only have the PAT you can get them this way:
# rd.bin is LZMA-compressed CPIO
$ lzcat rd.bin | cpio -id 2>/dev/null
$ file usr/lib/libsynocodesign.so
usr/lib/libsynocodesign.so: ELF 64-bit LSB shared object, ARM aarch64, …
4. Recover the hard-coded keys (get_keys
)
Inside libsynocodesign.so
the function get_keys(int keytype)
simply returns two 128-bit global variables for the requested archive family:
case 0: // PAT (system)
case 10:
case 11:
signature_key = qword_23A40;
master_key = qword_23A68;
break;
case 3: // SPK (applications)
signature_key = qword_23AE0;
master_key = qword_23B08;
break;
- signature_key → Ed25519 public key used to verify the archive header.
- master_key → Root key used to derive the per-archive encryption key.
You only have to dump those two constants once for each DSM major version.
5. Header structure & signature verification
synoarchive_open()
→ support_format_synoarchive()
→ archive_read_support_format_synoarchive()
performs the following:
- Read magic (3 bytes)
0xBFBAAD
or0xADBEEF
. - Read little-endian 32-bit
header_len
. - Read
header_len
bytes + the next 0x40-byte Ed25519 signature. - Iterate over all embedded public keys until
crypto_sign_verify_detached()
succeeds. - Decode the header with MessagePack, yielding:
[
data: bytes,
entries: [ [size: int, sha256: bytes], … ],
archive_description: bytes,
serial_number: [bytes],
not_valid_before: int
]
entries
later allows libarchive to integrity-check each file as it is decrypted.
6. Derive the per-archive sub-key
From the data
blob contained in the MessagePack header:
subkey_id
= little-endianuint64
at offset 0x10ctx
= 7 bytes at offset 0x18
The 32-byte stream key is obtained with libsodium:
crypto_kdf_derive_from_key(kdf_subkey, 32, subkey_id, ctx, master_key);
7. Synology’s custom libarchive backend
Synology bundles a patched libarchive that registers a fake "tar" format whenever the magic is 0xADBEEF
:
register_format(
"tar", spk_bid, spk_options,
spk_read_header, spk_read_data, spk_read_data_skip,
NULL, spk_cleanup, NULL, NULL);
spk_read_header()
- Read 0x200 bytes
- nonce = buf[0:0x18]
- cipher = buf[0x18:0x18+0x193]
- crypto_secretstream_xchacha20poly1305_init_pull(state, nonce, kdf_subkey)
- crypto_secretstream_xchacha20poly1305_pull(state, tar_hdr, …, cipher, 0x193)
The decrypted tar_hdr
is a classical POSIX TAR header.
spk_read_data()
while (remaining > 0):
chunk_len = min(0x400000, remaining) + 0x11 # +tag
buf = archive_read_ahead(chunk_len)
crypto_secretstream_xchacha20poly1305_pull(state, out, …, buf, chunk_len)
remaining -= chunk_len - 0x11
Each 0x18-byte nonce is prepended to the encrypted chunk.
Once all entries are processed libarchive produces a perfectly valid .tar
that can be unpacked with any standard tool.
8. Decrypt everything with synodecrypt
$ python3 synodecrypt.py SynologyPhotos-rtd1619b-1.7.0-0794.spk
[+] found matching keys (SPK)
[+] header signature verified
[+] 104 entries
[+] archive successfully decrypted → SynologyPhotos-rtd1619b-1.7.0-0794.tar
$ tar xf SynologyPhotos-rtd1619b-1.7.0-0794.tar
synodecrypt
automatically detects PAT/SPK, loads the correct keys and applies the full chain described above.
9. Common pitfalls
- Do not swap
signature_key
andmaster_key
– they serve different purposes. - The nonce comes before the ciphertext for every block (header and data).
- The maximum encrypted chunk size is 0x400000 + 0x11 (libsodium tag).
- Archives created for one DSM generation may switch to different hard-coded keys in the next release.
10. Additional tooling
patology
– parse/dump PAT archives.synodecrypt
– decrypt PAT/SPK/others.libsodium
– reference implementation of XChaCha20-Poly1305 secretstream.msgpack
– header serialisation.
References
- Extraction of Synology encrypted archives – Synacktiv (Pwn2Own IE 2024)
- synodecrypt on GitHub
- patology on GitHub
tip
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.