文章

加密与安全

加密与安全

包总览

用途分类
crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512哈希算法哈希
crypto/hmacHMAC 消息认证认证
crypto/aes crypto/des对称加密对称加密
crypto/rsa crypto/ecdsa crypto/ed25519非对称加密非对称
crypto/cipher加密模式(GCM/CBC/CTR)加密模式
crypto/rand密码学安全随机数随机数
crypto/tlsTLS/SSL传输安全
crypto/x509X.509 证书证书
encoding/pemPEM 编码编码

哈希算法

import (
    "crypto/md5"
    "crypto/sha1"
    "crypto/sha256"
    "crypto/sha512"
    "encoding/hex"
)

// MD5(不推荐用于安全场景,仅用于校验)
h := md5.Sum([]byte("hello"))
hex.EncodeToString(h[:])  // "5d41402abc4b2a76b9719d911017c592"

// SHA-1(不推荐用于安全场景)
h := sha1.Sum([]byte("hello"))
hex.EncodeToString(h[:])  // "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"

// SHA-256(推荐)
h := sha256.Sum256([]byte("hello"))
hex.EncodeToString(h[:])  // "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"

// SHA-512
h := sha512.Sum512([]byte("hello"))
hex.EncodeToString(h[:])

// 流式哈希(大文件)
f, _ := os.Open("largefile.iso")
defer f.Close()
h := sha256.New()
io.Copy(h, f)
hash := hex.EncodeToString(h.Sum(nil))

// 多次写入
h := sha256.New()
h.Write([]byte("hello "))
h.Write([]byte("world"))
hash := hex.EncodeToString(h.Sum(nil))

哈希算法对比

算法输出长度安全性性能推荐场景
MD5128 bit✗ 已破解最快文件校验(非安全)
SHA-1160 bit✗ 已破解Git 内部
SHA-256256 bit✓ 安全通用推荐
SHA-512512 bit✓ 安全高安全需求
SHA-3可变✓ 安全新标准

HMAC

import "crypto/hmac"

// HMAC:用密钥进行消息认证
func ComputeHMAC(key []byte, message []byte) string {
    mac := hmac.New(sha256.New, key)
    mac.Write(message)
    return hex.EncodeToString(mac.Sum(nil))
}

// 验证 HMAC(时间恒定比较,防时序攻击)
func VerifyHMAC(key []byte, message []byte, expectedMAC string) bool {
    mac := hmac.New(sha256.New, key)
    mac.Write(message)
    expected, _ := hex.DecodeString(expectedMAC)
    return hmac.Equal(mac.Sum(nil), expected)  // 时间恒定比较
}

重要:比较 HMAC 时必须用 hmac.Equal,不要用 ==bytes.Equal,否则有时序攻击风险。

对称加密 AES

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
)

// AES-GCM(推荐模式)
func AESEncrypt(key, plaintext []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
    }

    nonce := make([]byte, gcm.NonceSize())
    if _, err := rand.Read(nonce); err != nil {
        return nil, err
    }

    // nonce 前置,加密时自动附加认证标签
    ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
    return ciphertext, nil
}

func AESDecrypt(key, ciphertext []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("ciphertext too short")
    }

    nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
    plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
    if err != nil {
        return nil, err
    }
    return plaintext, nil
}

// 使用
key := make([]byte, 32)  // AES-256
rand.Read(key)

encrypted, _ := AESEncrypt(key, []byte("sensitive data"))
decrypted, _ := AESDecrypt(key, encrypted)
fmt.Println(string(decrypted))  // "sensitive data"

AES 加密模式对比

模式是否需要 IV/Nonce认证并行推荐
ECB✗ 不安全
CBC✗ 无认证
CTR✗ 无认证
GCM✓ 推荐
CFB✗ 无认证
OFB✗ 无认证

关键:始终使用 GCM 模式,它提供加密 + 认证(AEAD),防止篡改。

AES 密钥长度

AES 变体密钥长度轮数安全性
AES-12816 字节10
AES-19224 字节12
AES-25632 字节14

非对称加密 RSA

import (
    "crypto/rsa"
    "crypto/rand"
    "crypto/x509"
    "encoding/pem"
)

// 生成密钥对
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
publicKey := &privateKey.PublicKey

// 导出为 PEM 格式
// 私钥
privBytes := x509.MarshalPKCS1PrivateKey(privateKey)
privPEM := pem.EncodeToMemory(&pem.Block{
    Type:  "RSA PRIVATE KEY",
    Bytes: privBytes,
})

