.. | ||
bcrypt.go | ||
crypto_test.go | ||
crypto_url.go | ||
crypto.go | ||
ecb_test.go | ||
ecb.go | ||
generate.go | ||
README.md | ||
west_crypto.go |
AES 加密工具包
本包提供了多种加密方式,特别是用于处理敏感个人信息(如手机号、身份证号等)的加密和解密功能。
主要功能
- AES-CBC 模式加密/解密 - 标准加密模式,适用于一般数据加密
- AES-ECB 模式加密/解密 - 确定性加密模式,适用于数据库字段加密和查询
- 专门针对个人敏感信息的加密/解密方法
- 密钥生成和管理工具
安全性说明
- AES-CBC 模式:使用随机 IV,相同明文每次加密结果不同,安全性较高
- AES-ECB 模式:确定性加密,相同明文每次加密结果相同,便于数据库查询,但安全性较低
⚠️ 警告:ECB 模式仅适用于短文本(如手机号、身份证号)的确定性加密,不建议用于加密大段文本或高安全需求场景。
使用示例
1. 加密手机号
使用 AES-ECB 模式加密手机号,保证确定性(相同手机号总是产生相同密文):
import (
"fmt"
"qnc-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. 在数据库中存储和查询加密手机号
// 加密并存储手机号
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. 加密身份证号
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. 密钥管理
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 参数)
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 项目中,建议将加密密钥放在配置文件中:
- 在配置文件中添加密钥配置:
# etc/main.yaml
Name: main-api
Host: 0.0.0.0
Port: 8888
Encrypt:
MobileKey: "1234567890abcdef" # 16字节AES-128密钥
IDCardKey: "1234567890abcdef1234567890abcdef" # 32字节AES-256密钥
- 在配置结构中定义:
type Config struct {
rest.RestConf
Encrypt struct {
MobileKey string
IDCardKey string
}
}
- 在服务上下文中使用:
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),
}
}
- 在 Logic 中使用:
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)
// 其余逻辑...
}