siyuan-note/siyuan · critical

decrypt box [%s] failed: incorrect key or corrupted data

Error message

decrypt box [%s] failed: incorrect key or corrupted data

What it means

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.

Source

Thrown at kernel/model/crypto.go:1355

		dek, err = decryptWrappedDEKWithHistory(boxID, backup, kek, nc)
		if err == nil {
			// backup 解密成功:修复 conf + 刷新 backup
			box := &Box{ID: boxID}
			boxConf := box.GetConf()
			boxConf.Encrypted = true
			boxConf.BoxCrypt = backup
			if saveErr := box.SaveConf(boxConf); saveErr != nil {
				logging.LogWarnf("fix encrypted box conf from backup [%s] failed: %s", boxID, saveErr)
			}
			if needWriteNotebookCryptBackup(boxID, backup) {
				if writeErr := writeNotebookCryptBackup(boxID, backup); writeErr != nil {
					logging.LogWarnf("refresh notebook crypt backup [%s] failed: %s", boxID, writeErr)
				}
			}
			return dek, backup, nil
		}
	}
	return nil, nil, fmt.Errorf("decrypt box [%s] failed: incorrect key or corrupted data", boxID)
}

// UnlockBox 用主密码派生 KEK,解出该笔记本的 DEK 并缓存。KEK 用完即弃,不全局缓存。
// 每次调用都跑一次 Argon2id(约 1 秒),严格满足"每笔记本单独解锁"语义。
func UnlockBox(boxID string, password string, boxEnc *conf.BoxEncryption) (err error) {
	invalidateEncryptedPublishAccessCache()
	if !ast.IsNodeIDPattern(boxID) {
		return errors.New("invalid notebook ID")
	}

	// 全局配置锁先于笔记本生命周期锁获取(设计 §17 锁顺序约定),避免与持子系统锁后回取配置锁的路径死锁。
	// notebookCryptoMu 持锁期间调用的 deriveKEK/conf 修复只申请 Conf.m/cachedDEKsLock,不回取 box 生命周期锁。
	notebookCryptoMu.Lock()
	defer notebookCryptoMu.Unlock()
	releaseTransition := holdEncryptedBoxTransition(boxID)
	defer releaseTransition()
	return unlockBoxHeld(boxID, password, boxEnc)
}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Re-enter the master password carefully (check keyboard layout, trailing whitespace, IME state) and retry unlock
  2. Check whether any recent sync or restore operation overwrote conf.json or the crypt backup; restore the pre-change snapshot
  3. If corruption is suspected, verify the data directory is intact and use the documented recovery material (docs/ENCRYPTED-NOTEBOOK.md); never regenerate the MasterSalt
  4. As a last resort restore the entire workspace from backup; the DEK is unrecoverable without a valid envelope plus the correct password
Defensive patterns

Strategy: try-catch

Try / catch

// Go
dek, crypt, err := model.UnlockBox(boxID, password, boxEnc)
if err != nil && strings.Contains(err.Error(), "incorrect key or corrupted data") {
    // surface a password prompt; do NOT retry with the same input in a loop
    // count attempts and lock out after N failures to protect against brute force
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/185f2c4f5438326f. Report an issue: GitHub.