fish2018/pansou · error

无效的填充长度

Error message

无效的填充长度: %d

What it means

removePKCS7Padding reads the last plaintext byte as the padding length and validates it is in [1, min(len(data), aes.BlockSize)]. If the value is 0, larger than the data, or larger than one AES block, the padding is structurally invalid and the function fails with 无效的填充长度. This is a strong signal that decryption produced garbage — typically a wrong AES key/IV.

Solutions

  1. Verify AESKey/AESIV are current for the SDSO site; wrong-key garbage decryption is the dominant cause.
  2. Re-fetch a fresh encrypted URL rather than decrypting cached/stale data.
  3. Hex-dump the decrypted plaintext and confirm the last byte looks like padding (a small 1..16 value); if random, fix the key/IV, not the padding logic.
  4. Confirm the upstream scheme is actually AES-CBC + PKCS7; if the site switched modes (e.g. GCM or no padding), update DecryptURL accordingly.

Example fix

// before
plaintext := make([]byte, len(ciphertext))
mode.CryptBlocks(plaintext, ciphertext)
unpaddedText, err := removePKCS7Padding(plaintext)
// after
plaintext := make([]byte, len(ciphertext))
mode.CryptBlocks(plaintext, ciphertext)
last := int(plaintext[len(plaintext)-1])
if last == 0 || last > aes.BlockSize || last > len(plaintext) {
    return "", fmt.Errorf("decryption produced invalid padding %d — likely wrong AESKey/AESIV", last)
}
unpaddedText, err := removePKCS7Padding(plaintext)
Defensive patterns

Strategy: validation

Validate before calling

if len(plain) > 0 {
    p := int(plain[len(plain)-1])
    if p == 0 || p > 16 || p > len(plain) {
        return fmt.Errorf("invalid padding length %d — likely wrong key/IV", p)
    }
}

Try / catch

plain, err := DecryptURL(enc)
if err != nil {
    if strings.Contains(err.Error(), "无效的填充长度") {
        return refreshKeyAndRetry(enc) // reload current site key/IV
    }
    return err
}

Prevention

When it happens

Trigger: Decryption with mismatched AESKey/AESIV yields random-looking bytes whose last byte is an implausible padding length; ciphertext was corrupted in transit; input encrypted with a padding scheme other than PKCS7 (e.g. zero padding or no padding).

Common situations: SDSO site rotated keys so old constants decrypt to noise; cached encrypted URL from an older format; ciphertext passed through a transformation (URL decoding, charset conversion) that altered bytes.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/7878c06976e73ff6. Report an issue: GitHub.

Appendix: source

Thrown at plugin/sdso/sdso.go:437

	if err != nil {
		return "", fmt.Errorf("去除填充失败: %w", err)
	}

	return string(unpaddedText), nil
}

// removePKCS7Padding 去除PKCS7填充
func removePKCS7Padding(data []byte) ([]byte, error) {
	if len(data) == 0 {
		return nil, fmt.Errorf("数据为空")
	}

	// 获取填充长度
	paddingLen := int(data[len(data)-1])

	// 验证填充长度
	if paddingLen == 0 || paddingLen > len(data) || paddingLen > aes.BlockSize {
		return nil, fmt.Errorf("无效的填充长度: %d", paddingLen)
	}

	// 验证填充字节
	for i := len(data) - paddingLen; i < len(data); i++ {
		if data[i] != byte(paddingLen) {
			return nil, fmt.Errorf("无效的填充字节")
		}
	}

	// 返回去除填充后的数据
	return data[:len(data)-paddingLen], nil
}

// cleanHTMLTags 清理HTML标签
func cleanHTMLTags(text string) string {
	// 移除高亮标签 <span style="color: red;">...</span>
	re := regexp.MustCompile(`<span[^>]*>(.*?)</span>`)
	cleaned := re.ReplaceAllString(text, "$1")

View on GitHub (pinned to beaa561337)