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
- Verify a.aesKey matches the EncodingAESKey of the exact WeCom application that sent the callback (43-char base64 key, decoded to 32 bytes)
- Re-download/regenerate the EncodingAESKey from the WeCom admin console and update config
- Log the first bytes and length of the ciphertext and key to confirm they come from the same app
- 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
- Keep one Token/AESKey pair per WeCom app and load them together from the same config source
- Trim whitespace/newlines when loading keys from env or files
- Write an encrypt→decrypt round-trip test with your production key
- Alert on 'invalid padding' spikes — they usually mean config drift
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
- ciphertext too short
- ciphertext length is not a multiple of AES block size
- plaintext too short
- message length mismatch
- decrypt message: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/97949b8ffc45fedc.
Report an issue: GitHub.