fish2018/pansou · error
ciphertext too short
Error message
ciphertext too short
What it means
The AES-GCM decryption helper (decrypt, near plugin/qqpd/qqpd.go:2350) validates that the supplied ciphertext is at least as long as the GCM nonce size (12 bytes) before attempting gcm.Open. A shorter input can never be valid GCM output, so it fails fast with "ciphertext too short" instead of a confusing crypto error.
Solutions
- Verify the input being decrypted is the exact encrypted output (base64 of nonce+ciphertext), not plaintext or a URL-decoded fragment.
- Check for accidental encoding round-trips (e.g. base64 decoded twice) that shorten the payload.
- Re-generate/re-store the encrypted credential with the same encrypt helper.
- Confirm you are decrypting the right field — a wrong config key often yields an empty or short value.
Example fix
// before
data, _ := base64.StdEncoding.DecodeString(input) // error ignored
cleartext, err := decrypt(key, data)
// after
data, err := base64.StdEncoding.DecodeString(input)
if err != nil {
return "", fmt.Errorf("bad ciphertext encoding: %w", err)
}
cleartext, err := decrypt(key, data)
if err != nil && strings.Contains(err.Error(), "ciphertext too short") {
return "", fmt.Errorf("credential looks unencrypted or truncated; re-save it")
} Defensive patterns
Strategy: validation
Validate before calling
decoded, err := base64.StdEncoding.DecodeString(ciphertextB64)
if err != nil || len(decoded) < 12 {
return fmt.Errorf("credential is not valid encrypted data (len=%d)", len(decoded))
} Type guard
func looksEncrypted(s string) bool {
b, err := base64.StdEncoding.DecodeString(s)
return err == nil && len(b) >= 12
} Try / catch
plain, err := decrypt(key, data)
if err != nil {
if strings.Contains(err.Error(), "ciphertext too short") {
// value was stored unencrypted or truncated — prompt re-save
} else {
// wrong key or corrupted data
}
} Prevention
- Always base64-encode ciphertext at write time and decode at read time
- Store a version/format marker alongside encrypted fields
- Never skip the error from base64 decoding before decrypting
- Verify key material is identical between encrypt and decrypt sides
When it happens
Trigger: Passing an empty string/byte slice, a plaintext value, or a truncated base64 payload to the decrypt function — anything shorter than gcm.NonceSize() (12) bytes after decoding.
Common situations: Config/cookie field stored unencrypted or re-encoded (e.g. double base64 decode stripping bytes); credential file truncated or partially written; wrong field passed to decrypt.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/6cfe458e45d2c003.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/qqpd/qqpd.go:2350
ciphertext, err := base64.StdEncoding.DecodeString(encrypted)
if err != nil {
return "", err
}
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
return "", fmt.Errorf("ciphertext too short")
}
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return "", err
}
return string(plaintext), nil
}
// ============ 定期清理 ============
// startCleanupTask 定期清理任务
func (p *QQPDPlugin) startCleanupTask() {
ticker := time.NewTicker(24 * time.Hour)
for range ticker.C {
deleted := p.cleanupExpiredUsers()View on GitHub (pinned to beaa561337)