Tencent/WeKnora · error

invalid padding

Error message

invalid padding

What it means

After CBC decryption, decrypt() verifies PKCS#7 padding: the last byte gives the pad length, which must be between 1 and 16 and must fit within the plaintext. A padLen of 0, greater than the 16-byte block size, or larger than the buffer is impossible for valid WeCom messages and indicates wrong key or corrupted data. This is the first of two padding checks (range check here, byte-consistency at error 783).

Source

Thrown at internal/im/wecom/webhook_adapter.go:473

	if err != nil {
		return nil, fmt.Errorf("new cipher: %w", err)
	}

	if len(ciphertext) < aes.BlockSize {
		return nil, fmt.Errorf("ciphertext too short")
	}
	if len(ciphertext)%aes.BlockSize != 0 {
		return nil, fmt.Errorf("ciphertext length is not a multiple of AES block size")
	}

	iv := a.aesKey[:aes.BlockSize]
	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(ciphertext, ciphertext)

	// Remove and verify PKCS#7 padding
	padLen := int(ciphertext[len(ciphertext)-1])
	if padLen > wecomPKCS7BlockSize || padLen == 0 || padLen > len(ciphertext) {
		return nil, fmt.Errorf("invalid padding")
	}
	for i := 0; i < padLen; i++ {
		if ciphertext[len(ciphertext)-1-i] != byte(padLen) {
			return nil, fmt.Errorf("invalid padding")
		}
	}
	plaintext := ciphertext[:len(ciphertext)-padLen]

	// WeCom format: random(16) + msg_len(4) + msg + corp_id
	if len(plaintext) < 20 {
		return nil, fmt.Errorf("plaintext too short")
	}

	msgLen := binary.BigEndian.Uint32(plaintext[16:20])
	if uint32(len(plaintext)) < 20+msgLen {
		return nil, fmt.Errorf("message length mismatch")
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Verify a.aesKey matches the EncodingAESKey of the exact WeCom application that sent the callback (43-char base64 key, decoded to 32 bytes)
  2. Re-download/regenerate the EncodingAESKey from the WeCom admin console and update config
  3. Log the first bytes and length of the ciphertext and key to confirm they come from the same app
  4. Check for config loading issues (trailing newline, quotes) corrupting the key

Example fix

// before: key with newline from env
aesKey := os.Getenv("WECOM_AES_KEY")
// after: trimmed and validated
aesKey := strings.TrimSpace(os.Getenv("WECOM_AES_KEY"))
if len(aesKey) != 43 { return errors.New("invalid EncodingAESKey length") }
Defensive patterns

Strategy: validation

Validate before calling

if len(strings.TrimSpace(aesKey)) != 43 { return errors.New("EncodingAESKey must be 43 base64 chars") }

Try / catch

msg, err := adapter.ParseCallback(sig, ts, nonce, enc)
if err != nil && strings.Contains(err.Error(), "invalid padding") {
    logger.Error("WeCom decrypt failed — check EncodingAESKey matches the callback app")
    http.Error(w, "decrypt failed", http.StatusBadRequest)
    return
}

Prevention

When it happens

Trigger: Decryption with a mismatched EncodingAESKey so the last decrypted block's final byte is an arbitrary value; corrupted ciphertext; feeding non-AES data through decrypt.

Common situations: AES key copied from the wrong WeCom app (multi-app configs); key contains whitespace/newline from config file; environment-specific keys out of sync with the WeCom console.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/97949b8ffc45fedc. Report an issue: GitHub.