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/rand 包(加密安全随机数生成器)


🔹 概述

crypto/rand 包实现了加密安全的随机数生成器(CSPRNG - Cryptographically Secure Pseudorandom Number Generator)。

主要功能:

  • 生成加密安全的随机数
  • 生成随机大整数
  • 生成素数(用于 RSA 等)
  • 生成随机令牌/密码
  • 实现 io.Reader 接口

重要说明:

  • 加密安全 - 适用于密码学应用
  • 🔒 不可预测 - 无法通过已生成的值预测下一个值
  • 🌐 跨平台 - 使用操作系统提供的安全随机源
  • 📦 全局共享 - rand.Reader 是全局的、可并发使用
  • FIPS 140-3 - 支持 FIPS 模式(使用 DRBG)

与 math/rand 的区别:

  • crypto/rand - 加密安全,用于密钥、令牌等
  • math/rand - 非加密安全,用于游戏、模拟等

操作系统随机源:

  • Linux/FreeBSD/Solaris - getrandom(2)/dev/urandom
  • macOS/iOS/OpenBSD - arc4random_buf(3)
  • Windows - ProcessPrng API
  • NetBSD - kern.arandom sysctl
  • WebAssembly - Web Crypto API
  • wasip1 - random_get

🔹 全局变量

Reader - 全局随机数生成器

var Reader io.Reader
  • 说明:

    • 全局、共享的加密安全随机数生成器
    • 可安全并发使用
    • 在 FIPS 140-3 模式下,输出通过 SP 800-90A Rev.1 DRBG
  • 特点:

    • ✅ 线程安全
    • ✅ 永不返回错误(在非传统 Linux 系统上)
    • ✅ 总是填满缓冲区
  • 示例:

    package main
    
    import (
    	"crypto/rand"
    	"encoding/hex"
    	"fmt"
    )
    
    func main() {
    	// 使用全局 Reader 生成随机字节
    	bytes := make([]byte, 32)
    	_, err := rand.Read(bytes)
    	if err != nil {
    		fmt.Println("错误:", err)
    		return
    	}
    	
    	fmt.Printf("随机字节:%s\n", hex.EncodeToString(bytes))
    	fmt.Printf("长度:%d 字节\n", len(bytes))
    }
    

🔹 核心函数

Read - 填充随机字节

rand.Read(b []byte) (n int, err error)

  • 说明:

    • 用加密安全的随机字节填充切片 b
    • 永不返回错误(在非传统 Linux 系统上)
    • 总是完全填满 b
    • 如果底层随机源失败,会直接终止程序
  • 参数:

    • b []byte - 要填充的字节切片
  • 返回值:

    • n int - 读取的字节数(总是等于 len(b))
    • err error - 错误(通常为 nil)
  • 示例(生成随机密钥):

    package main
    
    import (
    	"crypto/rand"
    	"encoding/hex"
    	"fmt"
    )
    
    // GenerateRandomKey 生成随机密钥
    func GenerateRandomKey(size int) ([]byte, error) {
    	key := make([]byte, size)
    	_, err := rand.Read(key)
    	if err != nil {
    		return nil, err
    	}
    	return key, nil
    }
    
    func main() {
    	// 生成 256 位密钥
    	key, err := GenerateRandomKey(32) // 32 字节 = 256 位
    	if err != nil {
    		fmt.Println("错误:", err)
    		return
    	}
    	
    	fmt.Printf("256 位密钥:%s\n", hex.EncodeToString(key))
    	
    	// 生成 128 位 IV
    	iv := make([]byte, 16) // 16 字节 = 128 位
    	rand.Read(iv)
    	fmt.Printf("128 位 IV: %s\n", hex.EncodeToString(iv))
    }
    
  • 注意事项:

    • ✅ 总是检查错误(虽然通常不会发生)
    • ✅ 保证完全填满缓冲区
    • ⚠️ 在极端情况下(系统熵源耗尽)会终止程序

