package crypto import ( "crypto/aes" "crypto/md5" "crypto/rand" "encoding/base64" "encoding/hex" "errors" "fmt" ) // ECB模式是一种基本的加密模式,每个明文块独立加密 // 警告:ECB模式存在安全问题,仅用于需要确定性加密的场景,如数据库字段查询 // 不要用于加密大段文本或安全要求高的场景 // 验证密钥长度是否有效 (AES-128, AES-192, AES-256) func validateAESKey(key []byte) error { switch len(key) { case 16, 24, 32: return nil default: return errors.New("AES密钥长度必须是16、24或32字节(对应AES-128、AES-192、AES-256)") } } // AesEcbEncrypt AES-ECB模式加密,返回Base64编码的密文 // 使用已有的ECB实现,但提供更易用的接口 func AesEcbEncrypt(plainText, key []byte) (string, error) { if err := validateAESKey(key); err != nil { return "", err } block, err := aes.NewCipher(key) if err != nil { return "", err } // 使用PKCS7填充 plainText = PKCS7Padding(plainText, block.BlockSize()) // 创建密文数组 cipherText := make([]byte, len(plainText)) // ECB模式加密,使用west_crypto.go中已有的实现 mode := newECBEncrypter(block) mode.CryptBlocks(cipherText, plainText) // 返回Base64编码的密文 return base64.StdEncoding.EncodeToString(cipherText), nil } // AesEcbDecrypt AES-ECB模式解密,输入Base64编码的密文 func AesEcbDecrypt(cipherTextBase64 string, key []byte) ([]byte, error) { if err := validateAESKey(key); err != nil { return nil, err } // Base64解码 cipherText, err := base64.StdEncoding.DecodeString(cipherTextBase64) if err != nil { return nil, err } block, err := aes.NewCipher(key) if err != nil { return nil, err } // 检查密文长度 if len(cipherText)%block.BlockSize() != 0 { return nil, errors.New("密文长度必须是块大小的整数倍") } // 创建明文数组 plainText := make([]byte, len(cipherText)) // ECB模式解密,使用west_crypto.go中已有的实现 mode := newECBDecrypter(block) mode.CryptBlocks(plainText, cipherText) // 去除PKCS7填充 plainText, err = PKCS7UnPadding(plainText) if err != nil { return nil, err } return plainText, nil } // AesEcbEncryptHex AES-ECB模式加密,返回十六进制编码的密文 func AesEcbEncryptHex(plainText, key []byte) (string, error) { if err := validateAESKey(key); err != nil { return "", err } block, err := aes.NewCipher(key) if err != nil { return "", err } // 使用PKCS7填充 plainText = PKCS7Padding(plainText, block.BlockSize()) // 创建密文数组 cipherText := make([]byte, len(plainText)) // ECB模式加密 mode := newECBEncrypter(block) mode.CryptBlocks(cipherText, plainText) // 返回十六进制编码的密文 return hex.EncodeToString(cipherText), nil } // AesEcbDecryptHex AES-ECB模式解密,输入十六进制编码的密文 func AesEcbDecryptHex(cipherTextHex string, key []byte) ([]byte, error) { if err := validateAESKey(key); err != nil { return nil, err } // 十六进制解码 cipherText, err := hex.DecodeString(cipherTextHex) if err != nil { return nil, err } block, err := aes.NewCipher(key) if err != nil { return nil, err } // 检查密文长度 if len(cipherText)%block.BlockSize() != 0 { return nil, errors.New("密文长度必须是块大小的整数倍") } // 创建明文数组 plainText := make([]byte, len(cipherText)) // ECB模式解密 mode := newECBDecrypter(block) mode.CryptBlocks(plainText, cipherText) // 去除PKCS7填充 plainText, err = PKCS7UnPadding(plainText) if err != nil { return nil, err } return plainText, nil } // 以下是专门用于处理手机号等敏感数据的实用函数 // EncryptMobile 使用AES-ECB加密手机号,返回Base64编码 // 该方法保证对相同手机号总是产生相同密文,便于数据库查询 func EncryptMobile(mobile string, secretKey string) (string, error) { key, decodeErr := hex.DecodeString(secretKey) if decodeErr != nil { return "", decodeErr } if mobile == "" { return "", errors.New("手机号不能为空") } return AesEcbEncrypt([]byte(mobile), key) } // DecryptMobile 解密手机号 func DecryptMobile(encryptedMobile string, secretKey string) (string, error) { key, decodeErr := hex.DecodeString(secretKey) if decodeErr != nil { return "", decodeErr } if encryptedMobile == "" { return "", errors.New("加密手机号不能为空") } bytes, err := AesEcbDecrypt(encryptedMobile, key) if err != nil { return "", fmt.Errorf("解密手机号失败: %v", err) } return string(bytes), nil } // EncryptMobileHex 使用AES-ECB加密手机号,返回十六进制编码(适用于URL参数) func EncryptMobileHex(mobile string, key []byte) (string, error) { if mobile == "" { return "", errors.New("手机号不能为空") } return AesEcbEncryptHex([]byte(mobile), key) } // DecryptMobileHex 解密十六进制编码的手机号 func DecryptMobileHex(encryptedMobileHex string, key []byte) (string, error) { if encryptedMobileHex == "" { return "", errors.New("加密手机号不能为空") } bytes, err := AesEcbDecryptHex(encryptedMobileHex, key) if err != nil { return "", fmt.Errorf("解密手机号失败: %v", err) } return string(bytes), nil } // EncryptIDCard 使用AES-ECB加密身份证号 func EncryptIDCard(idCard string, key []byte) (string, error) { if idCard == "" { return "", errors.New("身份证号不能为空") } return AesEcbEncrypt([]byte(idCard), key) } // DecryptIDCard 解密身份证号 func DecryptIDCard(encryptedIDCard string, key []byte) (string, error) { if encryptedIDCard == "" { return "", errors.New("加密身份证号不能为空") } bytes, err := AesEcbDecrypt(encryptedIDCard, key) if err != nil { return "", fmt.Errorf("解密身份证号失败: %v", err) } return string(bytes), nil } // IsEncrypted 检查字符串是否为Base64编码的加密数据 func IsEncrypted(data string) bool { // 检查是否是有效的Base64编码 _, err := base64.StdEncoding.DecodeString(data) return err == nil && len(data) >= 20 // 至少20个字符的Base64字符串 } // GenerateAESKey 生成AES密钥 // keySize: 可选16, 24, 32字节(对应AES-128, AES-192, AES-256) func GenerateAESKey(keySize int) ([]byte, error) { if keySize != 16 && keySize != 24 && keySize != 32 { return nil, errors.New("密钥长度必须是16、24或32字节") } key := make([]byte, keySize) _, err := rand.Read(key) if err != nil { return nil, err } return key, nil } // DeriveKeyFromPassword 基于密码派生固定长度的AES密钥 func DeriveKeyFromPassword(password string, keySize int) ([]byte, error) { if keySize != 16 && keySize != 24 && keySize != 32 { return nil, errors.New("密钥长度必须是16、24或32字节") } // 使用PBKDF2或简单的方法从密码派生密钥 // 这里使用简单的MD5方法,实际生产环境应使用更安全的PBKDF2 hash := md5.New() hash.Write([]byte(password)) key := hash.Sum(nil) // 16字节 // 如果需要24或32字节,继续哈希 if keySize > 16 { hash.Reset() hash.Write(key) key = append(key, hash.Sum(nil)[:keySize-16]...) } return key, nil }