{"record":{"id":"185f2c4f5438326f","repo":"siyuan-note/siyuan","slug":"decrypt-box-s-failed-incorrect-key-or-corrupte","errorCode":null,"errorMessage":"decrypt box [%s] failed: incorrect key or corrupted data","messagePattern":"decrypt box \\[(.+?)\\] failed: incorrect key or corrupted data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"kernel/model/crypto.go","lineNumber":1355,"sourceCode":"\t\tdek, err = decryptWrappedDEKWithHistory(boxID, backup, kek, nc)\n\t\tif err == nil {\n\t\t\t// backup 解密成功：修复 conf + 刷新 backup\n\t\t\tbox := &Box{ID: boxID}\n\t\t\tboxConf := box.GetConf()\n\t\t\tboxConf.Encrypted = true\n\t\t\tboxConf.BoxCrypt = backup\n\t\t\tif saveErr := box.SaveConf(boxConf); saveErr != nil {\n\t\t\t\tlogging.LogWarnf(\"fix encrypted box conf from backup [%s] failed: %s\", boxID, saveErr)\n\t\t\t}\n\t\t\tif needWriteNotebookCryptBackup(boxID, backup) {\n\t\t\t\tif writeErr := writeNotebookCryptBackup(boxID, backup); writeErr != nil {\n\t\t\t\t\tlogging.LogWarnf(\"refresh notebook crypt backup [%s] failed: %s\", boxID, writeErr)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn dek, backup, nil\n\t\t}\n\t}\n\treturn nil, nil, fmt.Errorf(\"decrypt box [%s] failed: incorrect key or corrupted data\", boxID)\n}\n\n// UnlockBox 用主密码派生 KEK，解出该笔记本的 DEK 并缓存。KEK 用完即弃，不全局缓存。\n// 每次调用都跑一次 Argon2id（约 1 秒），严格满足\"每笔记本单独解锁\"语义。\nfunc UnlockBox(boxID string, password string, boxEnc *conf.BoxEncryption) (err error) {\n\tinvalidateEncryptedPublishAccessCache()\n\tif !ast.IsNodeIDPattern(boxID) {\n\t\treturn errors.New(\"invalid notebook ID\")\n\t}\n\n\t// 全局配置锁先于笔记本生命周期锁获取（设计 §17 锁顺序约定），避免与持子系统锁后回取配置锁的路径死锁。\n\t// notebookCryptoMu 持锁期间调用的 deriveKEK/conf 修复只申请 Conf.m/cachedDEKsLock，不回取 box 生命周期锁。\n\tnotebookCryptoMu.Lock()\n\tdefer notebookCryptoMu.Unlock()\n\treleaseTransition := holdEncryptedBoxTransition(boxID)\n\tdefer releaseTransition()\n\treturn unlockBoxHeld(boxID, password, boxEnc)\n}","sourceCodeStart":1337,"sourceCodeEnd":1373,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/crypto.go#L1337-L1373","documentation":"decryptBoxCrypt throws this after it tried the primary WrappedDEK and every alternate WrappedDEK in the backup, and none decrypted successfully under the provided KEK. It means the derived KEK is wrong (incorrect master password) or the stored ciphertext (envelope/backup) is corrupted. Unlike error 970, key material exists but cannot be decrypted.","triggerScenarios":"decryptWrappedDEKWithHistory fails for the primary envelope and for all backup WrappedDEKs during UnlockBox/unlockBoxHeld, ChangeMasterPassword, or the password-change recovery test, with a KEK derived from the supplied password.","commonSituations":"User typed the wrong master password; Argon2id parameters or salt changed between versions; conf.json and its backup were both corrupted or tampered with; a sync conflict replaced the envelope with one wrapped under a different password.","solutions":["Re-enter the master password carefully (check keyboard layout, trailing whitespace, IME state) and retry unlock","Check whether any recent sync or restore operation overwrote conf.json or the crypt backup; restore the pre-change snapshot","If corruption is suspected, verify the data directory is intact and use the documented recovery material (docs/ENCRYPTED-NOTEBOOK.md); never regenerate the MasterSalt","As a last resort restore the entire workspace from backup; the DEK is unrecoverable without a valid envelope plus the correct password"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Go\ndek, crypt, err := model.UnlockBox(boxID, password, boxEnc)\nif err != nil && strings.Contains(err.Error(), \"incorrect key or corrupted data\") {\n    // surface a password prompt; do NOT retry with the same input in a loop\n    // count attempts and lock out after N failures to protect against brute force\n}","preventionTips":["Confirm the master password once (double-entry field) before invoking unlock","Back up conf.json and the crypt backup before password changes; test with ChangeMasterPassword paths","Avoid mixing workspace snapshots across sync targets","Record recovery material per docs/ENCRYPTED-NOTEBOOK.md when setting the password"],"tags":["encryption","wrong-password","data-corruption"],"backgroundTag":"checksum-mismatch","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}