siyuan-note/siyuan · error

Decryption failed: incorrect key or corrupted data

Error message

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

What it means

Returned by ChangeMasterPassword Phase 0 (crypto.go:1730-1733) when decryptBoxCrypt fails to unwrap a notebook's DEK with the KEK derived from oldPassword - both the conf.json WrappedDEK and the backup fallback reject it (message 316 plus a [box=ID] suffix naming the offender). It means the old password is wrong, or that specific notebook's key material is from a different KEK generation or corrupted.

Solutions

  1. Re-enter the current (old) master password and retry
  2. If a password change was interrupted before, restart SiYuan and let migration recovery complete before attempting another change
  3. Identify the box from the [box=ID] suffix, inspect/restore that notebook's conf.json and crypt backup from a snapshot, then retry
Defensive patterns

Strategy: try-catch

Try / catch

if err := model.ChangeMasterPassword(oldPw, newPw); err != nil {
    if strings.Contains(err.Error(), Conf.Language(316)) {
        // message carries [box=ID]; wrong old password or that box's key material is stale
        if boxID := extractBoxIDSuffix(err); boxID != "" {
            inspectBoxKeyMaterial(boxID) // restore conf+backup from snapshot if damaged
        } else {
            promptForCorrectOldPassword()
        }
    }
}

Prevention

When it happens

Trigger: Wrong oldPassword typed into the change-password dialog (most common); a leftover notebook whose WrappedDEK was already re-wrapped by an interrupted earlier migration; one notebook's conf+backup key material corrupted while the global verifier still authenticates.

Common situations: User confuses old and new password fields; a previous change attempt crashed after Phase 2 leaving mixed generations; selective corruption of one notebook's conf.json.

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/ad1373379b3cb251. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/crypto.go:1733

	}
	newKEK := util.DeriveKey(newPassword, nc.MasterSalt, params)
	defer zeroAndClear(newKEK)
	newVerifier, err := util.EncryptWithAAD(newKEK, kekVerifierMagic, []byte("siyuan:kek-verifier"))
	if err != nil {
		return err
	}

	// Phase 0: 遍历所有加密笔记本(含 conf 损坏但存在备份的),预计算新 WrappedDEK(内存操作)
	// 允许 entries 为空:用户可能已启用加密功能但尚未创建加密笔记本,此时仍需更新全局 verifier 和 backup。
	encBoxIDs, listErr := listAllEncryptedBoxIDs()
	if listErr != nil {
		return fmt.Errorf("list encrypted notebooks failed: %w", listErr)
	}
	var entries []migrationBoxEntry
	for _, id := range encBoxIDs {
		dek, boxCrypt, dErr := decryptBoxCrypt(id, oldKEK)
		if dErr != nil {
			return errors.New(Conf.Language(316) + " [box=" + id + "]")
		}
		newWrapped, nErr := util.EncryptWithAAD(newKEK, dek, wrappedDEKAAD(id))
		if nErr != nil {
			return nErr
		}
		entries = append(entries, migrationBoxEntry{
			BoxID:         id,
			NewSpec:       boxEncryptionSpec,
			NewWrappedDEK: newWrapped,
			NewWrapNonce:  mustEncryptionNonce(newWrapped),
			Metadata:      append([]byte(nil), boxCrypt.Metadata...),
		})
	}

	// Phase 1: 持久化 migration manifest(崩溃后 recovery 的依据)
	newParamsJSON, _ := gulu.JSON.MarshalJSON(params)
	mig := &masterPasswordMigration{
		OldVerifier:      nc.KEKVerifier,

View on GitHub (pinned to afa823b6b4)