{"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":"error_code","errorClass":null,"httpStatus":null,"severity":"error","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/9f775e8a12daef8255556097396f9b2739078892/kernel/model/crypto.go#L1337-L1373","documentation":"decryptBoxCrypt returns this error after both the primary WrappedDEK and any differing backup WrappedDEK fail to decrypt with the supplied KEK. It means the derived key does not match the notebook's key wrapping, or the wrapped key data is corrupted. This is the generic 'wrong password or damaged key material' outcome of the per-notebook unlock pipeline.","triggerScenarios":"UnlockBox/UnlockAndMountBox with a wrong master password; ChangeMasterPassword racing an incomplete migration; WrappedDEK or backup WrappedDEK corrupted (bit rot, manual edit, bad sync); KEK derived from an older password while notebooks were already re-wrapped.","commonSituations":"User forgot/misspelled the master password; workspace synced mid-password-change so conf and backup hold WrappedDEKs from different password generations; history KEKs are out of sync so decryptWrappedDEKWithHistory cannot unwrap.","solutions":["Retry with the correct current master password (each attempt costs ~1s Argon2id)","If a password change was interrupted, complete the migration with the old or new password as appropriate so KEK and WrappedDEK generations match","Restore the notebook's conf.json and crypto backup from a known-good backup/sync peer","If the password is truly lost, the notebook data is unrecoverable by design; restore from an unencrypted snapshot"],"exampleFix":"// before\nerr := model.UnlockBox(boxID, typedPassword, boxEnc)\n// treated as fatal, box marked error\n// after\nif err != nil && strings.Contains(err.Error(), \"incorrect key or corrupted data\") {\n    // prompt user to re-enter password; do not permanently mark state error on first failure\n    return retryUnlockWithPrompt(boxID)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := model.UnlockBox(boxID, password, boxEnc); err != nil {\n    if strings.Contains(err.Error(), \"incorrect key or corrupted data\") {\n        // treat as wrong-password: prompt retry, cap attempts\n    }\n}","preventionTips":["Prompt users to confirm the master password before password changes","Complete password migrations without interruption","Keep conf.json and crypto backup in sync across peers","Log decryptBoxCrypt failures with the box ID for diagnosis"],"tags":["encryption","wrong-password","key-management","go"],"backgroundTag":"decryption-failed","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}