// 公钥
pubBytes := x509.MarshalPKCS1PublicKey(publicKey)
pubPEM := pem.EncodeToMemory(&pem.Block{
    Type:  "RSA PUBLIC KEY",
    Bytes: pubBytes,
})

// 从 PEM 解析
block, _ := pem.Decode(privPEM)
priv, _ := x509.ParsePKCS1PrivateKey(block.Bytes)

// 加密
ciphertext, err := rsa.EncryptOAEP(
    sha256.New(),
    rand.Reader,
    publicKey,
    []byte("secret message"),
    nil,  // label
)

// 解密
plaintext, err := rsa.DecryptOAEP(
    sha256.New(),
    rand.Reader,
    privateKey,
    ciphertext,
    nil,
)

// 签名
hashed := sha256.Sum256([]byte("message to sign"))
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed[:])

// 验签
err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hashed[:], signature)

RSA vs ECDSA vs Ed25519

算法密钥大小签名速度验签速度安全性推荐度
RSA-20482048 bit★★★☆☆
RSA-40964096 bit很慢★★☆☆☆
ECDSA-P256256 bit★★★★☆
Ed25519256 bit最快最快★★★★★

推荐:新项目使用 Ed25519,已有 RSA 系统至少用 2048 位。

Ed25519

import "crypto/ed25519"

// 生成密钥对
pub, priv, err := ed25519.GenerateKey(rand.Reader)

// 签名
signature := ed25519.Sign(priv, []byte("message"))

// 验签
valid := ed25519.Verify(pub, []byte("message"), signature)

TLS

import "crypto/tls"

// HTTPS 服务端
server := &http.Server{
    Addr: ":443",
    TLSConfig: &tls.Config{
        MinVersion:               tls.VersionTLS12,  // 最低 TLS 1.2
        Curves:                   []tls.CurveID{tls.X25519, tls.CurveP256},
        PreferServerCipherSuites: true,
        CipherSuites: []uint16{
            tls.TLS_AES_256_GCM_SHA384,
            tls.TLS_CHACHA20_POLY1305_SHA256,
            tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
        },
    },
}
server.ListenAndServeTLS("cert.pem", "key.pem")

// HTTPS 客户端(跳过证书验证,仅测试用)
client := &http.Client{
    Transport: &http.Transport{
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: true,  // ⚠️ 仅测试环境
        },
    },
}

// HTTPS 客户端(自定义 CA 证书)
caCert, _ := os.ReadFile("ca.pem")
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)

client := &http.Client{
    Transport: &http.Transport{
        TLSClientConfig: &tls.Config{
            RootCAs: caCertPool,
        },
    },
}

// mTLS(双向认证)
client := &http.Client{
    Transport: &http.Transport{
        TLSClientConfig: &tls.Config{
            Certificates: []tls.Certificate{clientCert},
            RootCAs:      caCertPool,
        },
    },
}

TLS 版本推荐

版本状态推荐
SSL 3.0✗ 已废弃
TLS 1.0✗ 已废弃
TLS 1.1✗ 已废弃
TLS 1.2✓ 仍广泛使用✓ 最低要求
TLS 1.3✓ 最新标准✓ 推荐

密码安全(bcrypt)

// 标准库不包含 bcrypt,需要 golang.org/x/crypto/bcrypt
import "golang.org/x/crypto/bcrypt"

// 哈希密码
hash, err := bcrypt.GenerateFromPassword([]byte("mypassword"), bcrypt.DefaultCost)
// hash: $2a$10$N9qo8uLOickgx2ZMRZoMy...

// 验证密码
err := bcrypt.CompareHashAndPassword(hash, []byte("mypassword"))
// nil = 匹配, error = 不匹配

// 修改 cost
bcrypt.GenerateFromPassword([]byte("pwd"), 12)  // cost=12
Cost计算时间安全性推荐
4~1ms仅测试
10~60ms默认
12~250ms推荐
14~1s很高高安全

不要用 MD5/SHA256 存密码。用 bcrypt/argon2/scrypt,它们有”工作因子”防止暴力破解。

安全编码检查清单

检查项说明
✅ 密码用 bcrypt/argon2不用 MD5/SHA
✅ HMAC 比较用 hmac.Equal不用 ==
✅ 对称加密用 AES-GCM不用 ECB/CBC
✅ 随机数用 crypto/rand不用 math/rand
✅ TLS 最低 1.2不用 SSL/TLS 1.0
✅ RSA 至少 2048 位或用 Ed25519
✅ 不硬编码密钥用环境变量/KMS
✅ SQL 用参数化查询不拼接 SQL