Int - 生成随机大整数

rand.Int(rand io.Reader, max *big.Int) (n *big.Int, err error)

  • 说明:

    • 生成 [0, max) 范围内的均匀分布随机大整数
    • 包含 0,不包含 max
  • 参数:

    • rand io.Reader - 随机数源(通常使用 rand.Reader
    • max *big.Int - 最大值(不包含)
  • 返回值:

    • n *big.Int - 随机大整数
    • err error - 错误信息
  • 示例(生成随机数):

    package main
    
    import (
    	"crypto/rand"
    	"fmt"
    	"math/big"
    )
    
    func main() {
    	// 生成 [0, 100) 的随机数
    	max := big.NewInt(100)
    	n, err := rand.Int(rand.Reader, max)
    	if err != nil {
    		fmt.Println("错误:", err)
    		return
    	}
    	
    	fmt.Printf("随机数 [0, 100): %s\n", n.String())
    	
    	// 生成 [0, 2^256) 的随机数
    	max256 := new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil)
    	n256, _ := rand.Int(rand.Reader, max256)
    	fmt.Printf("256 位随机数:%s\n", n256.Text(16))
    	
    	// 生成 [0, 10^100) 的随机数
    	max100 := new(big.Int).Exp(big.NewInt(10), big.NewInt(100), nil)
    	n100, _ := rand.Int(rand.Reader, max100)
    	fmt.Printf("100 位十进制随机数:%s\n", n100.String())
    }
    
  • 注意事项:

    • ⚠️ max <= 0 时会 panic
    • ✅ 均匀分布
    • ✅ 适用于密码学应用

Prime - 生成随机素数

rand.Prime(r io.Reader, bits int) (*big.Int, error)

  • 说明:

    • 生成指定位数的随机素数
    • 素数概率极高
    • Go 1.26+ 总是使用安全随机源
  • 参数:

    • r io.Reader - 随机数源(Go 1.26+ 可忽略)
    • bits int - 素数的位数
  • 返回值:

    • *big.Int - 随机素数
    • error - 错误信息
  • 示例(生成 RSA 素数):

    package main
    
    import (
    	"crypto/rand"
    	"fmt"
    )
    
    func main() {
    	// 生成 512 位素数(用于 RSA-1024)
    	p, err := rand.Prime(rand.Reader, 512)
    	if err != nil {
    		fmt.Println("错误:", err)
    		return
    	}
    	
    	fmt.Printf("512 位素数:%s\n", p.Text(16))
    	fmt.Printf("位数:%d\n", p.BitLen())
    	
    	// 生成 1024 位素数(用于 RSA-2048)
    	q, _ := rand.Prime(rand.Reader, 1024)
    	fmt.Printf("\n1024 位素数:%s\n", q.Text(16))
    	fmt.Printf("位数:%d\n", q.BitLen())
    	
    	// 生成 2048 位素数(用于 RSA-4096)
    	r, _ := rand.Prime(rand.Reader, 2048)
    	fmt.Printf("\n2048 位素数(前 64 位):%s...\n", r.Text(16)[:64])
    	fmt.Printf("位数:%d\n", r.BitLen())
    }
    
  • 注意事项:

    • ⚠️ bits < 2 时返回错误
    • ✅ 素数测试使用 Miller-Rabin 等方法
    • ✅ 适用于 RSA 密钥生成

Text - 生成随机文本

