package main import ( "crypto/aes" "crypto/cipher" "crypto/md5" "encoding/hex" "fmt" "strings" ) // crypto.go - AES-CBC 加密/解密 + MD5 签名(与 FasterLZU APP 行为一致) // 密钥必须通过环境变量 LZU_AES_KEY / LZU_MD5_KEY 提供(16 字节) var ( aesKey = envOr("LZU_AES_KEY", "") // 16 字节,由部署环境注入 md5Key = envOr("LZU_MD5_KEY", "") ) // aesEncrypt 使用 AES-CBC,IV=key,零填充,输出小写 hex func aesEncrypt(plaintext string) (string, error) { key := []byte(aesKey) if len(key) != 16 { return "", fmt.Errorf("AES key 长度不是 16 字节") } block, err := aes.NewCipher(key) if err != nil { return "", err } data := []byte(plaintext) // 零填充到 blockSize 的整数倍 blockSize := aes.BlockSize paddedLen := len(data) if paddedLen%blockSize != 0 { paddedLen = len(data) + (blockSize - len(data)%blockSize) } padded := make([]byte, paddedLen) copy(padded, data) // 剩余部分保持 0x00(零填充) iv := key mode := cipher.NewCBCEncrypter(block, iv) ciphertext := make([]byte, paddedLen) mode.CryptBlocks(ciphertext, padded) return hex.EncodeToString(ciphertext), nil } // aesDecrypt AES-CBC 解密,去除尾部零填充 func aesDecrypt(hexStr string) (string, error) { key := []byte(aesKey) if len(key) != 16 { return "", fmt.Errorf("AES key 长度不是 16 字节") } encrypted, err := hex.DecodeString(hexStr) if err != nil { return "", err } block, err := aes.NewCipher(key) if err != nil { return "", err } iv := key mode := cipher.NewCBCDecrypter(block, iv) decrypted := make([]byte, len(encrypted)) mode.CryptBlocks(decrypted, encrypted) // 去除尾部零填充 validLen := len(decrypted) for i := len(decrypted) - 1; i >= 0 && i >= len(decrypted)-16; i-- { if decrypted[i] != 0 { break } validLen-- } return string(decrypted[:validLen]), nil } // md5Encrypt 签名: 参数值以 | 连接,末尾拼接 key,返回 MD5 hex func md5Encrypt(params []string, key string) string { data := strings.Join(params, "|") + "|" + key sum := md5.Sum([]byte(data)) return hex.EncodeToString(sum[:]) }