chenhg5/cc-connect · error
ciphertext length %d not aligned to block
Error message
ciphertext length %d not aligned to block
What it means
After the key check, decryptAESECB verifies len(ciphertext)%aes.BlockSize==0; AES operates on 16-byte blocks and ECB mode cannot handle a partial final block, so a non-aligned ciphertext returns 'ciphertext length %d not aligned to block'. This almost always indicates an incomplete or corrupted download rather than a padding problem (padding is checked later by pkcs7Unpad).
Source
Thrown at platform/weixin/cdn.go:77
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
padded := pkcs7Pad(plaintext, aes.BlockSize)
out := make([]byte, len(padded))
for i := 0; i < len(padded); i += aes.BlockSize {
block.Encrypt(out[i:i+aes.BlockSize], padded[i:i+aes.BlockSize])
}
return out, nil
}
func decryptAESECB(ciphertext, key []byte) ([]byte, error) {
if len(key) != 16 {
return nil, fmt.Errorf("aes key must be 16 bytes, got %d", len(key))
}
if len(ciphertext)%aes.BlockSize != 0 {
return nil, fmt.Errorf("ciphertext length %d not aligned to block", len(ciphertext))
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
out := make([]byte, len(ciphertext))
for i := 0; i < len(ciphertext); i += aes.BlockSize {
block.Decrypt(out[i:i+aes.BlockSize], ciphertext[i:i+aes.BlockSize])
}
return pkcs7Unpad(out, aes.BlockSize)
}
// parseAesKey decodes CDNMedia.aes_key: base64(raw 16 bytes) or base64(32-char hex ASCII) → 16 bytes.
func parseAesKey(aesKeyBase64, label string) ([]byte, error) {
decoded, err := base64.StdEncoding.DecodeString(strings.TrimSpace(aesKeyBase64))
if err != nil {
return nil, fmt.Errorf("%s: aes_key base64: %w", label, err)
}View on GitHub (pinned to 4000b2338a)
Solutions
- Re-download the CDN media and verify the byte count matches the expected file size before decrypting
- Check HTTP status and Content-Length of the CDN response before ReadAll completes
- Ensure the entire response body was read (io.ReadAll, no partial reads/slices)
- If the payload is genuinely unaligned, the data is not valid AES-ECB ciphertext — do not attempt decryption
Example fix
data, err := io.ReadAll(resp.Body)
if err != nil { return err }
if resp.StatusCode != 200 || int64(len(data)) != resp.ContentLength {
return fmt.Errorf("cdn: incomplete download (%d/%d bytes)", len(data), resp.ContentLength)
}
plain, err := decryptAESECB(data, key) Defensive patterns
Strategy: validation
Validate before calling
if len(data)%aes.BlockSize != 0 {
return fmt.Errorf("cdn: got %d bytes, not multiple of 16 — download incomplete", len(data))
}
plain, err := decryptAESECB(data, key) Try / catch
if plain, err := decryptAESECB(data, key); err != nil {
if strings.Contains(err.Error(), "not aligned to block") {
return redownloadWithVerification(media) // truncated body
}
return err
} Prevention
- Compare downloaded byte count to Content-Length and expected file size before decrypting
- Use resumable/verified downloads for large media
- Check resp.StatusCode == 200 and content type before treating the body as ciphertext
- Avoid retry logic that appends partial bodies instead of replacing them
When it happens
Trigger: downloadAndDecryptCDN received a truncated body (connection dropped mid-download, Content-Length mismatch); the CDN returned a partial/error response; the caller sliced the ciphertext incorrectly before decrypting; empty ciphertext (len 0 is aligned, so this fires for lengths like 1..15 mod 16).
Common situations: Flaky network during large media download; proxy truncating the response; reading only part of resp.Body; retry logic that appended partial chunks.
Related errors
- invalid padded length %d
- aes key must be 16 bytes, got %d
- wecom-ws: aeskey decoded length %d, need >= 32
- invalid pkcs7 padding
- %s: aes_key base64: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/d5673c26ab5600f3.
Report an issue: GitHub.