feat: 核心电费查询 Go 服务
- FasterLZU 登录 + xiaofubao 6 步电费链路 - shiroJID 会话缓存 + 每日记录存储 - 定时任务: 每天 00:00 记录, 失败重试 5 次 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
82
go/crypto.go
Normal file
82
go/crypto.go
Normal file
@@ -0,0 +1,82 @@
|
||||
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[:])
|
||||
}
|
||||
Reference in New Issue
Block a user