siyuan-note/siyuan · error

encrypted notebook key envelope nonce mismatch

Error message

encrypted notebook key envelope nonce mismatch

What it means

The nonce embedded in the WrappedDEK ciphertext does not equal the separately stored WrapNonce field. The two must match for the envelope to be internally consistent; a mismatch means the stored pieces were mixed across generations or tampered with.

Solutions

  1. Identify which operation last rewrapped the DEK (e.g. ChangeMasterPassword) and restore a conf backup from before that operation
  2. Ensure password-change/rotation flows complete atomically across all boxes; re-run the change from a consistent state
  3. Do not hand-edit WrapNonce; it must be derived from the actual WrappedDEK ciphertext
Defensive patterns

Strategy: validation

Validate before calling

n, err := util.EncryptionNonce(enc.WrappedDEK); if err == nil && !bytes.Equal(n, enc.WrapNonce) { return errors.New("envelope fields inconsistent; restore pre-rotation backup") }

Try / catch

if err := unlockBox(boxID); err != nil { if strings.Contains(err.Error(), "nonce mismatch") { /* restore conf backup from before the last rewrap */ } }

Prevention

When it happens

Trigger: During unlock, validateWrappedDEKEnvelope compares util.EncryptionNonce(enc.WrappedDEK) with enc.WrapNonce using bytes.Equal; any re-wrap (password change, rotation) that updated one field but not the other triggers this.

Common situations: A partially applied master-password change that rewrote WrappedDEK but left the old WrapNonce (or vice versa); restoring conf fields from different backups; concurrent writers to the same box conf.

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@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/1225675c6c6405ea. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/crypto.go:1647

	if err := validateWrappedDEKEnvelope(enc); err != nil {
		return nil, err
	}
	return util.DecryptWithAAD(kek, enc.WrappedDEK, wrappedDEKAAD(boxID))
}

func validateWrappedDEKEnvelope(enc *conf.BoxEncryption) error {
	if enc == nil || enc.Spec != boxEncryptionSpec {
		return errors.New("unsupported encrypted notebook key envelope")
	}
	if enc.CreatedAt <= 0 {
		return errors.New("encrypted notebook key envelope creation time is missing")
	}
	nonce, err := util.EncryptionNonce(enc.WrappedDEK)
	if err != nil {
		return fmt.Errorf("invalid encrypted notebook key envelope: %w", err)
	}
	if !bytes.Equal(nonce, enc.WrapNonce) {
		return errors.New("encrypted notebook key envelope nonce mismatch")
	}
	return nil
}

func validateBoxEncryption(enc *conf.BoxEncryption) error {
	if err := validateWrappedDEKEnvelope(enc); err != nil {
		return err
	}
	if _, err := util.EncryptionNonce(enc.Metadata); err != nil {
		return fmt.Errorf("invalid encrypted notebook metadata envelope: %w", err)
	}
	return nil
}

// mustEncryptionNonce 从刚刚成功生成的密文中提取 nonce。生成密文格式错误属于内部不变量被破坏,直接终止执行。
func mustEncryptionNonce(ciphertext []byte) []byte {
	nonce, err := util.EncryptionNonce(ciphertext)
	if err != nil {

View on GitHub (pinned to 9f775e8a12)