qnc-server-tob/pkg/lzkit/crypto/README.md
2025-04-08 12:49:19 +08:00

236 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# AES 加密工具包
本包提供了多种加密方式,特别是用于处理敏感个人信息(如手机号、身份证号等)的加密和解密功能。
## 主要功能
- **AES-CBC 模式加密/解密** - 标准加密模式,适用于一般数据加密
- **AES-ECB 模式加密/解密** - 确定性加密模式,适用于数据库字段加密和查询
- **专门针对个人敏感信息的加密/解密方法**
- **密钥生成和管理工具**
## 安全性说明
- **AES-CBC 模式**:使用随机 IV相同明文每次加密结果不同安全性较高
- **AES-ECB 模式**:确定性加密,相同明文每次加密结果相同,便于数据库查询,但安全性较低
> **⚠️ 警告**ECB 模式仅适用于短文本(如手机号、身份证号)的确定性加密,不建议用于加密大段文本或高安全需求场景。
## 使用示例
### 1. 加密手机号
使用 AES-ECB 模式加密手机号,保证确定性(相同手机号总是产生相同密文)
```go
import (
"fmt"
"tydata-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: user-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)
// 其余逻辑...
}
```