rand.Text() string

  • 说明:

    • 生成加密安全的随机字符串
    • 使用 RFC 4648 base32 字母表
    • 包含至少 128 位随机性
    • 适用于密码、令牌、密钥等
  • 返回值:

    • string - 随机字符串(base32 编码)
  • 示例(生成随机令牌):

    package main
    
    import (
    	"crypto/rand"
    	"fmt"
    )
    
    func main() {
    	// 生成随机令牌
    	token := rand.Text()
    	fmt.Printf("随机令牌:%s\n", token)
    	fmt.Printf("长度:%d 字符\n", len(token))
    	
    	// 生成多个令牌
    	fmt.Println("\n生成多个令牌:")
    	for i := 0; i < 5; i++ {
    		fmt.Printf("令牌 %d: %s\n", i+1, rand.Text())
    	}
    }
    
  • 注意事项:

    • ✅ 适用于会话令牌、API 密钥等
    • ✅ 防碰撞(128 位随机性)
    • ✅ 防暴力破解
    • 📝 使用 base32 编码(A-Z, 2-7)

🔹 完整示例

1. 生成各种随机数据

package main

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"math/big"
)

func main() {
	fmt.Println("=== 加密安全随机数生成 ===\n")
	
	// 1. 生成随机字节
	bytes := make([]byte, 32)
	rand.Read(bytes)
	fmt.Printf("32 字节随机数:%s\n", hex.EncodeToString(bytes))
	
	// 2. 生成随机整数 [0, 1000)
	max := big.NewInt(1000)
	n, _ := rand.Int(rand.Reader, max)
	fmt.Printf("\n随机整数 [0, 1000): %s\n", n.String())
	
	// 3. 生成随机素数
	prime, _ := rand.Prime(rand.Reader, 256)
	fmt.Printf("\n256 位素数:%s\n", prime.Text(16))
	
	// 4. 生成随机令牌
	token := rand.Text()
	fmt.Printf("\n随机令牌:%s\n", token)
	
	// 5. 生成 UUID v4
	uuid := make([]byte, 16)
	rand.Read(uuid)
	// 设置 UUID v4 版本
	uuid[6] = (uuid[6] & 0x0f) | 0x40
	// 设置 UUID 变体
	uuid[8] = (uuid[8] & 0x3f) | 0x80
	fmt.Printf("\nUUID v4: %x-%x-%x-%x-%x\n",
		uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:])
}

2. 安全密码生成器

package main

import (
	"crypto/rand"
	"fmt"
	"math/big"
	"strings"
)

const (
	lowercase = "abcdefghijklmnopqrstuvwxyz"
	uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	digits    = "0123456789"
	specials  = "!@#$%^&*()_+-=[]{}|;:,.<>?"
	allChars  = lowercase + uppercase + digits + specials
)

// GenerateSecurePassword 生成安全密码
func GenerateSecurePassword(length int) (string, error) {
	if length < 4 {
		return "", fmt.Errorf("密码长度至少为 4")
	}
	
	password := make([]byte, length)
	
	// 确保包含至少一个大写、一个小写、一个数字、一个特殊字符
	password[0] = lowercase[randomInt(len(lowercase))]
	password[1] = uppercase[randomInt(len(uppercase))]
	password[2] = digits[randomInt(len(digits))]
	password[3] = specials[randomInt(len(specials))]
	
	// 剩余字符随机
	for i := 4; i < length; i++ {
		password[i] = allChars[randomInt(len(allChars))]
	}
	
	// 打乱顺序
	shuffle(password)
	
	return string(password), nil
}

func randomInt(max int) int {
	n, _ := rand.Int(rand.Reader, big.NewInt(int64(max)))
	return int(n.Int64())
}

func shuffle(bytes []byte) {
	for i := len(bytes) - 1; i > 0; i-- {
		j, _ := rand.Int(rand.Reader, big.NewInt(int64(i+1)))
		bytes[i], bytes[j] = bytes[j], bytes[i]
	}
}

func main() {
	fmt.Println("=== 安全密码生成器 ===\n")
	
	lengths := []int{8, 12, 16, 20, 32}
	
	for _, length := range lengths {
		password, _ := GenerateSecurePassword(length)
		fmt.Printf("%d 位密码:%s\n", length, password)
	}
}

3. 随机令牌生成器(用于 API 认证)

package main

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"time"
)

// TokenGenerator 令牌生成器
type TokenGenerator struct {
	prefix string
}

