blockedlog: BLOCKEDLOG_HMAC_KEY stored with old method is not decodable after upgrade to v24 - no UI recovery, new records silently not written
Author: aluquerivas-devCreated Sep 2, 2026Updated Sep 21, 2026
Title: blockedlog: BLOCKEDLOG_HMAC_KEY stored with old method is not decodable after upgrade to v24 — no UI recovery, new records silently not written
Summary
After upgrading to Dolibarr 24.0.0, every page of the Registros inmutables (Unalterable Log / BlockedLog) module fails with:
getClearHMACSecretKey Error: Failed to decode the crypted value of the parameter
BLOCKEDLOG_HMAC_KEY dolcrypt:AES-256-CTR:8bytehexiv:base64data using the obfuscation key.
A value was found in database but decoding failed. May be you modified the SIREN used to get
the obfuscation key from ping.dolibarr.org (or old config key $dolibarr_main_instance_unique_id).Environment (sanitized)
- Dolibarr 24.0.0 (upgrade from an older version).
- PHP 8.2+, MySQL/MariaDB, a non-French company (so no LNE/ALN, no
dolobfuscationmode). $dolibarr_main_dolcrypt_keyis not defined.$dolibarr_main_instance_unique_idis set.
What was observed
llx_constcontains exactly one row forBLOCKEDLOG_HMAC_KEY, value startingdolcrypt:AES-256-CTR:...(olddolcryptstorage method).- The
conf.phpwas compared before/after the upgrade:$dolibarr_main_instance_unique_idis identical in both; there is no$dolibarr_main_cookie_cryptkeyeither. - The stored ciphertext cannot be decrypted with the current
instance_unique_id(tried directly, and with md5/sha1/sha256 variants, with/without a "dolibarr" prefix — all return invalid bytes). So the ciphertext was produced with a different key than the onedolDecrypt()currently uses, or with a different method (older version). - The historical chain (a few thousand rows, all with
object_format = "V1") verifies 100% OK with the current code when re-checked withbuildKeyForSignature()+dol_hash(..., '5')(V1 does not use the HMAC key). So the chain itself is intact: only the stored HMAC key is unusable.
Impact
blockedlog/admin/blockedlog_list.phpand other module pages throw the error above (module admin area effectively dead).- No new immutable record can be written: all new rows are created in
object_format = "V2", andbuildFinalSignatureHash()throws when it cannot decode the key → the audit trail silently stopped right after the upgrade (no errors surfaced in normal business screens). - There is no UI recovery path:
modBlockedLog::init()only generates a new key when thellx_constvalue is empty; when the value exists but cannot be decoded,init()errors out and suggests manually deleting the row fromllx_const— a non-admin-equivalent action.
Workaround used (works, preserves the chain)
- Backup
llx_blockedlog. - Delete the
BLOCKEDLOG_HMAC_KEYrow fromllx_const. - Recreate it the official way:
'BLOCKEDLOGHMAC'.bin2hex(random_bytes(32))saved viasaveHMACSecretKey($key, 'dolcrypt')(encrypted with the currentinstance_unique_id). - Result:
getClearHMACSecretKey()decodes OK, list page works, new rows are signed again (V2) and the chain continues correctly from the last V1 signature (the integrity check page passes for the whole chain).
Suggestions for the maintainers
- Recovery path: when the stored
BLOCKEDLOG_HMAC_KEYcannot be decoded with the current algorithm, do not hard-fail: offer an explicit admin action "Reset HMAC key" (with a clear warning that the upcoming chain break makes previous records unverifiable), or auto-regenerate with a visible event message. - Better diagnostics: improve the error message to mention (a) the key derivation actually tried (
dolcrypt_keyvsinstance_unique_idvs oldcookie_cryptkey), (b) whether a backup/restore to another instance is suspected, (c) the exact SQL to recover (workaround above). - Upgrade path: during the upgrade, detect an undecodable
BLOCKEDLOG_HMAC_KEYand either regenerate it proactively (with a loud warning) or fail the upgrade with an explicit step, instead of leaving a partial state that silently stops writing records. - Key retention: consider storing the key as a list of alternative values (the decrypt code already loops over comma-separated keys), so a pending key change (hosting migration, SIREN change) does not brick the module.
Related upstream: PR #39067 "FIX BLOCKEDLOG_HMAC_KEY can not be the same by entity" (merged 2026-07-16) covers entity-side key handling, while this one is about decodability of the stored key after upgrade.
(All values above are sanitized; no customer data included.)
Source: Dolibarr/dolibarr