Go 语言标准库 —— crypto/aes 包(AES 加密)
🔹 概述
crypto/aes 包实现了 AES(Advanced Encryption Standard)对称加密算法。
主要功能:
- AES-128、AES-192、AES-256 加密
- 支持多种工作模式(ECB、CBC、CTR、CFB、OFB、GCM)
- 硬件加速支持(现代 CPU)
重要说明:
- AES 是分组密码(Block Cipher)
- 分组大小固定为 128 位(16 字节)
- 密钥长度:128 位(16 字节)、192 位(24 字节)、256 位(32 字节)
- ✅ 推荐使用,安全性高
- 需要配合工作模式使用(推荐 GCM)
工作模式:
- GCM - 认证加密(推荐)
- CBC - 密码块链接(常用)
- CTR - 计数器模式(流式)
- CFB - 密码反馈模式
- OFB - 输出反馈模式
- ECB - 电子密码本(❌ 不安全,不推荐)
🔹 核心函数
创建 AES Cipher
aes.NewCipher(key []byte) (cipher.Block, error)
-
说明:
- 创建新的 AES cipher 实例
- 根据密钥长度自动选择 AES-128/192/256
-
参数:
key []byte- 密钥(16/24/32 字节)
-
返回值:
cipher.Block- AES cipher 接口error- 错误信息
-
错误情况:
- 密钥长度不正确(必须是 16、24 或 32 字节)
-
示例:
package main import ( "crypto/aes" "fmt" ) func main() { // AES-128(16 字节密钥) key128 := []byte("1234567890123456") block, err := aes.NewCipher(key128) if err != nil { fmt.Println("错误:", err) return } fmt.Printf("AES-%d 创建成功\n", block.BlockSize()*8) // AES-256(32 字节密钥) key256 := []byte("12345678901234567890123456789012") block, _ = aes.NewCipher(key256) fmt.Printf("AES-%d 创建成功\n", block.BlockSize()*8) }
🔹 工作模式
GCM 模式(推荐)
cipher.NewGCM(block cipher.Block) (cipher.AEAD, error)
-
说明:
- Galois/Counter Mode
- 提供认证加密(Authenticated Encryption)
- 同时保证机密性和完整性
- ✅ 推荐使用
-
特点:
- 加密 + 认证
- 高性能
- 需要 Nonce(唯一值)
- 自动生成认证标签
-
示例(完整):
package main import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/hex" "fmt" "io" ) // AES-GCM 加密 func encryptGCM(plaintext []byte, key []byte) ([]byte, error) { // 创建 cipher block, err := aes.NewCipher(key) if err != nil { return nil, err } // 创建 GCM mode gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } // 生成随机 nonce(12 字节) nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return nil, err } // 加密(包含 nonce 和认证标签) // Seal 方法:dst, nonce, plaintext, additionalData ciphertext := gcm.Seal(nonce, nonce, plaintext, nil) return ciphertext, nil } // AES-GCM 解密 func decryptGCM(ciphertext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonceSize := gcm.NonceSize() if len(ciphertext) < nonceSize { return nil, fmt.Errorf("密文太短") } // 分离 nonce 和密文 nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] // Open 方法:dst, nonce, ciphertext, additionalData plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) return plaintext, err } func main() { // 256 位密钥(32 字节) key := []byte("12345678901234567890123456789012") plaintext := []byte("Hello, AES-GCM!") // 加密 ciphertext, err := encryptGCM(plaintext, key) if err != nil { fmt.Println("加密失败:", err) return } fmt.Printf("密文:%s\n", hex.EncodeToString(ciphertext)) // 解密 decrypted, err := decryptGCM(ciphertext, key) if err != nil { fmt.Println("解密失败:", err) return } fmt.Printf("明文:%s\n", string(decrypted)) } -
使用场景:
- 文件加密存储
- 数据库字段加密
- 网络传输加密
- 密钥封装
CBC 模式
cipher.NewCBCEncrypter(block cipher.Block, iv []byte)
-
说明:
- Cipher Block Chaining
- 每个明文块与前一个密文块异或
- 需要初始化向量(IV)
- 需要填充(PKCS7)
-
特点:
- 仅加密,无认证
- 需要手动填充
- 串行加密,并行解密
-
示例(完整):
package main import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/hex" "fmt" "io" ) // PKCS7 填充 func pkcs7Pad(data []byte, blockSize int) []byte { padding := blockSize - len(data)%blockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(data, padtext...) } // PKCS7 去填充 func pkcs7Unpad(data []byte) ([]byte, error) { if len(data) == 0 { return nil, fmt.Errorf("数据为空") } padding := int(data[len(data)-1]) if padding > len(data) || padding == 0 { return nil, fmt.Errorf("无效的填充") } // 验证填充 for i := 0; i < padding; i++ { if data[len(data)-1-i] != byte(padding) { return nil, fmt.Errorf("无效的填充") } } return data[:len(data)-padding], nil } // AES-CBC 加密 func encryptCBC(plaintext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } // PKCS7 填充 plaintext = pkcs7Pad(plaintext, block.BlockSize()) // 生成随机 IV(16 字节) ciphertext := make([]byte, aes.BlockSize+len(plaintext)) iv := ciphertext[:aes.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { return nil, err } // CBC 加密 mode := cipher.NewCBCEncrypter(block, iv) mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext) return ciphertext, nil } // AES-CBC 解密 func decryptCBC(ciphertext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } if len(ciphertext) < aes.BlockSize { return nil, fmt.Errorf("密文太短") } // 分离 IV 和密文 iv := ciphertext[:aes.BlockSize] ciphertext = ciphertext[aes.BlockSize:] // CBC 解密 mode := cipher.NewCBCDecrypter(block, iv) mode.CryptBlocks(ciphertext, ciphertext) // 去填充 plaintext, err := pkcs7Unpad(ciphertext) return plaintext, err } func main() { key := []byte("12345678901234567890123456789012") plaintext := []byte("Hello, AES-CBC!") ciphertext, _ := encryptCBC(plaintext, key) fmt.Printf("密文:%s\n", hex.EncodeToString(ciphertext)) decrypted, _ := decryptCBC(ciphertext, key) fmt.Printf("明文:%s\n", string(decrypted)) } -
使用场景:
- 兼容旧系统
- 文件加密
- 需要串行加密的场景
CTR 模式
cipher.NewCTR(block cipher.Block, iv []byte)
-
说明:
- Counter Mode
- 将分组密码转换为流密码
- 不需要填充
- 支持并行加密/解密
-
特点:
- 仅加密,无认证
- 不需要填充
- 可并行处理
- 需要唯一的 Nonce
-
示例:
package main import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/hex" "fmt" "io" ) // AES-CTR 加密/解密(相同操作) func encryptCTR(plaintext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } // 生成随机 nonce(16 字节) ciphertext := make([]byte, aes.BlockSize+len(plaintext)) nonce := ciphertext[:aes.BlockSize] if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return nil, err } // CTR 模式(加密和解密相同) stream := cipher.NewCTR(block, nonce) stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) return ciphertext, nil } // AES-CTR 解密 func decryptCTR(ciphertext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } if len(ciphertext) < aes.BlockSize { return nil, fmt.Errorf("密文太短") } // 分离 nonce 和密文 nonce := ciphertext[:aes.BlockSize] ciphertext = ciphertext[aes.BlockSize:] // CTR 模式(解密相同) stream := cipher.NewCTR(block, nonce) plaintext := make([]byte, len(ciphertext)) stream.XORKeyStream(plaintext, ciphertext) return plaintext, nil } func main() { key := []byte("12345678901234567890123456789012") plaintext := []byte("Hello, AES-CTR!") ciphertext, _ := encryptCTR(plaintext, key) fmt.Printf("密文:%s\n", hex.EncodeToString(ciphertext)) decrypted, _ := decryptCTR(ciphertext, key) fmt.Printf("明文:%s\n", string(decrypted)) } -
使用场景:
- 流式数据加密
- 实时通信
- 磁盘加密
CFB 模式
cipher.NewCFBEncrypter(block cipher.Block, iv []byte)
-
说明:
- Cipher Feedback Mode
- 将分组密码转换为流密码
- 不需要填充
-
特点:
- 仅加密,无认证
- 自同步流密码
- 串行处理
-
示例:
package main import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/hex" "fmt" "io" ) // AES-CFB 加密 func encryptCFB(plaintext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } // 生成随机 IV ciphertext := make([]byte, aes.BlockSize+len(plaintext)) iv := ciphertext[:aes.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { return nil, err } // CFB 加密 stream := cipher.NewCFBEncrypter(block, iv) stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) return ciphertext, nil } // AES-CFB 解密 func decryptCFB(ciphertext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } if len(ciphertext) < aes.BlockSize { return nil, fmt.Errorf("密文太短") } // 分离 IV 和密文 iv := ciphertext[:aes.BlockSize] ciphertext = ciphertext[aes.BlockSize:] // CFB 解密 stream := cipher.NewCFBDecrypter(block, iv) plaintext := make([]byte, len(ciphertext)) stream.XORKeyStream(plaintext, ciphertext) return plaintext, nil } func main() { key := []byte("12345678901234567890123456789012") plaintext := []byte("Hello, AES-CFB!") ciphertext, _ := encryptCFB(plaintext, key) fmt.Printf("密文:%s\n", hex.EncodeToString(ciphertext)) decrypted, _ := decryptCFB(ciphertext, key) fmt.Printf("明文:%s\n", string(decrypted)) }
OFB 模式
cipher.NewOFB(block cipher.Block, iv []byte)
-
说明:
- Output Feedback Mode
- 将分组密码转换为流密码
- 不需要填充
-
特点:
- 仅加密,无认证
- 密钥流独立于消息
- 可预先计算密钥流
-
示例:
package main import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/hex" "fmt" "io" ) // AES-OFB 加密/解密(相同操作) func encryptOFB(plaintext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } // 生成随机 IV ciphertext := make([]byte, aes.BlockSize+len(plaintext)) iv := ciphertext[:aes.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { return nil, err } // OFB 模式(加密和解密相同) stream := cipher.NewOFB(block, iv) stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) return ciphertext, nil } // AES-OFB 解密 func decryptOFB(ciphertext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } if len(ciphertext) < aes.BlockSize { return nil, fmt.Errorf("密文太短") } iv := ciphertext[:aes.BlockSize] ciphertext = ciphertext[aes.BlockSize:] // OFB 模式(解密相同) stream := cipher.NewOFB(block, iv) plaintext := make([]byte, len(ciphertext)) stream.XORKeyStream(plaintext, ciphertext) return plaintext, nil }
🔹 密钥派生
从密码生成密钥
crypto/pbkdf2 或 golang.org/x/crypto/pbkdf2
-
说明:
- PBKDF2(Password-Based Key Derivation Function 2)
- 从密码派生固定长度的密钥
- 增加暴力破解难度
- 需要盐(Salt)和迭代次数
-
示例:
package main import ( "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/sha256" "encoding/hex" "fmt" "io" "golang.org/x/crypto/pbkdf2" ) // 从密码派生密钥 func deriveKey(password string, salt []byte) []byte { return pbkdf2.Key( []byte(password), salt, 100000, // 迭代次数 32, // 密钥长度(AES-256) sha256.New, ) } // 加密 func encryptWithPassword(plaintext []byte, password string) ([]byte, error) { // 生成随机盐 salt := make([]byte, 16) if _, err := io.ReadFull(rand.Reader, salt); err != nil { return nil, err } // 派生密钥 key := deriveKey(password, salt) // 创建 cipher block, err := aes.NewCipher(key) if err != nil { return nil, err } // 创建 GCM gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } // 生成 nonce nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return nil, err } // 加密(包含 salt、nonce 和密文) ciphertext := gcm.Seal(nil, nonce, plaintext, nil) result := append(salt, nonce...) result = append(result, ciphertext...) return result, nil } // 解密 func decryptWithPassword(ciphertext []byte, password string) ([]byte, error) { if len(ciphertext) < 16+12 { return nil, fmt.Errorf("密文太短") } // 提取 salt 和 nonce salt := ciphertext[:16] nonce := ciphertext[16:28] ciphertext = ciphertext[28:] // 派生密钥 key := deriveKey(password, salt) // 创建 cipher block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } // 解密 plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) return plaintext, err } func main() { password := "mySecurePassword123" plaintext := []byte("Secret message!") // 加密 encrypted, _ := encryptWithPassword(plaintext, password) fmt.Printf("密文:%s\n", hex.EncodeToString(encrypted)) // 解密 decrypted, _ := decryptWithPassword(encrypted, password) fmt.Printf("明文:%s\n", string(decrypted)) }
🔹 使用场景
1. 文件加密
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"io"
"os"
)
func encryptFile(inputPath, outputPath string, key []byte) error {
// 读取明文文件
plaintext, err := os.ReadFile(inputPath)
if err != nil {
return err
}
// 创建 cipher
block, err := aes.NewCipher(key)
if err != nil {
return err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return err
}
// 生成 nonce
nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return err
}
// 加密
ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
// 写入密文文件
return os.WriteFile(outputPath, ciphertext, 0600)
}
func decryptFile(inputPath, outputPath string, key []byte) error {
// 读取密文文件
ciphertext, err := os.ReadFile(inputPath)
if err != nil {
return err
}
block, err := aes.NewCipher(key)
if err != nil {
return err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return err
}
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
return fmt.Errorf("密文太短")
}
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
// 解密
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return err
}
return os.WriteFile(outputPath, plaintext, 0600)
}
func main() {
key := []byte("12345678901234567890123456789012")
// 加密文件
err := encryptFile("secret.txt", "secret.txt.enc", key)
if err != nil {
fmt.Println("加密失败:", err)
return
}
fmt.Println("加密成功")
// 解密文件
err = decryptFile("secret.txt.enc", "restored.txt", key)
if err != nil {
fmt.Println("解密失败:", err)
return
}
fmt.Println("解密成功")
}
2. 数据库字段加密
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"database/sql"
"encoding/hex"
"fmt"
"io"
_ "github.com/mattn/go-sqlite3"
)
type EncryptedDB struct {
db *sql.DB
key []byte
}
func NewEncryptedDB(dbPath string, key []byte) (*EncryptedDB, error) {
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
return nil, err
}
// 创建表
_, err = db.Exec(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
email TEXT,
ssn TEXT -- 加密的社会安全号
)
`)
if err != nil {
return nil, err
}
return &EncryptedDB{db: db, key: key}, nil
}
func (e *EncryptedDB) encrypt(data []byte) (string, error) {
block, err := aes.NewCipher(e.key)
if err != nil {
return "", err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return "", err
}
ciphertext := gcm.Seal(nonce, nonce, data, nil)
return hex.EncodeToString(ciphertext), nil
}
func (e *EncryptedDB) decrypt(hexCiphertext string) ([]byte, error) {
ciphertext, err := hex.DecodeString(hexCiphertext)
if err != nil {
return nil, err
}
block, err := aes.NewCipher(e.key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
return nil, fmt.Errorf("密文太短")
}
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
return gcm.Open(nil, nonce, ciphertext, nil)
}
func (e *EncryptedDB) InsertUser(email, ssn string) error {
encryptedSSN, err := e.encrypt([]byte(ssn))
if err != nil {
return err
}
_, err = e.db.Exec("INSERT INTO users (email, ssn) VALUES (?, ?)", email, encryptedSSN)
return err
}
func (e *EncryptedDB) GetUser(id int) (email, ssn string, err error) {
err = e.db.QueryRow("SELECT email, ssn FROM users WHERE id = ?", id).Scan(&email, &ssn)
if err != nil {
return
}
decryptedSSN, err := e.decrypt(ssn)
if err != nil {
return
}
ssn = string(decryptedSSN)
return
}
func main() {
key := []byte("12345678901234567890123456789012")
db, _ := NewEncryptedDB("users.db", key)
// 插入加密数据
db.InsertUser("alice@example.com", "123-45-6789")
// 查询并解密
email, ssn, _ := db.GetUser(1)
fmt.Printf("Email: %s, SSN: %s\n", email, ssn)
}
3. HTTP 请求体加密
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
)
type SecureClient struct {
key []byte
}
func (sc *SecureClient) encrypt(data interface{}) (string, error) {
jsonData, _ := json.Marshal(data)
block, err := aes.NewCipher(sc.key)
if err != nil {
return "", err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
nonce := make([]byte, gcm.NonceSize())
io.ReadFull(rand.Reader, nonce)
ciphertext := gcm.Seal(nonce, nonce, jsonData, nil)
return base64.StdEncoding.EncodeToString(ciphertext), nil
}
func (sc *SecureClient) decrypt(encoded string, result interface{}) error {
ciphertext, _ := base64.StdEncoding.DecodeString(encoded)
block, err := aes.NewCipher(sc.key)
if err != nil {
return err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return err
}
nonceSize := gcm.NonceSize()
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return err
}
return json.Unmarshal(plaintext, result)
}
func (sc *SecureClient) Post(url string, data interface{}) (*http.Response, error) {
encrypted, err := sc.encrypt(data)
if err != nil {
return nil, err
}
req, _ := http.NewRequest("POST", url, bytes.NewBufferString(encrypted))
req.Header.Set("Content-Type", "application/encrypted")
return http.DefaultClient.Do(req)
}
func main() {
client := &SecureClient{
key: []byte("12345678901234567890123456789012"),
}
// 发送加密数据
data := map[string]string{
"username": "alice",
"password": "secret123",
}
resp, _ := client.Post("https://api.example.com/login", data)
if resp != nil {
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("响应:%s\n", string(body))
}
}
🔹 注意事项和最佳实践
1. 密钥长度
- ✅ AES-128:16 字节密钥
- ✅ AES-192:24 字节密钥
- ✅ AES-256:32 字节密钥
- ⚠️ 密钥长度必须正确
// 正确
key128 := make([]byte, 16) // AES-128
key256 := make([]byte, 32) // AES-256
// 错误 - 会导致 panic
key := []byte("short") // 长度不正确
aes.NewCipher(key) // panic: crypto/aes: invalid key size
2. 选择 GCM 模式
- ✅ 优先使用 GCM 模式
- ✅ 提供认证加密
- ❌ 避免使用 ECB 模式(不安全)
// 推荐
gcm, _ := cipher.NewGCM(block)
ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
// 不推荐 - ECB 模式不安全
// ECB 会暴露数据模式
3. 随机数生成
- ✅ 使用 crypto/rand 生成 nonce/IV
- ❌ 不要重复使用 nonce(GCM)
- ❌ 不要重复使用 IV(CBC)
// 正确
nonce := make([]byte, gcm.NonceSize())
io.ReadFull(rand.Reader, nonce)
// 错误 - 固定 nonce 不安全
nonce := make([]byte, 12) // 全 0
4. 认证加密
- ✅ GCM 提供认证
- ✅ 验证解密结果
- ❌ CBC/CTR 无认证,需额外 HMAC
// GCM 自动认证
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
// 认证失败,数据可能被篡改
}
// CBC 需要额外 HMAC
hmac := computeHMAC(ciphertext, key2)
// 验证 hmac
5. 密钥管理
- ✅ 安全存储密钥
- ✅ 使用密钥管理服务(KMS)
- ✅ 定期轮换密钥
- ❌ 不要硬编码密钥
// 错误 - 硬编码密钥
key := []byte("my-secret-key-1234567890123456")
// 正确 - 从环境变量读取
key := []byte(os.Getenv("ENCRYPTION_KEY"))
// 正确 - 使用 KMS
key, _ := kms.Decrypt(encryptedKey)
6. 错误处理
- ✅ 检查所有错误
- ✅ 验证认证标签(GCM)
- ✅ 清理敏感数据
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
// 认证失败或解密错误
return nil, err
}
🔥 总结
核心函数
| 函数 | 说明 | 推荐度 |
|---|---|---|
| aes.NewCipher(key) | 创建 AES cipher | ✅ 必需 |
| cipher.NewGCM(block) | GCM 模式 | ✅ 强烈推荐 |
| cipher.NewCBCEncrypter(block, iv) | CBC 模式 | ⚠️ 常用 |
| cipher.NewCTR(block, iv) | CTR 模式 | ✅ 流式加密 |
| cipher.NewCFBEncrypter(block, iv) | CFB 模式 | ⚠️ 少用 |
| cipher.NewOFB(block, iv) | OFB 模式 | ⚠️ 少用 |
工作模式对比
| 模式 | 认证 | 填充 | 并行加密 | 并行解密 | 推荐度 |
|---|---|---|---|---|---|
| GCM | ✅ | ❌ | ✅ | ✅ | ✅ 强烈推荐 |
| CBC | ❌ | ✅ | ❌ | ✅ | ⚠️ 常用 |
| CTR | ❌ | ❌ | ✅ | ✅ | ✅ 推荐 |
| CFB | ❌ | ❌ | ❌ | ❌ | ⚠️ 少用 |
| OFB | ❌ | ❌ | ❌ | ✅ | ⚠️ 少用 |
| ECB | ❌ | ✅ | ✅ | ✅ | ❌ 不安全 |
密钥长度
| 类型 | 密钥长度 | 字节数 | 安全性 |
|---|---|---|---|
| AES-128 | 128 位 | 16 字节 | ✅ 高 |
| AES-192 | 192 位 | 24 字节 | ✅ 很高 |
| AES-256 | 256 位 | 32 字节 | ✅ 极高 |
主要特点
- 对称加密 👉 加密解密使用相同密钥
- 分组密码 👉 固定 128 位分组
- 硬件加速 👉 现代 CPU 支持 AES-NI
- 多种模式 👉 GCM、CBC、CTR 等
- 高性能 👉 软件/硬件实现都很高效
使用场景
- 文件加密 👉 GCM 模式
- 数据库加密 👉 GCM 模式
- 网络传输 👉 GCM/CTR 模式
- 流式加密 👉 CTR/CFB 模式
- 密钥封装 👉 GCM 模式
最佳实践
- ✅ 优先使用 GCM 模式
- ✅ 使用 AES-256(32 字节密钥)
- ✅ 使用 crypto/rand 生成 nonce/IV
- ✅ 不要重复使用 nonce
- ✅ 验证 GCM 认证标签
- ✅ 安全存储和管理密钥
- ✅ 定期轮换密钥
- ⚠️ 注意:ECB 模式不安全
安全建议
- 🔒 使用 PBKDF2 从密码派生密钥
- 🔒 使用密钥管理服务(KMS)
- 🔒 实施密钥轮换策略
- 🔒 记录加密操作日志
- 🔒 进行安全审计
crypto/aes 包提供了高效安全的 AES 加密实现,请始终使用 GCM 模式并妥善管理密钥!