// NewTokenGenerator 创建令牌生成器
func NewTokenGenerator(prefix string) *TokenGenerator {
	return &TokenGenerator{prefix: prefix}
}

// GenerateToken 生成随机令牌
func (tg *TokenGenerator) GenerateToken() string {
	// 生成 32 字节随机数据
	randomBytes := make([]byte, 32)
	rand.Read(randomBytes)
	
	// 添加时间戳
	timestamp := time.Now().UnixNano()
	
	// 组合:prefix + timestamp + random
	token := fmt.Sprintf("%s_%d_%s",
		tg.prefix,
		timestamp,
		base64.URLEncoding.EncodeToString(randomBytes))
	
	return token
}

// GenerateAPIKey 生成 API 密钥
func GenerateAPIKey() (string, error) {
	key := make([]byte, 32) // 256 位
	_, err := rand.Read(key)
	if err != nil {
		return "", err
	}
	return hex.EncodeToString(key), nil
}

// GenerateSessionID 生成会话 ID
func GenerateSessionID() string {
	id := make([]byte, 16) // 128 位
	rand.Read(id)
	return hex.EncodeToString(id)
}

func main() {
	fmt.Println("=== 随机令牌生成器 ===\n")
	
	// API 令牌生成器
	apiGen := NewTokenGenerator("api")
	fmt.Println("API 令牌:")
	for i := 0; i < 3; i++ {
		fmt.Printf("  %s\n", apiGen.GenerateToken())
	}
	
	// 访问令牌生成器
	accessGen := NewTokenGenerator("access")
	fmt.Println("\n访问令牌:")
	for i := 0; i < 3; i++ {
		fmt.Printf("  %s\n", accessGen.GenerateToken())
	}
	
	// API 密钥
	fmt.Println("\nAPI 密钥:")
	for i := 0; i < 3; i++ {
		key, _ := GenerateAPIKey()
		fmt.Printf("  %s\n", key)
	}
	
	// 会话 ID
	fmt.Println("\n会话 ID:")
	for i := 0; i < 3; i++ {
		fmt.Printf("  %s\n", GenerateSessionID())
	}
}

4. 随机盐值生成(用于密码哈希)

package main

import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
)

// SaltConfig 盐值配置
type SaltConfig struct {
	Size   int    // 盐值大小(字节)
	Format string // 输出格式:"hex" 或 "base64"
}

// GenerateSalt 生成随机盐值
func GenerateSalt(config SaltConfig) (string, error) {
	salt := make([]byte, config.Size)
	_, err := rand.Read(salt)
	if err != nil {
		return "", err
	}
	
	switch config.Format {
	case "base64":
		return base64.StdEncoding.EncodeToString(salt), nil
	case "hex":
		fallthrough
	default:
		return fmt.Sprintf("%x", salt), nil
	}
}

// HashPassword 模拟密码哈希(实际应使用 bcrypt/argon2)
func HashPassword(password, salt string) string {
	// 实际应用中应使用 bcrypt 或 argon2
	return fmt.Sprintf("%s$%s", salt, password)
}

func main() {
	fmt.Println("=== 随机盐值生成器 ===\n")
	
	// 配置
	configs := []SaltConfig{
		{Size: 8, Format: "hex"},   // 64 位盐
		{Size: 16, Format: "hex"},  // 128 位盐
		{Size: 16, Format: "base64"}, // 128 位盐 (base64)
		{Size: 32, Format: "hex"},  // 256 位盐
	}
	
	passwords := []string{"password123", "secure_pass", "admin2024"}
	
	for i, config := range configs {
		fmt.Printf("%d. %d 位盐值 (%s):\n", i+1, config.Size*8, config.Format)
		
		for _, pwd := range passwords {
			salt, _ := GenerateSalt(config)
			hashed := HashPassword(pwd, salt)
			fmt.Printf("   密码:%s\n", pwd)
			fmt.Printf("   盐值:%s\n", salt)
			fmt.Printf("   哈希:%s\n\n", hashed)
		}
		fmt.Println()
	}
	
	// 最佳实践建议
	fmt.Println("=== 最佳实践 ===")
	fmt.Println("✅ 每个密码使用唯一盐值")
	fmt.Println("✅ 盐值至少 128 位(16 字节)")
	fmt.Println("✅ 盐值与哈希一起存储")
	fmt.Println("✅ 使用 bcrypt/argon2 进行密码哈希")
	fmt.Println("❌ 不要重复使用盐值")
	fmt.Println("❌ 不要使用固定盐值")
}

