{"record":{"id":"6fe9c7495c5bda53","repo":"siyuan-note/siyuan","slug":"invalid-encrypted-envelope-magic","errorCode":null,"errorMessage":"invalid encrypted envelope magic","messagePattern":"invalid encrypted envelope magic","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/kdf.go","lineNumber":104,"sourceCode":"func DeriveKey(password string, salt []byte, p Argon2Params) []byte {\n\treturn argon2.IDKey([]byte(password), salt, p.Iterations, p.Memory, p.Parallelism, p.KeyLength)\n}\n\n// Encrypt 用 AES-256-GCM 加密。每次调用生成随机 nonce，因此同一明文多次加密结果不同。\n// 返回格式：magic(4B) || spec(1B) || algorithm(1B) || nonceLength(1B) || nonce || ciphertext || GCM tag(16B)。\nfunc 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 派生用途隔离的子密钥。","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/kdf.go#L86-L122","documentation":"EncryptionNonce parses SiYuan's SENC envelope format (magic 'SENC' + spec + algorithm + nonce length + nonce). The input does not start with the 4-byte 'SENC' magic, meaning it is not an encrypted envelope produced by Encrypt/EncryptWithAAD. The function refuses to parse arbitrary or foreign bytes.","triggerScenarios":"Calling EncryptionNonce with ciphertext that was not produced by util.Encrypt/EncryptWithAAD — e.g. raw AES-GCM output from another tool, plaintext bytes, a base64 string decoded incorrectly, or data encrypted by a different format version.","commonSituations":"Inspecting legacy (pre-encryption-feature) notebook data, decrypting data encrypted by an external tool, passing the wrong slice (e.g. header-stripped ciphertext), or corruption/truncation overwrote the header.","solutions":["Verify the input is a complete envelope returned by util.Encrypt/EncryptWithAAD, not raw ciphertext or plaintext","Check that the data source actually wrote an encrypted envelope (notebook encryption was enabled when the data was written)","If the data came from another tool, decrypt it with that tool's method instead of SiYuan's EncryptionNonce","If bytes were truncated/reordered in transit, re-fetch or restore the original file"],"exampleFix":"// before\nnonce, err := util.EncryptionNonce(rawAESCiphertext) // no SENC header\n\n// after\nenvelope, err := util.Encrypt(key, plaintext)\nif err != nil { return err }\nnonce, err := util.EncryptionNonce(envelope)","handlingStrategy":"validation","validationCode":"func isSENCEnvelope(b []byte) bool {\n    return len(b) >= 7 && b[0]=='S' && b[1]=='E' && b[2]=='N' && b[3]=='C'\n}\nif !isSENCEnvelope(data) { return errors.New(\"not a SENC envelope\") }","typeGuard":"func hasEncHeader(b []byte) bool {\n    return len(b) >= 4 && string(b[:4]) == \"SENC\"\n}","tryCatchPattern":"nonce, err := util.EncryptionNonce(ciphertext)\nif err != nil {\n    return fmt.Errorf(\"not a SiYuan encrypted envelope: %w\", err)\n}","preventionTips":["Only pass output of util.Encrypt/EncryptWithAAD to EncryptionNonce","Never strip or re-encode the envelope header before parsing","Check for the 'SENC' prefix before parsing third-party data"],"tags":["encryption","aes-gcm","envelope-format","validation"],"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"}