AES-GCM 加密解密笔记
概述
这份笔记展示了如何使用 Go 语言实现 AES-GCM 模式的加密和解密。AES-GCM 是一种高效且安全的认证加密模式,提供了数据的机密性和完整性保护。
代码实现
以下是完整的 AES-GCM 加密解密实现:
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"io"
)
// AESGCMEncrypt 使用 AES-GCM 模式加密明文
// 参数:
// - key: AES 密钥 (16/24/32 字节对应 AES-128/192/256)
// - plaintext: 需要加密的明文字符串
// 返回:
// - 加密后的 Base64 编码字符串
// - 错误信息
func AESGCMEncrypt(key []byte, plaintext string) (string, error) {
// 创建 AES 密码块
block, err := aes.NewCipher(key)
if err != nil {
return "", fmt.Errorf("无法创建 AES 密钥块: %v", err)
}
// 创建 GCM 模式
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", fmt.Errorf("无法创建 GCM 模式: %v", err)
}
// 生成随机 nonce (Number used ONCE)
nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return "", fmt.Errorf("无法生成随机 nonce: %v", err)
}
// 加密数据 (nonce 会被添加到密文前面)
ciphertext := gcm.Seal(nonce, nonce, []byte(plaintext), nil)
// Base64 编码密文
return base64.StdEncoding.EncodeToString(ciphertext), nil
}
// AESGCMDecrypt 使用 AES-GCM 模式解密密文
// 参数:
// - key: 与加密时相同的 AES 密钥
// - ciphertextBase64: Base64 编码的密文
// 返回:
// - 解密后的明文字符串
// - 错误信息
func AESGCMDecrypt(key []byte, ciphertextBase64 string) (string, error) {
// Base64 解码密文
ciphertext, err := base64.StdEncoding.DecodeString(ciphertextBase64)
if err != nil {
return "", fmt.Errorf("无法解码密文: %v", err)
}
// 创建 AES 密码块
block, err := aes.NewCipher(key)
if err != nil {
return "", fmt.Errorf("无法创建 AES 密钥块: %v", err)
}
// 创建 GCM 模式
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", fmt.Errorf("无法创建 GCM 模式: %v", err)
}
// 获取 nonce 大小
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
return "", fmt.Errorf("密文长度不足以包含 nonce")
}
// 从密文中提取 nonce 和实际密文
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
// 解密数据
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return "", fmt.Errorf("解密失败: %v", err)
}
return string(plaintext), nil
}
// GenerateKey 生成指定长度的随机密钥
// 参数:
// - size: 密钥长度 (16/24/32 字节对应 AES-128/192/256)
// 返回:
// - 生成的随机密钥
// - 错误信息
func GenerateKey(size int) ([]byte, error) {
// 验证密钥大小是否有效
if size != 16 && size != 24 && size != 32 {
return nil, fmt.Errorf("无效的密钥大小: %d (必须是 16, 24 或 32 字节)", size)
}
key := make([]byte, size)
n, err := rand.Read(key) // 使用密码学安全随机数
// 确保读取了足够的随机字节
if err != nil {
return nil, fmt.Errorf("生成随机密钥失败: %v", err)
}
if n != size {
return nil, fmt.Errorf("未能生成足够的随机字节: 需要 %d, 获得 %d", size, n)
}
return key, nil
}
// 示例用法
func main() {
// 生成密钥 (32 字节 = 256 位)
key, err := GenerateKey(32)
if err != nil {
fmt.Printf("密钥生成失败: %v\n", err)
return
}
// 示例明文
plaintext := "Hello, this is a secret message!"
// 加密
ciphertextBase64, err := AESGCMEncrypt(key, plaintext)
if err != nil {
fmt.Printf("加密失败: %v\n", err)
return
}
fmt.Printf("加密后的密文(Base64 编码): %s\n", ciphertextBase64)
// 解密
decryptedText, err := AESGCMDecrypt(key, ciphertextBase64)
if err != nil {
fmt.Printf("解密失败: %v\n", err)
return
}
fmt.Printf("解密后的明文: %s\n", decryptedText)
}
使用说明
密钥生成:
- 使用
GenerateKey(size)
函数生成密钥 - 支持 16/24/32 字节密钥,对应 AES-128/192/256
- 使用
加密:
- 调用
AESGCMEncrypt(key, plaintext)
函数 - 返回 Base64 编码的密文
- 调用
解密:
- 调用
AESGCMDecrypt(key, ciphertextBase64)
函数 - 返回解密后的明文
- 调用
安全注意事项
密钥管理:
- 安全存储密钥,避免泄露
- 考虑使用密钥派生函数 (KDF) 从密码生成密钥
- 定期轮换密钥
Nonce 处理:
- 本实现自动生成随机 nonce 并附加到密文
- 确保每次加密使用不同的 nonce
认证数据:
- 当前实现未使用附加认证数据 (AAD)
- 如需更高安全性,可在
Seal
和Open
方法中添加 AAD
错误处理:
- 始终检查返回的错误
- 避免泄露敏感错误信息给用户
适用场景
- 敏感数据加密存储
- 安全通信
- 令牌/凭证加密
- 配置文件加密