5. 随机 ID 生成器(用于数据库记录)

package main

import (
	"crypto/rand"
	"encoding/base32"
	"fmt"
	"strings"
	"time"
)

// IDGenerator 随机 ID 生成器
type IDGenerator struct {
	prefix   string
	idLength int
}

// NewIDGenerator 创建 ID 生成器
func NewIDGenerator(prefix string, length int) *IDGenerator {
	return &IDGenerator{
		prefix:   strings.ToUpper(prefix),
		idLength: length,
	}
}

// Generate 生成随机 ID
func (g *IDGenerator) Generate() string {
	// 生成随机字节
	bytes := make([]byte, g.idLength)
	rand.Read(bytes)
	
	// Base32 编码
	encoded := base32.StdEncoding.EncodeToString(bytes)
	
	// 移除填充字符
	encoded = strings.TrimRight(encoded, "=")
	
	// 添加前缀和时间戳
	timestamp := time.Now().UnixNano() % 1000000 // 微秒级时间戳
	return fmt.Sprintf("%s-%d-%s", g.prefix, timestamp, encoded[:16])
}

// GenerateBatch 批量生成 ID
func (g *IDGenerator) GenerateBatch(count int) []string {
	ids := make([]string, count)
	for i := 0; i < count; i++ {
		ids[i] = g.Generate()
	}
	return ids
}

func main() {
	fmt.Println("=== 随机 ID 生成器 ===\n")
	
	// 订单 ID 生成器
	orderGen := NewIDGenerator("ORD", 16)
	fmt.Println("订单 ID:")
	for i := 0; i < 5; i++ {
		fmt.Printf("  %s\n", orderGen.Generate())
	}
	
	// 用户 ID 生成器
	userGen := NewIDGenerator("USR", 12)
	fmt.Println("\n用户 ID:")
	for i := 0; i < 5; i++ {
		fmt.Printf("  %s\n", userGen.Generate())
	}
	
	// 产品 ID 生成器
	productGen := NewIDGenerator("PRD", 14)
	fmt.Println("\n产品 ID:")
	for i := 0; i < 5; i++ {
		fmt.Printf("  %s\n", productGen.Generate())
	}
	
	// 批量生成
	fmt.Println("\n批量生成订单 ID:")
	batchIDs := orderGen.GenerateBatch(10)
	for _, id := range batchIDs {
		fmt.Printf("  %s\n", id)
	}
}

6. 与非加密随机数对比

package main

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"math/rand"
	"time"
)

