{"record":{"id":"70ba8c2bb7f2fe3a","repo":"JeffreySu/WeiXinMPSDK","slug":"requestmessageevent-miniprogrampay","errorCode":null,"errorMessage":"通知资源密文长度无效。","messagePattern":"通知资源密文长度无效。","errorType":"exception","errorClass":"CryptographicException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_MiniProgramPay.cs","lineNumber":90,"sourceCode":"                throw new ArgumentException(\"EncodingAESKey 必须为 43 个字符。\", nameof(encodingAesKey));\n            }\n\n            if (resource == null)\n            {\n                throw new InvalidOperationException(\"通知中不包含 resource 节点。\");\n            }\n\n            if (!string.Equals(resource.algorithm, \"AEAD_AES_256_GCM\", StringComparison.OrdinalIgnoreCase))\n            {\n                throw new NotSupportedException($\"不支持的通知资源加密算法：{resource.algorithm}\");\n            }\n\n            var key = Convert.FromBase64String(encodingAesKey + \"=\");\n            var encrypted = Convert.FromBase64String(resource.ciphertext);\n            const int tagSize = 16;\n            if (encrypted.Length <= tagSize)\n            {\n                throw new CryptographicException(\"通知资源密文长度无效。\");\n            }\n\n            var ciphertext = new byte[encrypted.Length - tagSize];\n            var tag = new byte[tagSize];\n            var plaintext = new byte[ciphertext.Length];\n            Buffer.BlockCopy(encrypted, 0, ciphertext, 0, ciphertext.Length);\n            Buffer.BlockCopy(encrypted, ciphertext.Length, tag, 0, tag.Length);\n\n            try\n            {\n                var nonce = Encoding.UTF8.GetBytes(resource.nonce);\n                var associatedData = Encoding.UTF8.GetBytes(resource.associated_data ?? string.Empty);\n#if NET8_0_OR_GREATER\n                using (var aesGcm = new AesGcm(key, tagSize))\n#else\n                using (var aesGcm = new AesGcm(key))\n#endif\n                {","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_MiniProgramPay.cs#L72-L108","documentation":"The Base64-decoded ciphertext must be longer than the 16-byte GCM authentication tag so it can be split into ciphertext + tag. A payload of 16 bytes or fewer cannot contain any plaintext plus a tag, so the library throws CryptographicException before attempting decryption.","triggerScenarios":"resource.ciphertext decodes to <= 16 bytes — e.g. empty ciphertext, a truncated field, or the caller passing the tag-only portion.","commonSituations":"Corrupt/truncated webhook bodies logged and replayed incorrectly, encoding the ciphertext as a placeholder in tests, or manually slicing the encrypted buffer at the wrong offset.","solutions":["Re-read the original webhook body and confirm resource.ciphertext is complete and valid Base64","Check nothing is truncating the payload (proxy, logging middleware, fixed-size buffers)","Validate decrypted length > 16 before calling DecryptResource in defensive wrappers"],"exampleFix":"// before\nvar plain = message.DecryptResource(aesKey);\n// after\nvar raw = Convert.FromBase64String(message.Resource.ciphertext);\nif (raw.Length <= 16)\n    throw new InvalidDataException($\"ciphertext too short: {raw.Length} bytes\");\nvar plain = message.DecryptResource(aesKey);","handlingStrategy":"validation","validationCode":"byte[] raw;\nif (!Convert.TryFromBase64String(message.Resource?.ciphertext ?? \"\", raw = new byte[512], out var n) || n <= 16)\n    throw new InvalidDataException(\"ciphertext missing or too short\");","typeGuard":"static bool HasValidCiphertext(Models.MessageEvent.Resource r) =>\n    r?.ciphertext != null && Convert.FromBase64String(r.ciphertext).Length > 16;","tryCatchPattern":"try { var plain = msg.DecryptResource(aesKey); }\ncatch (CryptographicException ex) { log.Error(\"Bad ciphertext payload\", ex); return Results.StatusCode(400); }","preventionTips":["Never truncate/re-encode webhook bodies when logging or replaying them","Preserve the raw body bytes end-to-end through proxies and middleware","Validate Base64 decodability of resource.ciphertext at the webhook boundary"],"tags":["cryptography","payload-validation","base64"],"backgroundTag":"invalid-argument-format","analyzedSha":"be573f6f94bdbf718dd5f6cdecb137fbc7ff651e","analyzedAt":"2026-09-12T10:01:50.733Z","contentChangedAt":"2026-09-12T10:01:50.733Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}