{"record":{"id":"a05ded3c8101af52","repo":"siyuan-note/siyuan","slug":"unsupported-encrypted-envelope-spec","errorCode":null,"errorMessage":"unsupported encrypted envelope spec","messagePattern":"unsupported encrypted envelope spec","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/kdf.go","lineNumber":110,"sourceCode":"func Encrypt(key, plaintext []byte) ([]byte, error) {\n\treturn encryptGCM(key, plaintext, nil, \"Encrypt\")\n}\n\n// Decrypt 对应 Encrypt 的解密。密钥错误、格式无效或密文被篡改时返回错误。\nfunc Decrypt(key, ciphertext []byte) ([]byte, error) {\n\treturn decryptGCM(key, ciphertext, nil, \"Decrypt\")\n}\n\n// EncryptionNonce 从 AES-GCM 密文信封中提取 nonce。\nfunc EncryptionNonce(ciphertext []byte) ([]byte, error) {\n\tif !hasEncryptionMagic(ciphertext) {\n\t\treturn nil, errors.New(\"invalid encrypted envelope magic\")\n\t}\n\tif len(ciphertext) < encryptionEnvelopeHeaderSize {\n\t\treturn nil, errors.New(\"encrypted envelope too short\")\n\t}\n\tif ciphertext[len(encryptionMagic)] != EncryptionSpec {\n\t\treturn nil, errors.New(\"unsupported encrypted envelope spec\")\n\t}\n\tif ciphertext[len(encryptionMagic)+1] != encryptionAlgorithmAES256GCM {\n\t\treturn nil, errors.New(\"unsupported encrypted envelope algorithm\")\n\t}\n\tnonceLength := int(ciphertext[len(encryptionMagic)+2])\n\tif nonceLength == 0 || len(ciphertext) < encryptionEnvelopeHeaderSize+nonceLength {\n\t\treturn nil, errors.New(\"invalid encrypted envelope nonce length\")\n\t}\n\treturn append([]byte(nil), ciphertext[encryptionEnvelopeHeaderSize:encryptionEnvelopeHeaderSize+nonceLength]...), nil\n}\n\n// DeriveSubKey 用 HKDF-SHA256 从主 DEK 派生用途隔离的子密钥。\n// 同一 (dek, purpose) 多次调用结果一致；不同 purpose 派生出相互独立的子密钥，\n// 实现用途分离——.sy/assets/AV 各用独立子密钥，互不可替代，限制单点密钥泄漏的影响面。\nfunc DeriveSubKey(dek []byte, purpose string) []byte {\n\t// HKDF info 用 purpose 字节；salt 为 nil（DEK 本身已是高熵随机密钥，无需额外 salt）\n\tr := hkdf.New(sha256.New, dek, nil, []byte(purpose))\n\tout := make([]byte, 32) // AES-256","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/util/kdf.go#L92-L128","documentation":"Raised by EncryptionNonce when the spec byte at offset len(encryptionMagic) (4) does not equal EncryptionSpec (currently 1). The spec byte identifies the envelope format version; a mismatch means the blob is either a future/incompatible version or corrupted at that byte.","triggerScenarios":"EncryptionNonce reads a blob whose 5th byte is not 1. Happens if the blob was produced by a newer SiYuan using a higher spec, or if the byte was flipped by corruption.","commonSituations":"Opening a notebook created by a newer kernel version that bumped EncryptionSpec; bit-rot in the conf; an older kernel reading a newer-format envelope.","solutions":["Upgrade the kernel to a version that understands the spec byte in the blob.","If the spec byte is unexpected due to corruption, restore from backup.","Do not hand-edit envelope bytes; regenerate via the official crypto flow."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if util.IsCiphertext(blob) && len(blob) > 4 && blob[4] != byte(util.EncryptionSpec) {\n    return fmt.Errorf(\"envelope spec %d is unsupported by this kernel\", blob[4])\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep kernel and notebook formats on compatible versions.","Do not hand-edit envelope bytes.","Restore from backup if the spec byte looks corrupted."],"tags":["crypto","aes-gcm","encryption","validation","version-mismatch"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}