{"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":"validation","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/251596fc0de2f9528c00c224252fd073a99973f4/kernel/util/kdf.go#L99-L135","documentation":"Raised by EncryptionNonce when the stored nonceLength byte is 0, or when the buffer is too short to contain encryptionEnvelopeHeaderSize+nonceLength bytes. The nonce length is read from the envelope header and must fit within the remaining buffer.","triggerScenarios":"EncryptionNonce reads nonceLength = blob[6]; if it is zero, or the buffer does not contain at least 7+nonceLength bytes, this error returns. Occurs with corrupted header bytes (nonceLength set to a huge value) or truncated ciphertext.","commonSituations":"Header byte corruption setting nonceLength to a large value; a truncated blob whose header claims more nonce bytes than remain; an envelope written with a non-standard nonce size read by code assuming GCM's 12-byte nonce.","solutions":["Restore the ciphertext from a known-good backup.","Validate the full envelope length (header + nonce + at least one GCM tag block) before calling EncryptionNonce.","Ensure writers always use the GCM default nonce size (12 bytes) via encryptGCM."],"exampleFix":"// before\nnonce, err := util.EncryptionNonce(blob)\n\n// after: sanity-check the declared nonce length\nif len(blob) >= 7 {\n    declared := int(blob[6])\n    if declared == 0 || len(blob) < 7+declared {\n        return errors.New(\"envelope declares an impossible nonce length\")\n    }\n}\nnonce, err := util.EncryptionNonce(blob)","handlingStrategy":"validation","validationCode":"if len(blob) >= 7 {\n    declared := int(blob[6])\n    if declared == 0 || len(blob) < 7+declared {\n        return errors.New(\"envelope declares an impossible nonce length\")\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Sanity-check the declared nonce length against the buffer size.","Writers must use GCM's standard 12-byte nonce.","Restore truncated/corrupted blobs from backup."],"tags":["crypto","aes-gcm","encryption","validation","corruption"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}