package cpdaily import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/des" "crypto/rand" "encoding/base64" "encoding/hex" "fmt" "math/big" "strings" ) // ========== AES-128-CBC-PKCS7 ========== var ( AesKey = []byte("fafUY9659kyengTR") AesKeyForCat = []byte("hru89rwr87Nthifa") AesIv = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7} ) func AesEncrypt(data []byte) []byte { return aesEncrypt(data, AesKey, AesIv) } func AesDecrypt(data []byte) []byte { return aesDecrypt(data, AesKey, AesIv) } func AesEncryptForCat(data []byte) []byte { return aesEncrypt(data, AesKeyForCat, AesIv) } func AesDecryptForCat(data []byte) []byte { return aesDecrypt(data, AesKeyForCat, AesIv) } func aesEncrypt(data, key, iv []byte) []byte { block, _ := aes.NewCipher(key) padded := pkcs7Pad(data, block.BlockSize()) ciphertext := make([]byte, len(padded)) mode := cipher.NewCBCEncrypter(block, iv) mode.CryptBlocks(ciphertext, padded) return ciphertext } func aesDecrypt(data, key, iv []byte) []byte { block, _ := aes.NewCipher(key) plaintext := make([]byte, len(data)) mode := cipher.NewCBCDecrypter(block, iv) mode.CryptBlocks(plaintext, data) return pkcs7Unpad(plaintext) } func pkcs7Pad(data []byte, blockSize int) []byte { padding := blockSize - len(data)%blockSize padText := bytes.Repeat([]byte{byte(padding)}, padding) return append(data, padText...) } func pkcs7Unpad(data []byte) []byte { if len(data) == 0 { return data } padLen := int(data[len(data)-1]) if padLen > len(data) || padLen == 0 { return data } return data[:len(data)-padLen] } // ========== CAS 登录密码加密 ========== // EncryptCasPassword AES-128-CBC 加密密码 // key=salt(从页面提取), iv=16位随机, 明文=64位随机字符串+密码, 输出base64 func EncryptCasPassword(password, salt string) string { const randStrLen = 64 const randIvLen = 16 randomIv := randomString(randIvLen) randomStr := randomString(randStrLen) plaintext := []byte(randomStr + password) key := []byte(salt) iv := []byte(randomIv) encrypted := aesEncrypt(plaintext, key, iv) return base64.StdEncoding.EncodeToString(encrypted) } // ========== RSA (IAP 登录用) ========== // 硬编码 IAP RSA 公钥 const IapRsaPubKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCpbRy8ZoyQvRPpUDIXycglTwVDcYrLcv7P9HI4E7/TAPZiI3GN0ckTUVVWRvoo/re3uCOOJK+F+Ufh19XiRIdoPYCULsSyEjcLLiyAS09mVOzhAQco84E/lM24T7rRTVID7LIgWPewyN8Nd5vzHET4Q3qTthoL8n82BwC1iXuVQIDAQAB" type RSAKeyPair struct { n *big.Int e *big.Int } func NewRSAKeyPairFromPublicKey(base64Key string) (*RSAKeyPair, error) { der, err := base64.StdEncoding.DecodeString(base64Key) if err != nil { return nil, fmt.Errorf("base64 decode error: %w", err) } // 简单的 DER 解析 (PKCS#1 Public Key) // 跳过 ASN.1 头部,提取 n 和 e return parsePKCS1PublicKey(der) } func parsePKCS1PublicKey(der []byte) (*RSAKeyPair, error) { // 简化的 PKCS#1 解析 // 实际上应该用 crypto/x509,但为了轻量级,手动解析 // 格式: SEQUENCE { SEQUENCE { OID, NULL }, BIT STRING { SEQUENCE { INTEGER n, INTEGER e } } } // 或者直接 PKCS#1: SEQUENCE { INTEGER n, INTEGER e } // 找最后的两个 INTEGER data := string(der) nParts := strings.Split(data, "\x02") if len(nParts) < 3 { return nil, fmt.Errorf("invalid RSA key format") } // 提取 n (倒数第二个 INTEGER) nBytes := extractIntegerBytes(nParts[len(nParts)-2]) // 提取 e (最后一个 INTEGER) eBytes := extractIntegerBytes(nParts[len(nParts)-1]) r := &RSAKeyPair{ n: new(big.Int).SetBytes(nBytes), e: new(big.Int).SetBytes(eBytes), } return r, nil } func extractIntegerBytes(s string) []byte { if len(s) == 0 { return nil } // 第一个字节是长度 data := []byte(s) if len(data) < 2 { return data } length := int(data[0]) if length > 128 { // 长格式 numLenBytes := length & 0x7F length = 0 for i := 1; i <= numLenBytes; i++ { length = length*256 + int(data[i]) } data = data[1+numLenBytes:] } else { data = data[1:] } if length > len(data) { length = len(data) } return data[:length] } func (r *RSAKeyPair) Encrypt(plaintext string) (string, error) { // PKCS#1 v1.5 加密 k := (r.n.BitLen() + 7) / 8 if k < 12 { return "", fmt.Errorf("key too short") } // 填充: 0x00 || 0x02 || PS || 0x00 || M // PS 是随机非零字节 plainBytes := []byte(plaintext) if len(plainBytes) > k-11 { return "", fmt.Errorf("plaintext too long") } padded := make([]byte, k) padded[0] = 0x00 padded[1] = 0x02 // PS: 随机非零字节 for i := 2; i < k-len(plainBytes)-1; i++ { bt := byte(0) for bt == 0 { b := make([]byte, 1) rand.Read(b) bt = b[0] } padded[i] = bt } padded[k-len(plainBytes)-1] = 0x00 copy(padded[k-len(plainBytes):], plainBytes) // c = m^e mod n m := new(big.Int).SetBytes(padded) c := new(big.Int).Exp(m, r.e, r.n) result := c.Text(16) if len(result)%2 != 0 { result = "0" + result } return result, nil } // ========== 工具函数 ========== func randomString(length int) string { const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" result := make([]byte, length) for i := 0; i < length; i++ { n, _ := rand.Read(make([]byte, 1)) result[i] = chars[int(n)%len(chars)] } return string(result) } func randomStringV2(length int) string { b := make([]byte, length) rand.Read(b) return hex.EncodeToString(b)[:length] } // ========== DES-CBC-PKCS7 (用于 Cpdaily-Extension) ========== var ( DesKeyForCat = []byte("b3L26XNL") DesIv = []byte{1, 2, 3, 4, 5, 6, 7, 8} ) func DesEncryptForCat(data []byte) []byte { block, _ := des.NewCipher(DesKeyForCat) padded := pkcs7Pad(data, block.BlockSize()) ciphertext := make([]byte, len(padded)) mode := cipher.NewCBCEncrypter(block, DesIv) mode.CryptBlocks(ciphertext, padded) return ciphertext }