func main() {
	fmt.Println("=== crypto/rand vs math/rand 对比 ===\n")
	
	// 1. 可预测性对比
	fmt.Println("1. 可预测性对比:")
	fmt.Println("   math/rand(可预测):")
	rand.Seed(12345) // 固定种子
	for i := 0; i < 3; i++ {
		fmt.Printf("     %d ", rand.Intn(100))
	}
	fmt.Println()
	
	rand.Seed(12345) // 相同种子
	for i := 0; i < 3; i++ {
		fmt.Printf("     %d ", rand.Intn(100))
	}
	fmt.Println("\n   ^ 相同种子产生相同序列")
	
	fmt.Println("\n   crypto/rand(不可预测):")
	for i := 0; i < 2; i++ {
		bytes := make([]byte, 8)
		crypto.rand.Read(bytes)
		fmt.Printf("     %s\n", hex.EncodeToString(bytes))
	}
	fmt.Println("   ^ 每次都不同,无法预测")
	
	// 2. 性能对比
	fmt.Println("\n2. 性能对比:")
	
	// math/rand
	start := time.Now()
	for i := 0; i < 10000; i++ {
		rand.Int63()
	}
	mathDuration := time.Since(start)
	
	// crypto/rand
	start = time.Now()
	bytes := make([]byte, 8*10000)
	crypto.rand.Read(bytes)
	cryptoDuration := time.Since(start)
	
	fmt.Printf("   math/rand:   %.2f ms (10000 次)\n", float64(mathDuration.Microseconds())/1000)
	fmt.Printf("   crypto/rand: %.2f ms (10000 次)\n", float64(cryptoDuration.Microseconds())/1000)
	fmt.Printf("   性能比:%.1fx\n", float64(cryptoDuration)/float64(mathDuration))
	
	// 3. 使用场景
	fmt.Println("\n3. 使用场景:")
	fmt.Println("   ✅ crypto/rand:")
	fmt.Println("      - 密码学密钥生成")
	fmt.Println("      - 会话令牌")
	fmt.Println("      - API 密钥")
	fmt.Println("      - 密码盐值")
	fmt.Println("      - 随机素数(RSA)")
	
	fmt.Println("\n   ✅ math/rand:")
	fmt.Println("      - 游戏逻辑")
	fmt.Println("      - 模拟测试")
	fmt.Println("      - 随机采样")
	fmt.Println("      - 负载均衡(非安全)")
}

🔹 注意事项和最佳实践

1. 与 math/rand 的区别

  • crypto/rand - 加密安全

    • 不可预测
    • 使用操作系统熵源
    • 适用于密码学应用
    • 性能较慢
  • math/rand - 非加密安全

    • 可预测(知道种子可重现)
    • 使用伪随机算法
    • 适用于游戏、模拟
    • 性能较快
// ✅ 正确 - 生成密钥
key := make([]byte, 32)
crypto.rand.Read(key)

// ❌ 错误 - 生成密钥
key := make([]byte, 32)
rand.Read(key) // 不安全!

2. 错误处理

  • rand.Read() 通常不返回错误
  • ⚠️ 在极端情况下会终止程序
  • ✅ 仍应检查错误(最佳实践)
// 正确 - 检查错误
bytes := make([]byte, 32)
_, err := crypto.rand.Read(bytes)
if err != nil {
	return nil, err
}

// Go 1.26+ 可以简化
bytes := make([]byte, 32)
crypto.rand.Read(bytes) // 错误会 panic

3. 熵源质量

  • ✅ 现代操作系统提供高质量熵源
  • ⚠️ 虚拟机/容器可能熵源不足
  • ✅ 使用硬件 RNG(如果可用)
// 检查熵源质量(Linux)
func checkEntropy() {
	data, _ := os.ReadFile("/proc/sys/kernel/random/entropy_avail")
	entropy, _ := strconv.Atoi(strings.TrimSpace(string(data)))
	fmt.Printf("可用熵:%d 位\n", entropy)
	if entropy < 1000 {
		fmt.Println("警告:熵源可能不足")
	}
}

4. 并发安全

  • rand.Reader 是线程安全的
  • ✅ 可以在多个 goroutine 中同时使用
// 安全 - 并发使用
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
	wg.Add(1)
	go func() {
		defer wg.Done()
		bytes := make([]byte, 16)
		crypto.rand.Read(bytes) // 安全
	}()
}
wg.Wait()

5. FIPS 140-3 合规性

  • ✅ FIPS 模式下使用 DRBG(SP 800-90A Rev.1)
  • ✅ 输出符合 FIPS 140-3 要求
  • ⚠️ 需要启用 FIPS 模式
