Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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/pbkdf2golang.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-128128 位16 字节✅ 高
AES-192192 位24 字节✅ 很高
AES-256256 位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 模式并妥善管理密钥!