# AES 加密工具包

本包提供了多种加密方式，特别是用于处理敏感个人信息(如手机号、身份证号等)的加密和解密功能。

## 主要功能

-   **AES-CBC 模式加密/解密** - 标准加密模式，适用于一般数据加密
-   **AES-ECB 模式加密/解密** - 确定性加密模式，适用于数据库字段加密和查询
-   **专门针对个人敏感信息的加密/解密方法**
-   **密钥生成和管理工具**

## 安全性说明

-   **AES-CBC 模式**：使用随机 IV，相同明文每次加密结果不同，安全性较高
-   **AES-ECB 模式**：确定性加密，相同明文每次加密结果相同，便于数据库查询，但安全性较低

> **⚠️ 警告**：ECB 模式仅适用于短文本(如手机号、身份证号)的确定性加密，不建议用于加密大段文本或高安全需求场景。

## 使用示例

### 1. 加密手机号

使用 AES-ECB 模式加密手机号，保证确定性(相同手机号总是产生相同密文)：

```go
import (
    "fmt"
    "jnc-server/pkg/lzkit/crypto"
)

func encryptMobileExample() {
    // 您的密钥(需安全保存，建议存储在配置中)
    key := []byte("1234567890abcdef") // 16字节AES-128密钥

    // 加密手机号
    mobile := "13800138000"
    encryptedMobile, err := crypto.EncryptMobile(mobile, key)
    if err != nil {
        panic(err)
    }

    fmt.Println("加密后的手机号:", encryptedMobile)

    // 解密手机号
    decryptedMobile, err := crypto.DecryptMobile(encryptedMobile, key)
    if err != nil {
        panic(err)
    }

    fmt.Println("解密后的手机号:", decryptedMobile)
}
```

### 2. 在数据库中存储和查询加密手机号

```go
// 加密并存储手机号
func saveUser(db *sqlx.DB, mobile string, key []byte) (int64, error) {
    encryptedMobile, err := crypto.EncryptMobile(mobile, key)
    if err != nil {
        return 0, err
    }

    var id int64
    err = db.QueryRow(
        "INSERT INTO users (mobile, create_time) VALUES (?, NOW()) RETURNING id",
        encryptedMobile,
    ).Scan(&id)

    return id, err
}

// 根据手机号查询用户
func findUserByMobile(db *sqlx.DB, mobile string, key []byte) (*User, error) {
    encryptedMobile, err := crypto.EncryptMobile(mobile, key)
    if err != nil {
        return nil, err
    }

    var user User
    err = db.QueryRow(
        "SELECT id, mobile, create_time FROM users WHERE mobile = ?",
        encryptedMobile,
    ).Scan(&user.ID, &user.EncryptedMobile, &user.CreateTime)

    if err != nil {
        return nil, err
    }

    // 解密手机号用于显示
    user.Mobile, _ = crypto.DecryptMobile(user.EncryptedMobile, key)

    return &user, nil
}
```

### 3. 加密身份证号

```go
func encryptIDCardExample() {
    key := []byte("1234567890abcdef")

    idCard := "440101199001011234"
    encryptedIDCard, err := crypto.EncryptIDCard(idCard, key)
    if err != nil {
        panic(err)
    }

    fmt.Println("加密后的身份证号:", encryptedIDCard)

    // 解密身份证号
    decryptedIDCard, err := crypto.DecryptIDCard(encryptedIDCard, key)
    if err != nil {
        panic(err)
    }

    fmt.Println("解密后的身份证号:", decryptedIDCard)
}
```

### 4. 密钥管理

```go
func keyManagementExample() {
    // 生成随机密钥
    key, err := crypto.GenerateAESKey(16) // AES-128
    if err != nil {
        panic(err)
    }
    fmt.Printf("生成的密钥(十六进制): %x\n", key)

    // 从密码派生密钥(便于记忆)
    password := "my-secure-password"
    derivedKey, err := crypto.DeriveKeyFromPassword(password, 16)
    if err != nil {
        panic(err)
    }
    fmt.Printf("从密码派生的密钥: %x\n", derivedKey)
}
```

### 5. 使用十六进制输出(适用于 URL 参数)

```go
func hexEncodingExample() {
    key := []byte("1234567890abcdef")
    mobile := "13800138000"

    // 使用十六进制编码(适合URL参数)
    encryptedHex, err := crypto.EncryptMobileHex(mobile, key)
    if err != nil {
        panic(err)
    }

    fmt.Println("十六进制编码的加密手机号:", encryptedHex)

    // 解密十六进制编码的手机号
    decryptedMobile, err := crypto.DecryptMobileHex(encryptedHex, key)
    if err != nil {
        panic(err)
    }

    fmt.Println("解密后的手机号:", decryptedMobile)
}
```

## 在 Go-Zero 项目中使用

在 Go-Zero 项目中，建议将加密密钥放在配置文件中：

1. 在配置文件中添加密钥配置：

```yaml
# etc/main.yaml
Name: main-api
Host: 0.0.0.0
Port: 8888

Encrypt:
    MobileKey: "1234567890abcdef" # 16字节AES-128密钥
    IDCardKey: "1234567890abcdef1234567890abcdef" # 32字节AES-256密钥
```

2. 在配置结构中定义：

```go
type Config struct {
    rest.RestConf
    Encrypt struct {
        MobileKey string
        IDCardKey string
    }
}
```

3. 在服务上下文中使用：

```go
type ServiceContext struct {
    Config      config.Config
    UserModel   model.UserModel
    MobileKey   []byte
    IDCardKey   []byte
}

func NewServiceContext(c config.Config) *ServiceContext {
    return &ServiceContext{
        Config:      c,
        UserModel:   model.NewUserModel(sqlx.NewMysql(c.DB.DataSource), c.Cache),
        MobileKey:   []byte(c.Encrypt.MobileKey),
        IDCardKey:   []byte(c.Encrypt.IDCardKey),
    }
}
```

4. 在 Logic 中使用：

```go
func (l *RegisterLogic) Register(req *types.RegisterReq) (*types.RegisterResp, error) {
    // 加密手机号用于存储
    encryptedMobile, err := crypto.EncryptMobile(req.Mobile, l.svcCtx.MobileKey)
    if err != nil {
        return nil, errors.New("手机号加密失败")
    }

    // 保存到数据库
    user := &model.User{
        Mobile: encryptedMobile,
        // 其他字段...
    }

    result, err := l.svcCtx.UserModel.Insert(l.ctx, nil, user)
    // 其余逻辑...
}
```