// FIPS 模式下自动使用 DRBG
// 无需特殊配置
bytes := make([]byte, 32)
crypto.rand.Read(bytes) // FIPS 合规

6. 常见用途

  • 密钥生成 - AES、HMAC 密钥
  • 令牌生成 - 会话令牌、API 令牌
  • 盐值生成 - 密码哈希盐值
  • 素数生成 - RSA 密钥
  • Nonce/IV 生成 - 加密初始化向量
  • 游戏逻辑 - 使用 math/rand
  • 模拟测试 - 使用 math/rand

🔥 总结

核心函数

函数说明返回值使用场景
Read()填充随机字节(n, error)通用随机数生成
Int()生成随机大整数(*big.Int, error)随机数、概率
Prime()生成随机素数(*big.Int, error)RSA 密钥生成
Text()生成随机文本string令牌、密码

全局变量

变量类型说明
Readerio.Reader全局加密安全随机源

操作系统随机源

操作系统随机源
Linux/FreeBSD/Solarisgetrandom(2)/dev/urandom
macOS/iOS/OpenBSDarc4random_buf(3)
WindowsProcessPrng API
NetBSDkern.arandom sysctl
WebAssemblyWeb Crypto API
wasip1random_get

主要特点

  • 加密安全 👉 不可预测,适用于密码学
  • 全局共享 👉 rand.Reader 可并发使用
  • 跨平台 👉 使用操作系统安全随机源
  • FIPS 合规 👉 支持 FIPS 140-3 模式
  • 永不失败 👉 在非传统 Linux 系统上

使用场景

  • 密码学生成 👉 密钥、IV、Nonce
  • 令牌生成 👉 会话令牌、API 密钥
  • 盐值生成 👉 密码哈希盐值
  • 素数生成 👉 RSA 密钥生成
  • 随机 ID 👉 数据库记录 ID
  • 游戏逻辑 👉 使用 math/rand
  • 模拟测试 👉 使用 math/rand

最佳实践

  • ✅ 始终使用 crypto/rand 进行密码学操作
  • ✅ 检查错误(虽然通常不会发生)
  • ✅ 使用足够长的密钥/令牌(至少 128 位)
  • ✅ 每个密码使用唯一盐值
  • ✅ 令牌包含足够随机性(至少 128 位)
  • ⚠️ 注意虚拟机熵源质量
  • ❌ 不要使用 math/rand 进行安全操作

安全建议

  • 🔒 密钥至少 256 位(32 字节)
  • 🔒 令牌至少 128 位随机性
  • 🔒 盐值至少 128 位(16 字节)
  • 🔒 使用硬件 RNG(如果可用)
  • 🔒 监控熵源质量
  • 🔒 定期轮换密钥和令牌

🔹 常用工具函数封装

package random

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"math/big"
)

// Bytes 生成指定长度的随机字节
func Bytes(length int) ([]byte, error) {
	bytes := make([]byte, length)
	_, err := rand.Read(bytes)
	return bytes, err
}

// Hex 生成指定长度的随机十六进制字符串
func Hex(length int) (string, error) {
	bytes, err := Bytes(length)
	if err != nil {
		return "", err
	}
	return hex.EncodeToString(bytes), nil
}

// Base64 生成指定长度的随机 Base64 字符串
func Base64(length int) (string, error) {
	bytes, err := Bytes(length)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(bytes), nil
}

// Int 生成 [0, max) 范围内的随机整数
func Int(max int) (int, error) {
	n, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
	if err != nil {
		return 0, err
	}
	return int(n.Int64()), nil
}

// Token 生成随机令牌(至少 128 位随机性)
func Token() string {
	return rand.Text()
}

// Key 生成加密密钥(256 位)
func Key() ([]byte, error) {
	return Bytes(32)
}

// Salt 生成盐值(128 位)
func Salt() (string, error) {
	return Hex(16)
}

crypto/rand 包提供了加密安全的随机数生成,适用于所有密码学应用!