Tencent/WeKnora · error
aes key too short: %d bytes
Error message
aes key too short: %d bytes
What it means
decryptAESCBC rejects AES keys shorter than 16 bytes because Go's crypto/aes only supports 16-, 24-, or 32-byte keys. The WeCom aeskey is expected to be base64 of a 16-byte (AES-128) key; fewer bytes means the key was decoded wrong or truncated.
Source
Thrown at internal/im/wecom/ws_adapter.go:143
return io.NopCloser(bytes.NewReader(decrypted)), fileName, nil
}
// decryptAESCBC decrypts data encrypted with AES-256-CBC using PKCS#7 padding.
// The aesKeyB64 is the base64-encoded AES key provided per-message by WeCom.
// IV is the first 16 bytes of the decoded AES key.
func decryptAESCBC(ciphertext []byte, aesKeyB64 string) ([]byte, error) {
// WeCom's per-message aeskey is base64-encoded (43 chars → 32 bytes after decode)
aesKey, err := base64.StdEncoding.DecodeString(aesKeyB64 + "=")
if err != nil {
// Try without padding
aesKey, err = base64.RawStdEncoding.DecodeString(aesKeyB64)
if err != nil {
return nil, fmt.Errorf("base64 decode aes key: %w", err)
}
}
if len(aesKey) < 16 {
return nil, fmt.Errorf("aes key too short: %d bytes", len(aesKey))
}
block, err := aes.NewCipher(aesKey)
if err != nil {
return nil, fmt.Errorf("new aes cipher: %w", err)
}
if len(ciphertext) < aes.BlockSize {
return nil, fmt.Errorf("ciphertext too short: %d bytes", len(ciphertext))
}
if len(ciphertext)%aes.BlockSize != 0 {
return nil, fmt.Errorf("ciphertext not a multiple of block size: %d bytes", len(ciphertext))
}
// IV = first 16 bytes of the AES key
iv := aesKey[:aes.BlockSize]
mode := cipher.NewCBCDecrypter(block, iv)
plaintext := make([]byte, len(ciphertext))View on GitHub (pinned to 988cbb0330)
Solutions
- Verify the message's aeskey is valid base64 decoding to exactly 16 bytes; re-read it from the original message.
- Check that decryptAESCBC actually base64-decodes the key before the length check (the error prints the decoded length).
- Never truncate or trim the key string when storing/parsing messages.
- If the key is genuinely short, the message is corrupt — re-fetch the message from WeCom.
Example fix
// before
key, _ := base64.StdEncoding.DecodeString(strings.TrimSpace(msg.AesKey))
// after
key, err := base64.StdEncoding.DecodeString(msg.AesKey)
if err != nil || len(key) != 16 {
return fmt.Errorf("invalid aes key: decoded %d bytes", len(key))
} Defensive patterns
Strategy: validation
Validate before calling
decoded, err := base64.StdEncoding.DecodeString(msg.AesKey)
if err != nil || len(decoded) < 16 {
return fmt.Errorf("refusing to decrypt: aes key decodes to %d bytes", len(decoded))
} Type guard
func isUsableAESKey(key []byte) bool {
return len(key) == 16 || len(key) == 24 || len(key) == 32
} Try / catch
rc, name, err := adapter.DownloadFile(ctx, msg)
if err != nil && strings.Contains(err.Error(), "aes key too short") {
// corrupt/mis-parsed message: re-fetch or skip
} Prevention
- Never trim, truncate, or hand-edit the aeskey string.
- Confirm the key is base64-decoded before use; check decoded length is 16/24/32.
- Re-fetch the message if the key looks malformed rather than guessing.
- Guard parsing code so field shifts can't silently shorten the key.
When it happens
Trigger: Calling decryptAESCBC (via DownloadFile) with an aesKey that decodes to fewer than 16 bytes — e.g. malformed base64 handled by a path that didn't error, a truncated key string, or passing the base64 string raw instead of decoded bytes.
Common situations: Manually trimmed/padded key stored in config; passing the base64-encoded key literally as the key bytes; WeCom SDK or message format change altering the aeskey field; copy/paste dropping characters.
Related errors
- decrypt file: %w
- ciphertext too short
- ciphertext length is not a multiple of AES block size
- invalid padding
- plaintext too short
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/c49a57561b7f0cd9.
Report an issue: GitHub.