siyuan-note/siyuan · critical
316
316
Error message
Decryption failed: incorrect key or corrupted data
What it means
Thrown by deriveNotebookCryptoBackupCandidate (crypto.go:1187, i18n code 316) when the KEK passed the verifier magic check but the backup fails integrity authentication: the Spec is not CurrentNotebookCryptoSpec, Checksum is empty, KEKMAC is empty, or verifyKEKMAC fails. A backup that decrypts but does not authenticate is treated as corrupted or tampered, so it is rejected to prevent using untrusted key material.
Source
Thrown at kernel/model/crypto.go:1187
func deriveNotebookCryptoBackupCandidate(password string) (backup *conf.NotebookCrypto, kek []byte, err error) {
backup, err = loadNotebookCryptoBackup()
if err != nil || backup == nil || len(backup.MasterSalt) == 0 || len(backup.KEKVerifier) == 0 {
return nil, nil, errors.New(Conf.Language(310))
}
params, validErr := util.ValidateArgon2Params(backup.KDFParams)
if validErr != nil {
return nil, nil, errors.New(Conf.Language(317))
}
kek = util.DeriveKey(password, backup.MasterSalt, params)
decrypted, decryptErr := util.DecryptWithAAD(kek, backup.KEKVerifier, []byte("siyuan:kek-verifier"))
if decryptErr != nil || string(decrypted) != string(kekVerifierMagic) {
zeroAndClear(kek)
return nil, nil, errors.New(Conf.Language(311))
}
if backup.Spec != conf.CurrentNotebookCryptoSpec || backup.Checksum == "" ||
len(backup.KEKMAC) == 0 || !verifyKEKMAC(backup, kek) {
zeroAndClear(kek)
return nil, nil, errors.New(Conf.Language(316))
}
if !verifyKEKAgainstExistingBoxes(kek) || !verifyKEKAgainstEncryptedHistory(kek) {
zeroAndClear(kek)
return nil, nil, errors.New(Conf.Language(316))
}
backup.KDFParams = params
return backup, kek, nil
}
// deriveKEK 从主密码派生 KEK 并校验。校验失败返回错误。KEK 仅在函数作用域内有效,调用方负责使用。
func deriveKEK(password string) ([]byte, error) {
Conf.m.RLock()
nc := *Conf.NotebookCrypto
Conf.m.RUnlock()
if !nc.Enabled {
// 本机未启用:可能是数据同步到新设备后本机 conf.json 还没有加密配置。
// 尝试从 DataDir 备份恢复(备份会随 DataDir 同步过来);恢复成功时直接复用其派生的 KEK。View on GitHub (pinned to 251596fc0d)
Solutions
- Restore a complete, spec-compatible backup from a known-good sync snapshot or another device.
- Upgrade/downgrade the kernel to a version whose CurrentNotebookCryptoSpec matches the backup, if the backup is intentionally from another spec era.
- If the local conf.json authenticates instead (localAuthenticated path in deriveKEK), prefer it and let the model repair the backup automatically.
Defensive patterns
Strategy: validation
Validate before calling
// Confirm backup integrity before recovery.
b, err := loadNotebookCryptoBackup()
if err != nil || b == nil {
return errors.New("no backup")
}
if b.Spec != conf.CurrentNotebookCryptoSpec || b.Checksum == "" || len(b.KEKMAC) == 0 {
return errors.New("backup fails spec/checksum/MAC; restore a complete backup")
} Try / catch
if err := model.UnlockBox(boxID, password, boxCrypt); err != nil {
if err.Error() == model.Conf.Language(316) {
respond(c, "key backup failed integrity check; restore a trusted backup")
return
}
respond(c, err.Error())
} Prevention
- Never edit or truncate the backup file.
- Keep kernel version aligned with the backup's NotebookCryptoSpec.
- Maintain a known-good backup copy for restore.
When it happens
Trigger: deriveNotebookCryptoBackupCandidate: backup.Spec != conf.CurrentNotebookCryptoSpec, backup.Checksum == "", len(backup.KEKMAC) == 0, or the HMAC computed over the backup does not equal backup.KEKMAC under the derived KEK.
Common situations: Backup from an incompatible spec version (upgrade/downgrade across format changes). Backup truncated or bit-flipped (MAC mismatch). Backup hand-edited. Sync delivered a partially-updated backup.
Related errors
- 310
- 317
- encrypted .sy [%s]: base id [%s] != root id [%s]
- Encrypted notebooks already exist but the master key backup
- Cannot import a key backup while encrypted notebooks are ena
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/1cf9d0e9301cf09c.
Report an issue: GitHub.