JeffreySu/WeiXinMPSDK · error · CryptographicException

通知资源密文长度无效。

Error message

通知资源密文长度无效。

What it means

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.

Solutions

  1. Re-read the original webhook body and confirm resource.ciphertext is complete and valid Base64
  2. Check nothing is truncating the payload (proxy, logging middleware, fixed-size buffers)
  3. Validate decrypted length > 16 before calling DecryptResource in defensive wrappers

Example fix

// before
var plain = message.DecryptResource(aesKey);
// after
var raw = Convert.FromBase64String(message.Resource.ciphertext);
if (raw.Length <= 16)
    throw new InvalidDataException($"ciphertext too short: {raw.Length} bytes");
var plain = message.DecryptResource(aesKey);
Defensive patterns

Strategy: validation

Validate before calling

byte[] raw;
if (!Convert.TryFromBase64String(message.Resource?.ciphertext ?? "", raw = new byte[512], out var n) || n <= 16)
    throw new InvalidDataException("ciphertext missing or too short");

Type guard

static bool HasValidCiphertext(Models.MessageEvent.Resource r) =>
    r?.ciphertext != null && Convert.FromBase64String(r.ciphertext).Length > 16;

Try / catch

try { var plain = msg.DecryptResource(aesKey); }
catch (CryptographicException ex) { log.Error("Bad ciphertext payload", ex); return Results.StatusCode(400); }

Prevention

When it happens

Trigger: resource.ciphertext decodes to <= 16 bytes — e.g. empty ciphertext, a truncated field, or the caller passing the tag-only portion.

Common situations: 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.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of JeffreySu/WeiXinMPSDK@be573f6f94 (2026-09-12). Data as JSON: /api/errors/70ba8c2bb7f2fe3a. Report an issue: GitHub.

Appendix: source

Thrown at src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_MiniProgramPay.cs:90

                throw new ArgumentException("EncodingAESKey 必须为 43 个字符。", nameof(encodingAesKey));
            }

            if (resource == null)
            {
                throw new InvalidOperationException("通知中不包含 resource 节点。");
            }

            if (!string.Equals(resource.algorithm, "AEAD_AES_256_GCM", StringComparison.OrdinalIgnoreCase))
            {
                throw new NotSupportedException($"不支持的通知资源加密算法:{resource.algorithm}");
            }

            var key = Convert.FromBase64String(encodingAesKey + "=");
            var encrypted = Convert.FromBase64String(resource.ciphertext);
            const int tagSize = 16;
            if (encrypted.Length <= tagSize)
            {
                throw new CryptographicException("通知资源密文长度无效。");
            }

            var ciphertext = new byte[encrypted.Length - tagSize];
            var tag = new byte[tagSize];
            var plaintext = new byte[ciphertext.Length];
            Buffer.BlockCopy(encrypted, 0, ciphertext, 0, ciphertext.Length);
            Buffer.BlockCopy(encrypted, ciphertext.Length, tag, 0, tag.Length);

            try
            {
                var nonce = Encoding.UTF8.GetBytes(resource.nonce);
                var associatedData = Encoding.UTF8.GetBytes(resource.associated_data ?? string.Empty);
#if NET8_0_OR_GREATER
                using (var aesGcm = new AesGcm(key, tagSize))
#else
                using (var aesGcm = new AesGcm(key))
#endif
                {

View on GitHub (pinned to be573f6f94)