{"record":{"id":"3425823e80631e40","repo":"siyuan-note/siyuan","slug":"cannot-import-a-key-backup-while-encrypted-noteboo","errorCode":null,"errorMessage":"Cannot import a key backup while encrypted notebooks are enabled. Disable it first","messagePattern":"Cannot import a key backup while encrypted notebooks are enabled\\. Disable it first","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/model/crypto.go","lineNumber":319,"sourceCode":"}\n\n// ImportNotebookCryptoBackup 接收用户导入的密钥备份文件内容（JSON 字节），\n// 校验为合法 NotebookCrypto 后写回 <DataDir>/.siyuan/data-crypto-backup.json 并装回本机 Conf。\n// 用于新设备/重装后不依赖同步、手动恢复加密配置（详见设计文档 §4.1）。\n// 安全：备份文件不含主密码（salt 不保密、verifier 是密文），导入只恢复配置，解锁仍需主密码。\n// 防呆：本机已有完整且已启用的加密配置时拒绝导入，避免覆盖现有 salt/verifier 孤立现有 WrappedDEK。\n// ImportNotebookCryptoBackup 接收用户导入的密钥备份文件内容（JSON 字节）+ 主密码，\n// 校验主密码能解开备份里的 verifier 后才写回配置。防止 crafted 备份设置弱 KDFParams 等攻击。\n// RecoveryRequired 状态允许导入，但候选 KEK 必须能解开所有现存笔记本和已删除笔记本历史。\nfunc ImportNotebookCryptoBackup(data []byte, password string) error {\n\tnotebookCryptoMu.Lock()\n\tdefer notebookCryptoMu.Unlock()\n\n\tConf.m.RLock()\n\tcurrent := *Conf.NotebookCrypto\n\tConf.m.RUnlock()\n\tif current.Enabled && notebookCryptoConfigurationComplete(&current) {\n\t\treturn errors.New(Conf.Language(324))\n\t}\n\n\tnc := &conf.NotebookCrypto{}\n\tif err := json.Unmarshal(data, nc); err != nil {\n\t\treturn errors.New(Conf.Language(317))\n\t}\n\tif !notebookCryptoConfigurationComplete(nc) {\n\t\treturn errors.New(Conf.Language(317))\n\t}\n\n\t// 用导入的 salt + 用户输入的主密码派生 KEK，校验能否解开备份里的 verifier\n\tparams, validErr := util.ValidateArgon2Params(nc.KDFParams)\n\tif validErr != nil {\n\t\treturn errors.New(Conf.Language(317))\n\t}\n\tkek := util.DeriveKey(password, nc.MasterSalt, params)\n\tdefer zeroAndClear(kek)\n\tif nc.Checksum != computeBackupChecksum(nc) {","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/crypto.go#L301-L337","documentation":"ImportNotebookCryptoBackup refuses to import a backup when the local NotebookCrypto configuration is already Enabled and complete (notebookCryptoConfigurationComplete). This is a deliberate guard: importing would overwrite the existing MasterSalt/KEKVerifier and orphan the existing WrappedDEKs, making current encrypted notebooks permanently undecryptable. The error is Conf.Language(324).","triggerScenarios":"Calling ImportNotebookCryptoBackup while Conf.NotebookCrypto.Enabled is true and the configuration has all required fields. Happens when a user has encryption active on this device and attempts to import a backup from another device or a previously exported file.","commonSituations":"User enabled encryption on device A and tries to import device B's backup on device A; user re-imports an old backup after changing the master password; scripted restore run against an already-configured workspace.","solutions":["Disable encryption on the current device first (DecryptEncryptedNotebook / disable flow), then import the backup.","If the goal is to adopt another device's key domain, use the sync-based recovery path instead of manual import.","Confirm whether the import is actually needed — an already-enabled complete config does not require restoration."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Only offer import when encryption is not already enabled and complete.\nif model.NotebookCryptoEnabled() {\n    // hide / disable import; prompt to disable encryption first if needed\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Gate the import action on encryption being disabled or incomplete.","Prefer the sync-based recovery path to adopt another device's key domain rather than manual import.","Never import a backup onto an already-enabled complete configuration — it would orphan existing WrappedDEKs."],"tags":["crypto","backup","encryption","import","guard"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}