graph TD
A["Password (raw UTF-8, max 51 bytes)"] --> B["SHA-1(password)"]
B -->|"20-byte startKey"| C["PBKDF2-HMAC-SHA1"]
S["Salt (16 bytes)"] --> C
I["Iterations (typically 1024)"] --> C
C -->|"20 bytes, truncated to 16"| D["Blowfish Key Schedule"]
IV["IV (8 bytes)"] --> E["Blowfish-CFB64 Decrypt"]
D --> E
CT["Ciphertext (8..1024 bytes)"] --> E
E -->|"plaintext"| F["SHA-1(plaintext)"]
F -->|"first 128 bits compared"| G["Stored Checksum (20 bytes)"]
Pipeline detail:
startKey = SHA-1(password) — 20 bytes; this is the "Bogus SHA-1 in StarOffice code" path, where the password is hashed before use as the PBKDF2 key (not a standard PKCS#5 pattern).
derivedKey = PBKDF2(PRF=HMAC-SHA1, password=startKey, salt=salt16, c=iterations, dkLen=16) — single PBKDF2 block (dkLen 16 <= hLen 20), counter INT(1) appended to salt for U_1, output truncated from 20 to 16 bytes.
Blowfish key schedule with the 16-byte derived key (128-bit key).
Blowfish-CFB64 decryption (full 8-byte feedback) with the 8-byte IV.
SHA-1(plaintext) verification: the first 128 bits (4 x u32) of the resulting hash are compared against the stored 20-byte checksum. The fifth word is stored (DGST_SIZE_4_5) but only the first four words drive the GPU comparison (r0..r3 in m18600_comp).
pw_max: 51 — hardcoded in module_pw_max() with the comment "Bogus SHA-1 in StarOffice code". StarOffice/OpenOffice's implementation pre-hashes the password through SHA-1 before feeding to PBKDF2; the 51-byte limit corresponds to a single SHA-1 compression block (64 bytes minus padding overhead: 55 bytes for the last block with length, but StarOffice used 51). This means passwords longer than 51 bytes are silently rejected by hashcat regardless of attack mode.
pw_min: MODULE_DEFAULT (0)
Salt type:SALT_TYPE_EMBEDDED — all cryptographic parameters are parsed from the hash line itself
salt_iter:iterations - 1 (the _init kernel performs the first PBKDF2 HMAC-SHA1 round; _loop handles the remaining iterations)
Kernel architecture: Pure kernel only (m18600-pure.cl), no optimized variant. Uses SIMD vectorization (NEW_SIMD_CODE).
Comparison width: 128 bits (4 x u32). The _comp kernel extracts r0..r3 from sha1_ctx.h[0..3]; DGST_SIZE_4_5 stores all 5 words but DGST_POS0..3 = 0..3 drives comparison using only the first four. Fifth SHA-1 word is never compared on the GPU.
Cipher: Blowfish-CFB64 with full 8-byte feedback, using inc_cipher_blowfish.cl. Key is scheduled from the 16-byte truncated PBKDF2 output (128-bit Blowfish key). Decryption uses the S-box arrays in local memory, with dynamic local memory sizing via JIT build options to maximize GPU occupancy.
JIT build options: Extensive shared memory management — the Blowfish S-boxes (4 x 256 x 4 bytes = 4096 bytes per thread) are allocated in local/shared memory, with FIXED_LOCAL_SIZE_COMP computed from device_local_mem_size / 4096 or kernel_dynamic_local_mem_size_memset / 4096 for CUDA
AES-256 ODF 1.2:cipher_type=1 is rejected; use mode 18400 instead
SHA-256 checksum:checksum_type=1 is rejected; use mode 18400 instead
Non-standard key sizes: Only key_size=16 accepted; 24/32-byte keys rejected
Non-standard IV/salt lengths: Only iv_len=8 and salt_len=16 accepted
Iteration counts < 1000 or > 999999: The token parser enforces 4–6 digit length, so 1–999 and 1000000+ are rejected at the tokenizer level. Value 0 is separately rejected via if (iterations < 1) return PARSER_SALT_ITERATION.
Passwords > 51 bytes: Silently truncated/rejected by module_pw_max(). This is a StarOffice implementation constraint where the pre-SHA-1 step was buggy.
Fifth checksum word: The comparison only checks 128 bits of the 160-bit SHA-1. Theoretically a 2^-128 false positive rate; no practical impact.
OpenOffice "buggy SHA-1" checksum variant: JtR's implementation matches both standard and buggy SHA-1 checksums; hashcat computes only the standard SHA-1. This means some very old StarOffice files with the buggy checksum may not verify correctly even with the right password.