{"record":{"id":"b9d006d7b0dbcc3f","repo":"siyuan-note/siyuan","slug":"invalid-encrypted-envelope-nonce-length","errorCode":null,"errorMessage":"invalid encrypted envelope nonce length","messagePattern":"invalid encrypted envelope nonce length","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/kdf.go","lineNumber":117,"sourceCode":"}\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\n\tif _, err := io.ReadFull(r, out); err != nil {\n\t\t// hkdf.Read 不应出错（除非 dek 为空）；防御性 panic 避免静默返回弱密钥\n\t\tpanic(\"hkdf derive failed: \" + err.Error())\n\t}\n\treturn out\n}\n","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/kdf.go#L99-L135","documentation":"EncryptionNonce reads the nonce length byte (offset 6) and checks it is non-zero and that the envelope actually contains that many bytes after the 7-byte header. A zero length or a length exceeding the remaining buffer means the envelope is malformed or truncated.","triggerScenarios":"Calling EncryptionNonce on an envelope where byte 6 is 0x00 (corrupt header) or where len(ciphertext) < 7 + nonceLength (body truncated), e.g. a partially written or partially synced encrypted file.","commonSituations":"Interrupted writes (crash/power loss mid-write), incomplete sync of encrypted blobs, manual truncation of ciphertext, or corruption flipping the length byte.","solutions":["Verify the full envelope was written/read — compare file size against the expected envelope length","Restore the encrypted blob from backup or re-sync it; a truncated GCM envelope is unrecoverable in place","Check the write path for missing error handling on file writes that could leave partial envelopes","If only extracting the nonce for diagnostics, treat this envelope as corrupt and skip it"],"exampleFix":"// before\nnonce, err := util.EncryptionNonce(envelope[:len(envelope)-8]) // chopped tail\n\n// after\nnonce, err := util.EncryptionNonce(envelope)\nif err != nil { return fmt.Errorf(\"envelope corrupt: %w\", err) }","handlingStrategy":"validation","validationCode":"if len(data) >= 7 {\n    nl := int(data[6])\n    if nl == 0 || len(data) < 7+nl {\n        return errors.New(\"envelope nonce length invalid or body truncated\")\n    }\n}","typeGuard":"func envelopeComplete(b []byte) bool {\n    if len(b) < 7 { return false }\n    nl := int(b[6])\n    return nl > 0 && len(b) >= 7+nl\n}","tryCatchPattern":"nonce, err := util.EncryptionNonce(ciphertext)\nif err != nil {\n    return fmt.Errorf(\"envelope corrupt/truncated, restore from backup: %w\", err)\n}","preventionTips":["Ensure file writes of envelopes are atomic or error-checked (no partial writes)","Verify sync completed fully before reading encrypted blobs","Keep backups; truncated GCM envelopes cannot be repaired in place"],"tags":["encryption","envelope-format","corrupt-data","truncated-data"],"backgroundTag":"invalid-argument-format","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}