mirror of
https://github.com/LisherSong/ps5-web-file-manager.git
synced 2026-10-06 10:00:24 +02:00
7-Zip wraps the packed stream of a password protected archive in a 7zAES
coder (method 0x06F10701). The bundled LZMA SDK has no C implementation of
it, so add one to the folder chain:
* aes_props_layout() splits the property bytes into numCyclesPower, salt
and IV exactly as CDecoder::SetDecoderProperties2() does, and rejects a
block whose declared lengths do not match its size;
* aes_derive_key() runs the 7-Zip KDF: SHA-256 over
(salt || password_utf16le || counter_le64) repeated 1 << numCyclesPower
times, with the 0x3F power meaning "no derivation", the key being the
salt and password copied into 32 bytes;
* utf8_to_utf16le() converts the caller's password, since that is the
encoding 7-Zip hashes;
* the SZ_N_AES node decrypts one block at a time with Aes_SetKey_Dec() /
AesCbc_Init() / g_AesCbc_Decode(), keeping the trailing partial block in
the node so the declared (unpadded) unpack size is what gets delivered.
sz_chain_decode() gains a `password` argument, and sz_chain_needs_password()
lets a caller ask for one before it touches the filesystem. A folder that
needs a password and did not get one fails as SZ_CHAIN_ERR_PASSWORD with a
message naming 7zAES, rather than as a generic corrupt archive.
Because a wrong password decrypts to plausible looking rubbish, a failure
from a folder that carried a 7zAES coder gets "(a wrong password looks like
this)" appended, so the UI can offer a retry instead of calling the file
damaged.
numCyclesPower comes from the archive and drives 2^n SHA-256 passes, so it is
capped by the limits profile (max_aes_cycles, 2^24 for both the default and
the large profile).
An encrypted *header* (-mhe=on) is a different problem: the archive header is
encrypted with the same coder and has to be decrypted before any folder
exists. That stays out of scope and is reported as such.
tests/run-sevenz-tests.sh: aes leaves KNOWN_GAPS and passes; aeshe stays
there with the reason spelled out.