Go 開發者的密碼學導航:crypto 庫使用指南
Go 號稱 “開箱即用”,這與其標準庫的豐富功能和高質量是分不開的。而在 Go 標準庫中,crypto 庫(包括 crypto 包、crypto 目錄下相關包以及 golang.org/x/crypto 下的補充包) 又是 Go 社區最值得稱道的 Go 庫之一。
crypto 庫由 Go 核心團隊維護,確保了最高級別的安全標準和及時的漏洞修復,爲開發者提供了可靠的安全保障。crypto 還涵蓋了從基礎的對稱加密到複雜的非對稱加密,以及各種哈希函數和數字簽名算法等廣泛的加解密算法支持,以滿足 Go 開發者的各種需求爲目的,而不是與其他密碼學工具包競爭。此外,crypto 庫還經過精心優化,能夠在不同硬件平臺上儘可能地保證高效的執行性能。值得一提的是,crypto 庫還提供了統一的 API 設計,使得不同加密算法的使用方式保持一致,也降低了開發者的學習成本。
可以說 Go crypto 庫 [1] 是 Go 生態中密碼學功能的核心,它爲 Go 開發者提供了一套全面、安全、保持現代化、提供安全默認值且易於使用的密碼學工具,使得在 Go 應用程序中實現各種密碼學功能需求時變得簡單而可靠。
不過要理解並得心應手的使用 crypto 庫中的相關密碼學包仍然並非易事,這是因爲密碼學涉及數學、密碼分析、計算機安全等多個學科,概念多,算法也十分複雜,而大多程序員對密碼學的瞭解又多停留在使用層面,缺乏對其原理和底層機制的深入認知,甚至連每個包的用途都不甚瞭解。這導致很多開發者瀏覽了 crypto 相關包之後,甚至不知道該使用哪個包。
所以在這篇文章中,我想爲 Go 開發者建立一張 crypto 庫的 “地圖”,這張“地圖” 將幫助我們從宏觀角度理解 crypto 庫的結構,幫助大家快速精準選擇正確的包。並且通過對 crypto 相關包設計的理解,輕鬆掌握 crypto 相關包的使用模式。
注:Go 標準庫 crypto 庫的第一任負責人是 Adam Langley(agl)[2],他開創了 Go crypto 庫,他在招募和培養了 Filippo Valsorda[3] 後離開了 Go 項目,後者成爲了 Go crypto 的負責人。Filippo 在 Go 項目工作若干年後,把負責人交給了 Roland Shoemaker[4],即現任 Go 團隊安全組的負責人。當然 Shoemaker 也是 Filippo 招募到 Go 團隊中的。
下面我們首先來看看 Go crypto 庫的 “整體架構”。
- 標準庫 crypto 與 golang.org/x/crypto
Go 的密碼學功能 (即我們統一稱的 crypto 庫) 分爲兩個主要部分:標準庫的 crypto 相關包和擴展庫 golang.org/x/crypto。這種分離設計有其特定的目的和優勢:
Go 標準庫的 crypto 相關包,包含了最基礎、最穩定和使用最廣泛的密碼學算法。這些算法實現經過 Go 團隊的嚴格審查,保證了長期穩定性和向後兼容性。同時,這些包是隨 Go 安裝包分發的,使用時再無需引入額外的依賴。
而 golang.org/x/crypto 則號稱是 Go 標準庫 crypto 相關包的補充庫,雖然它同樣由 Go 團隊維護,但由於不是標準庫,它可以包含更多實驗性或較新的密碼學算法及實現,並可以更快速的迭代和更新。這樣它也可以成爲 Go 標準庫中一些 crypto 相關包的 “孵化器”,就像當年 golang.org/x/net/context 提升爲標準庫 context[5] 一樣。
同時 golang.org/x/crypto 也是 Go 標準庫依賴的爲數極少的外部包之一。比如,下面是 Go 1.23.0[6] 標準庫 go.mod 文件的內容:
module std
go 1.23
require (
golang.org/x/crypto v0.23.1-0.20240603234054-0b431c7de36a
golang.org/x/net v0.25.1-0.20240603202750-6249541f2a6c
)
require (
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
)
我們看到 Go 標準庫依賴特定版本的 golang.org/x/crypto 模塊。
與標準庫不同的是,如果你要使用 golang.org/x/crypto 模塊中的密碼學包,你就需要單獨引入項目依賴。此外,golang.org/x 下的包通常被視爲實驗性或擴展包,因此它們並不嚴格遵循 Go1 兼容性承諾 [7]。換句話說,這些包在 API 穩定性上沒有與標準庫相同的保證,可能會有非向後兼容的更改。
綜上,我們看到 Go 標準庫 crypto 與 golang.org/x/crypto 的這種分離策略,允許 Go 團隊在保持標準庫穩定性的同時,也能夠靈活地引入新的密碼學算法和技術。
接下來,我們來看看 crypto 庫的整體結構設計原則,這些原則對理解整個 crypto 庫大有裨益。
- 整體結構設計原則
Go 的 crypto 庫整體上的結構設計遵循了幾個原則:
2.1 統一接口和類型抽象
首先是統一接口和類型抽象,這在最頂層的 crypto 包中就能充分體現。
crypto 包定義了一個 Hash 類型和一個創建具體哈希實現的方法。這個設計允許統一管理不同的哈希算法,同時保持了良好的可擴展性:
// $GOROOT/src/crypto/crypto.go
type Hash uint
// New returns a new hash.Hash calculating the given hash function. New panics
// if the hash function is not linked into the binary.
func (h Hash) New() hash.Hash {
if h > 0 && h < maxHash {
f := hashes[h]
if f != nil {
return f()
}
}
panic("crypto: requested hash function #" + strconv.Itoa(int(h)) + " is unavailable")
}
// HashFunc simply returns the value of h so that [Hash] implements [SignerOpts].
func (h Hash) HashFunc() Hash {
return h
}
// RegisterHash registers a function that returns a new instance of the given
// hash function. This is intended to be called from the init function in
// packages that implement hash functions.
func RegisterHash(h Hash, f func() hash.Hash) {
if h >= maxHash {
panic("crypto: RegisterHash of unknown hash function")
}
hashes[h] = f
}
var hashes = make([]func() hash.Hash, maxHash)
Hash 類型作爲一個統一的標識符,用於表示不同的哈希算法。New 方法則 “像一個工廠方法”,用於創建具體的哈希實現。新的哈希算法可以很容易地添加到這個系統中,只需定義一個新的常量並提供相應的實現,並將實現通過 RegisterHash 註冊到 hashes 中即可。下面是一個使用 sha256 算法的示例 (僅做演示,並非慣例寫法):
package main
import (
"crypto"
_ "crypto/sha256" // register h256 to hashes
)
func main() {
ht := crypto.SHA256
h := ht.New()
h.Write([]byte("hello world"))
sum := h.Sum(nil)
println(sum)
}
注:也許是早期標準庫的設計問題,hash 接口目前沒有放到 crypto 下面,而是在標準庫頂層目錄下。crypto 庫中的 hash 實現通過 New 方法返回真正的 hash.Hash 實現。
crypto 包還定義了幾個關鍵接口,這些接口被各個子包實現,從而實現了高度的可擴展性和互操作性,比如下面的 Signer、SignerOpts、Decrypter 接口:
// Signer is an interface for an opaque private key that can be used for
// signing operations. For example, an RSA key kept in a hardware module.
type Signer interface {
Public() PublicKey
Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error)
}
// SignerOpts contains options for signing with a [Signer].
type SignerOpts interface {
HashFunc() Hash
}
// Decrypter is an interface for an opaque private key that can be used for
// asymmetric decryption operations. An example would be an RSA key
// kept in a hardware module.
type Decrypter interface {
Public() PublicKey
Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error)
}
以 Signer 接口爲例,這個 Signer 接口爲不同的簽名算法(如 RSA、ECDSA、Ed25519 等)提供了一個統一的抽象。下面是一個使用統一 Signer 接口但不同 Signer 實現的示例:
func signData(signer crypto.Signer, data []byte) ([]byte, error) {
hash := crypto.SHA256
h := hash.New()
h.Write(data)
digest := h.Sum(nil)
return signer.Sign(rand.Reader, digest, hash)
}
func main() {
rsaKey, _ := rsa.GenerateKey(rand.Reader, 2048)
signature, _ := signData(rsaKey, []byte("Hello, World!"))
println(signature)
ecdsaKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
signature, _ = signData(ecdsaKey, []byte("Hello, World!"))
println(signature)
}
在這個例子中,我們看到了如何使用相同的 signData 函數來處理不同類型的簽名算法,這體現了統一接口帶來的靈活性和一致性。
在 crypto 目錄下的各個子包中,上述原則也有很好的體現,比如 cipher 包就定義了 Block、Stream 等接口,然後 aes、des 等對稱加密包也都提供了創建實現了這些接口的類型的函數,比如 aes.NewCipher 以及 des.NewCipher 等。
2.2 模塊化
每個子包專注於特定的功能,這種模塊化設計使得每個包都相對獨立,便於維護和使用。以 aes 包和 des 包爲例:
// crypto/aes/cipher.go
func NewCipher(key []byte) (cipher.Block, error) {
// AES specific implementation
}
// crypto/des/cipher.go
func NewCipher(key []byte) (cipher.Block, error) {
// DES specific implementation
}
這兩個包都實現了相同的 NewCipher 函數,但內部實現完全不同,專注於各自的加密算法。
2.3 易用性與靈活性的平衡
Go crypto 庫中的很多包既提供了可以滿足大多數常見用例的需求、易用性很好的高級 API,同時也提供了更靈活的低級 API,允許開發者在需要時進行更精細的控制或自定義實現。
讓我們以 SHA256 哈希函數爲例來說明這一點:
// 高級API
func highLevelAPI(data []byte) [32]byte {
return sha256.Sum256(data)
}
// 低級API
func lowLevelAPI(data []byte) [32]byte {
h := sha256.New()
h.Write(data)
return *(*[32]byte)(h.Sum(nil))
}
func main() {
fmt.Println(lowLevelAPI([]byte("hello world")))
fmt.Println(highLevelAPI([]byte("hello world")))
}
在這個例子中,sha256.Sum256 是高級 API,而 lowLevelAPI 中使用的那套邏輯則是對低級 API 的組合以實現 Sum256 功能。
2.4 可擴展性
基於 “統一接口和類型抽象” 原則設計的 crypto 庫可以讓用戶輕鬆地集成自己的實現或第三方庫,這種可擴展性便於我們添加新的算法或功能,而不影響現有結構。 比如,我們可以像這下面這樣實現自定義的 cipher.Block:
type MyCustomCipher struct {
// ...
}
func (c *MyCustomCipher) BlockSize() int {
// ...
}
func (c *MyCustomCipher) Encrypt(dst, src []byte) {
// ...
}
func (c *MyCustomCipher) Decrypt(dst, src []byte) {
// ...
}
之後,這個自定義的 cipher.Block 實現便可以直接用在標準庫提供的分組密碼模式中。
作爲 crypto 庫的擴展和實驗庫,golang.org/x/crypto 也遵循了與標準庫 crypto 相關包一致的設計原則,這裏就不舉例說明了。
有了上述對 crypto 庫的整體設計原則的認知後,我們再來看一下 Go 標準庫 crypto 目錄下的子包結構,瞭解了這個結果,你就會像擁有了 crypto 庫的 “導航”,可以順利方便地找到你想要的密碼學包了。
- 子包結構概覽
衆所周知,Go 標準庫 crypto 目錄下不僅有 crypto 包,還有衆多種類的密碼學包,下面這張示意圖對這些包進行了簡單分類:
下面我會按照圖中的類別對各個包做簡單介紹,包括功能、用途、簡單的示例以及是否推薦使用。密碼學一直在發展,很多算法因爲不再 “牢不可破” 而逐漸不再被推薦使用。但 Go 爲了保證 Go1 兼容性,這些包依賴留在了 Go 標準庫中。
我們自上而下,先從哈希函數開始。
3.1 哈希函數
3.1.1 md5
-
功能:實現 MD5 哈希算法
-
用途:生成數據的 128 位哈希值
-
示例:
import "crypto/md5"
hash := md5.Sum([]byte("hello world"))
- 使用建議:不推薦用於安全相關用途,因爲 MD5 已被證明不夠安全。
3.1.2 sha1
-
功能:實現 SHA-1 哈希算法
-
用途:生成數據的 160 位哈希值
-
示例:
import "crypto/sha1"
hash := sha1.Sum([]byte("hello world"))
- 使用建議:不推薦用於安全相關用途,因爲 SHA-1 已被證明存在碰撞風險。
3.1.3 sha256
-
功能:實現 SHA-256 哈希算法
-
用途:生成數據的 256 位哈希值
-
示例:
import "crypto/sha256"
hash := sha256.Sum256([]byte("hello world"))
- 使用建議:推薦使用,安全性高。
3.1.4 sha512
-
功能:實現 SHA-512 哈希算法
-
用途:生成數據的 512 位哈希值
-
示例:
import "crypto/sha512"
hash := sha512.Sum512([]byte("hello world"))
- 使用建議:推薦使用,安全性很高。
3.2 加密和解密
3.2.1 aes
-
功能:實現 AES(Advanced Encryption Standard) 對稱加密算法
-
用途:數據對稱加密和解密
-
示例:
import "crypto/aes"
key := []byte("example key 1234") // 16字節的key
block, _ := aes.NewCipher(key)
- 使用建議:推薦使用,是目前最廣泛使用的對稱加密算法。
3.2.2 des
-
功能:實現 DES(Data Encryption Standard) 和 Triple DES 加密算法
-
用途:數據對稱加密和解密
-
示例:
import "crypto/des"
key := []byte("example!") // 8字節的key
block, _ := des.NewCipher(key)
- 使用建議:不推薦使用 DES,密鑰長度不足 (DES 使用 56 位密鑰,實際上是 64 位,但其中 8 位是奇偶校驗位,不用於加密),容易被暴力破解。推薦使用 AES;Triple DES 在某些遺留系統中仍在使用。
3.2.3 rc4
-
功能:實現 RC4(Rivest Cipher 4) 流加密算法
-
用途:流數據的加密和解密
-
示例:
import "crypto/rc4"
key := []byte("secret key")
cipher, _ := rc4.NewCipher(key)
- 使用建議:不推薦使用,因爲 RC4 已被證明存在安全漏洞。由於這些已知的安全問題,RC4 已經被許多現代加密協議和應用所棄用。例如,TLS(Transport Layer Security)協議已經移除了對 RC4 的支持。
3.2.4 cipher
-
功能:定義了塊加密的通用接口
-
用途:爲其他加密算法提供通用的加密和解密方法
-
示例:
import "crypto/cipher"
// 使用AES-GCM模式
block, _ := aes.NewCipher(key)
aesgcm, _ := cipher.NewGCM(block)
- 使用建議:推薦使用,特別是 GCM 等認證加密模式。
3.3 簽名和驗證
3.3.1 dsa
-
功能:實現數字簽名算法(DSA, Digital Signature Algorithm)
-
用途:生成和驗證數字簽名
-
示例:
import "crypto/dsa"
var privateKey dsa.PrivateKey
dsa.GenerateKey(&privateKey, rand.Reader)
- 使用建議:目前的趨勢是 DSA 在許多應用中不再被推薦使用。DSA 的安全性高度依賴於密鑰長度。隨着計算能力的提升,較短的 DSA 密鑰長度(例如 1024 位)已經不再被認爲是安全的。NIST 建議使用更長的密鑰長度(例如 2048 位或更長),但這會增加計算複雜性和資源消耗。ECDSA 使用橢圓曲線密碼學,可以在更短的密鑰長度下提供相同級別的安全性。
3.3.2 ecdsa
-
功能:實現橢圓曲線數字簽名算法(ECDSA, Elliptic Curve Digital Signature Algorithm)
-
用途:生成和驗證數字簽名
-
示例:
import "crypto/ecdsa"
privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- 使用建議:強烈推薦使用,安全性高且效率好。
3.3.3 ed25519
-
功能:實現 Ed25519 簽名算法 (Edwards-curve Digital Signature Algorithm with Curve25519)
-
用途:生成和驗證數字簽名
-
示例:
import "crypto/ed25519"
publicKey, privateKey, _ := ed25519.GenerateKey(rand.Reader)
- 使用建議:強烈推薦使用,安全性高且性能優秀。Ed25519 提供了比傳統 ECDSA 更高的安全性和性能,同時減少了某些類型的實現風險。因此,在選擇數字簽名算法時,Ed25519 是一個非常有吸引力的選項,尤其是在需要高性能和強安全保障的應用中。
3.3.4 rsa
-
功能:實現 RSA(Rivest–Shamir–Adleman) 加密和簽名算法
-
用途:非對稱加密、數字簽名
-
示例:
import "crypto/rsa"
privateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
- 使用建議:關於是否推薦使用 RSA,這取決於具體的應用場景和安全需求。RSA 在許多應用中仍然被廣泛使用,尤其是在需要公鑰加密和數字簽名的場景。它是一個經過時間考驗的算法,有着良好的安全記錄。隨着計算能力的提升,特別是量子計算的發展,RSA 的安全性可能會受到威脅。此外,對於某些高性能或資源受限的環境,RSA 可能不如其他算法(如橢圓曲線加密算法,如 ECDSA 或 Ed25519)高效。尤其是簽名,ECDSA 或 Ed25519 可能是更好的選擇。
3.4 密鑰交換
3.4.1 ecdh
-
功能:實現橢圓曲線 Diffie-Hellman 密鑰交換 (Elliptic Curve Diffie-Hellman)
-
用途:安全地在不安全的通道上協商共享密鑰
-
示例:
import "crypto/ecdh"
curve := ecdh.P256()
privateKey, _ := curve.GenerateKey(rand.Reader)
- 使用建議:ECDH 是一個強大且高效的密鑰交換協議,在許多現代安全通信中被推薦使用,是現代密鑰交換的首選方法。
3.5 安全隨機數生成
3.5.1 rand
-
功能:提供加密安全的隨機數生成器
-
用途:生成密鑰、隨機填充等
-
示例:
import "crypto/rand"
randomBytes := make([]byte, 32)
rand.Read(randomBytes)
- 使用建議:強烈推薦使用,不要使用 math/rand 包 (包括 math/rand/v2) 生成密碼學相關的隨機數(這些隨機數是僞隨機)。
3.6 證書和協議
3.6.1 tls
-
功能:實現傳輸層安全(TLS, Transport Layer Security)協議
-
用途:安全網絡通信
-
示例:
import "crypto/tls"
config := &tls.Config{MinVersion: tls.VersionTLS12}
- 使用建議:強烈推薦使用,是保護網絡通信的標準方法。
3.6.2 x509
-
功能:實現 X.509 公鑰基礎設施標準
-
用途:處理數字證書、證書籤名請求(CSR)等
-
示例:
import "crypto/x509"
cert, _ := x509.ParseCertificate(certDER)
- 使用建議:推薦使用,是處理數字證書的標準方法。
3.7. 輔助功能
3.7.1 elliptic
-
功能:實現幾個標準的橢圓曲線
-
用途:爲 ECDSA 和 ECDH 提供基礎
-
示例:
import "crypto/elliptic"
curve := elliptic.P256()
- 使用建議:推薦使用,但通常不直接使用,而是通過 ecdsa 或 ecdh 包間接使用。
3.7.2 hmac
-
功能:實現密鑰散列消息認證碼(HMAC, Hash-based Message Authentication Code)
-
用途:消息完整性驗證
-
示例:
import "crypto/hmac"
h := hmac.New(sha256.New, []byte("secret key"))
h.Write([]byte("message"))
- 使用建議:推薦使用,是保護數據完整性和消息認證的標準方法。
3.7.3 subtle
-
功能:提供一些用於實現加密功能的常用但容易出錯的操作
-
用途:比較、常量時間操作等
-
示例:
import "crypto/subtle"
equal := subtle.ConstantTimeCompare([]byte("a"), []byte("b"))
- 使用建議:推薦在需要時使用,有助於防止時序攻擊。
結合上面兩節,我們看到 crypto 庫的內部依賴結構設計得非常巧妙,以最小化耦合。大多數子包依賴於 crypto 基礎包中定義的接口和類型。crypto/subtle 包提供了一些底層的輔助函數,被多個其他包使用。每個加密算法包(如 crypto/aes,crypto/rsa)通常是獨立的,減少了包間的直接依賴。一些高級功能包(如 crypto/tls)會依賴多個基礎算法包。大多數需要隨機性的包都依賴 crypto/rand 作爲安全隨機源。
此外,crypto 庫與其他 Go 標準庫可緊密集成,包括:
-
與 io 包集成:使用 io.Reader 和 io.Writer 接口,便於流式處理和與其他 I/O 操作集成。
-
與 encoding 相關包集成:比如與 encoding/pem 和 encoding/asn1 包配合,用於處理密鑰和證書的編碼。
-
與 hash 包集成:加密哈希函數實現了 hash.Hash 接口,保持一致性。
-
與 net 包集成:如 crypto/tls 包與 net 包緊密集成,提供安全的網絡通信。
接下來,再來看看 golang.org/x/crypto 擴展庫,我們同樣借鑑上面的分類和介紹方法,看看 crypto 擴展庫中都有哪些有價值的實用密碼學包。
4 golang.org/x/crypto 擴展庫
我們還是從哈希函數開始介紹。
4.1 哈希函數
4.1.1 blake2b 和 blake2s
-
功能:實現 BLAKE2b 和 BLAKE2s 哈希函數。BLAKE2 是一種加密哈希函數,由 Jean-Philippe Aumasson、Samuel Neves、Zooko Wilcox-O'Hearn 和 Christian Winnerlein 設計,旨在替代 MD5 和 SHA-1 等舊的哈希函數。BLAKE2 有兩種主要變體:BLAKE2b 和 BLAKE2s。
-
用途:生成高速、安全的哈希值。
-
示例:
import "golang.org/x/crypto/blake2b"
hash := blake2b.Sum256([]byte("hello world"))
- 使用建議:推薦使用,BLAKE2 提供了比 MD5 和 SHA-1 更高的安全性,同時保持與 SHA-2 和 SHA-3 相當的強度,安全性高且速度快。
4.1.2 md4
-
功能:實現 MD4(Message Digest Algorithm 4) 哈希算法
-
用途:生成 128 位哈希值
-
示例:
import "golang.org/x/crypto/md4"
h := md4.New()
h.Write([]byte("hello world"))
hash := h.Sum(nil)
- 使用建議:不推薦用於安全相關用途,MD4 已被證明不安全,容易受到碰撞攻擊和其他類型的攻擊。已經被更安全的哈希函數所取代,如 SHA-2 和 SHA-3 等。
4.1.3 ripemd160
-
功能:實現 RIPEMD-160(RACE Integrity Primitives Evaluation Message Digest 160) 哈希算法。
-
用途:生成 160 位哈希值
-
示例:
import "golang.org/x/crypto/ripemd160"
h := ripemd160.New()
h.Write([]byte("hello world"))
hash := h.Sum(nil)
- 使用建議:RIPEMD-160 提供了比 MD5 和 SHA-1 更高的安全性,儘管它不像 SHA-2 和 SHA-3 那樣被廣泛研究和使用。但它仍然在某些特定場景(如比特幣地址生成)中使用,但一般情況下推薦使用更現代的哈希函數 (如 SHA-256 和 SHA-512)。
4.1.4 sha3
-
功能:實現 SHA-3(Secure Hash Algorithm 3) 哈希算法族。SHA-3 是由美國國家標準與技術研究院(NIST)在 2015 年發佈的一種加密哈希函數,作爲 SHA-2 的後繼者。SHA-3 的設計基於 Keccak 算法,由 Guido Bertoni、Joan Daemen、Michaël Peeters 和 Gilles Van Assche 開發。
-
用途:生成不同長度的哈希值。SHA-3 包括多種變體,如 SHA3-224、SHA3-256、SHA3-384 和 SHA3-512,分別生成 224 位、256 位、384 位和 512 位的哈希值。
-
示例:
import "golang.org/x/crypto/sha3"
hash := sha3.Sum256([]byte("hello world"))
- 使用建議:強烈推薦使用,是最新的 NIST 標準哈希函數。
4.2 加密和解密
4.2.1 blowfish
-
功能:實現 Blowfish(設計者 Bruce Schneier) 加密算法
-
用途:數據的對稱加密和解密
-
示例:
import "golang.org/x/crypto/blowfish"
cipher, _ := blowfish.NewCipher([]byte("key"))
- 使用建議:不推薦用於新系統,其密鑰長度上限爲 448 位,不如更現代的算法安全,建議使用 AES。
4.2.2 cast5
-
功能:實現 CAST5(又名 CAST-128)加密算法
-
用途:數據對稱加密和解密
-
示例:
import "golang.org/x/crypto/cast5"
cipher, _ := cast5.NewCipher([]byte("16-byte key"))
- 使用建議:不推薦用於新系統,建議使用 AES。
4.2.3 chacha20
-
功能:實現 ChaCha20 流加密算法 (ChaCha20 stream cipher)
-
用途:流數據的對稱加密和解密
-
示例:
import "golang.org/x/crypto/chacha20"
cipher, _ := chacha20.NewUnauthenticatedCipher(key, nonce)
- 使用建議:推薦使用,特別是在移動設備上性能優於 AES。它被廣泛用於各種安全協議和應用中,包括 TLS(Transport Layer Security)、SSH(Secure Shell)和 QUIC(Quick UDP Internet Connections)等。
4.2.4 salsa20
-
功能:實現 Salsa20 流加密算法 (Salsa20 stream cipher)
-
用途:流數據的對稱加密和解密
-
示例:
import "golang.org/x/crypto/salsa20"
salsa20.XORKeyStream(dst, src, nonce, key)
- 使用建議:推薦使用,但 ChaCha20 可能因其性能優勢和更廣泛的標準支持而成爲更受歡迎的選擇。
4.2.4 tea
-
功能:實現 TEA(Tiny Encryption Algorithm)加密算法
-
用途:輕量級數據加密
-
示例:
import "golang.org/x/crypto/tea"
cipher, _ := tea.NewCipher([]byte("16-byte key"))
- 使用建議:儘管 TEA 算法在過去被認爲是安全的,但它已經出現了一些已知的安全漏洞,如密鑰相關攻擊和差分攻擊。因此,TEA 算法可能不適合需要高安全性的應用。不推薦將它用於新系統,建議使用 AES。
4.2.5 twofish
-
功能:實現 Twofish(Twofish block cipher) 加密算法
-
用途:數據對稱加密和解密
-
示例:
import "golang.org/x/crypto/twofish"
cipher, _ := twofish.NewCipher([]byte("16, 24, or 32 byte key"))
- 使用建議:不推薦將它用於新系統,建議使用 AES。
4.2.6 xtea
-
功能:實現 XTEA(eXtended Tiny Encryption Algorithm) 加密算法
-
用途:輕量級對稱數據加密
-
示例:
import "golang.org/x/crypto/xtea"
cipher, _ := xtea.NewCipher([]byte("16-byte key"))
- 使用建議:儘管 XTEA 修復了 TEA 的一些安全漏洞,但它仍然可能存在其他安全問題,特別是在面對現代計算能力和攻擊技術時。因此,不推薦用於新系統,建議使用 AES。
4.2.7 xts
-
功能:實現 XTS (XEX-based tweaked-codebook mode with ciphertext stealing) 模式
-
用途:是一種塊加密的標準操作模式,主要用於全磁盤加密
-
示例:
import "golang.org/x/crypto/xts"
cipher, _ := xts.NewCipher(aes.NewCipher, []byte("32-byte key"))
- 使用建議:在全磁盤加密場景,即需要對存儲設備進行加密的應用中推薦使用。
4.3 認證加密
4.3.1 chacha20poly1305
-
功能:實現 ChaCha20-Poly1305(ChaCha20 流加密算法和 Poly1305 消息認證碼) AEAD(認證加密與關聯數據)。
-
用途:提供加密和認證的組合
-
示例:
import "golang.org/x/crypto/chacha20poly1305"
aead, _ := chacha20poly1305.New(key)
- 使用建議:ChaCha20-Poly1305 是一個高效且安全的組合加密算法,在許多現代安全應用中被推薦使用。這裏也強烈推薦使用,提供了高安全性和高性能。
4.4 密鑰派生和密碼哈希
4.4.1 argon2
-
功能:實現 Argon2(Argon2 memory-hard key derivation function) 密碼哈希算法
-
用途:安全地存儲密碼
-
示例:
import "golang.org/x/crypto/argon2"
hash := argon2.IDKey([]byte("password"), salt, 1, 64*1024, 4, 32)
- 使用建議:強烈推薦使用,是最新的密碼哈希標準。
4.4.2 bcrypt
-
功能:實現 bcrypt(Blowfish-based password hashing function) 密碼哈希算法
-
用途:安全地存儲密碼
-
示例:
import "golang.org/x/crypto/bcrypt"
hash, _ := bcrypt.GenerateFromPassword([]byte("password"), bcrypt.DefaultCost)
- 使用建議:推薦使用,廣泛應用於密碼存儲 [8]。
4.4.3 hkdf
-
功能:實現 HMAC-based Key Derivation Function (HKDF)
-
用途:HKDF 是基於 HMAC(Hash-based Message Authentication Code)的一種變體,專門用於從較短的輸入密鑰材料(如共享密鑰或密碼)派生出更長的、安全的密鑰。
-
示例:
import "golang.org/x/crypto/hkdf"
hkdf := hkdf.New(sha256.New, secret, salt, info)
- 使用建議:推薦使用,是標準的密鑰派生函數。
4.4.4 pbkdf2
-
功能:實現 PBKDF2(Password-Based Key Derivation Function 2, 基於密碼的密鑰派生函數 2)
-
用途:從密碼派生密鑰
-
示例:
import "golang.org/x/crypto/pbkdf2"
dk := pbkdf2.Key([]byte("password"), salt, 4096, 32, sha1.New)
- 使用建議:對於需要高安全性和抵抗暴力破解攻擊的應用,PBKDF2 是一個很好的選擇。然而,對於更現代的應用,特別是那些對安全性有極高要求的應用,可能更推薦使用更現代的密碼哈希算法,如 Argon2。
4.4.5 scrypt
-
功能:實現 scrypt(Scrypt key derivation function) 密鑰派生函數
-
用途:從密碼派生密鑰,特別適合抵抗硬件暴力破解 [9]
-
示例:
import "golang.org/x/crypto/scrypt"
dk, _ := scrypt.Key([]byte("password"), salt, 32768, 8, 1, 32)
- 使用建議:推薦使用,特別是在需要抵抗硬件攻擊或並行計算攻擊的場景。
4.5 公鑰密碼學
4.5.1 bn256
-
功能:實現 256 位 Barreto-Naehrig 曲線
-
用途:支持雙線性對運算,用於某些高級密碼協議
-
示例:
import "golang.org/x/crypto/bn256"
g1 := new(bn256.G1).ScalarBaseMult(k)
- 使用建議:該包已作廢並凍結,不推薦使用。github.com/cloudflare/bn256 有更完整的實現,但對於新的應用,特別是那些對安全性有極高要求的應用,不推薦使用 bn256。
4.5.2 nacl
-
功能:提供 NaCl(Networking and Cryptography library)的 Go 實現
-
用途:NaCl 主要用於需要高效加密和安全通信的應用。它提供了各種加密原語,包括對稱加密、公鑰加密、哈希函數、消息認證碼(MAC)和密鑰協商協議等。
-
示例:
import "golang.org/x/crypto/nacl/box"
publicKey, privateKey, _ := box.GenerateKey(rand.Reader)
- 使用建議:推薦使用,提供了易用的高級加密接口
4.6 協議和標準
4.6.1 acme
-
功能:實現 ACME(Automatic Certificate Management Environment)協議,該協議旨在自動化證書的頒發、更新和管理。它允許服務器自動請求和接收 TLS/SSL 證書,而無需人工干預。
-
用途:自動化證書管理,如 Let's Encrypt
-
示例:使用較複雜,通常通過更高級的庫如 golang.org/x/crypto/acme/autocert 使用,鑑於篇幅,這裏就不貼代碼了。
-
使用建議:在需要自動化證書管理的場景中推薦使用
4.6.2 ocsp
-
功能:實現在線證書狀態協議(OCSP, Online Certificate Status Protocol),該協議提供了一種實時查詢數字證書狀態的方法。它允許客戶端在建立安全連接之前,向證書頒發機構(CA)查詢特定證書的有效性。
-
用途:檢查 X.509 數字證書的撤銷狀態
-
示例:
import "golang.org/x/crypto/ocsp"
resp, _ := ocsp.ParseResponse(responseBytes, issuer)
- 使用建議:在需要證書狀態檢查的應用中推薦使用
4.6.3 openpgp
-
功能:實現 OpenPGP(Open Pretty Good Privacy) 標準。OpenPGP 是一種加密標準,旨在提供數據加密和解密、數字簽名和數據完整性保護。
-
用途:主要用於保護電子郵件通信、文件存儲和數據傳輸的安全。它支持對稱加密、公鑰加密、哈希函數和消息認證碼(MAC),以及生成和驗證數字簽名。
-
示例:
import "golang.org/x/crypto/openpgp"
entity, _ := openpgp.NewEntity("name", "comment", "email", nil)
- 使用建議:OpenPGP 是一個強大、靈活和安全的加密標準,被廣泛用於各種安全協議和應用中,包括電子郵件加密、文件加密和數據傳輸加密。在許多現代安全應用中被推薦使用。
4.6.4 otr
-
功能:實現 Off-The-Record Messaging (OTR) 離線消息傳遞協議
-
用途:提供即時通訊場景的端到端加密,確保通信內容只能被預期的接收者閱讀,而不會被第三方竊聽或篡改。
-
示例:(使用較複雜,通常需要結合具體的即時通訊應用)
-
使用建議:在開發加密即時通訊應用時可以考慮使用
4.6.5 pkcs12
-
功能:實現 PKCS#12 標準 (Public-Key Cryptography Standards #12),PKCS#12 是由 RSA Laboratories 設計的,旨在定義一種標準格式,用於存儲和傳輸私鑰、公鑰和證書鏈。PKCS#12 文件通常以. p12 或. pfx 擴展名結尾。
-
用途:存儲和傳輸服務器證書、中間證書和私鑰
-
示例:
import "golang.org/x/crypto/pkcs12"
blocks, _ := pkcs12.ToPEM(pfxData, "password")
- 使用建議:PKCS#12 是一個強大、安全和標準化的密鑰和證書存儲格式,在需要安全存儲和傳輸加密密鑰和證書的應用中被推薦使用。不過該包已經凍結,如需要,可考慮 software.sslmate.com/src/go-pkcs12 的實現 (github.com/SSLMate/go-pkcs12)。
4.6.6 ssh
-
功能:實現 SSH 客戶端和服務器
-
用途:提供安全的遠程登錄和其他安全網絡服務
-
示例:
import "golang.org/x/crypto/ssh"
config := &ssh.ClientConfig{User: "user", Auth: []ssh.AuthMethod{ssh.Password("password")}}
- 使用建議:強烈推薦用於實現 SSH 功能
4.7 其他
4.7.1 poly1305
-
功能:實現 Poly1305 消息認證碼。Poly1305 是一種高速的消息認證碼(MAC)算法, 通常與 ChaCha20 流加密算法結合使用,形成 ChaCha20-Poly1305 組合,用於提供加密和消息認證的完整解決方案。
-
用途:用於消息認證,確保消息在傳輸過程中的完整性和真實性,未被篡改。
-
示例:
import "golang.org/x/crypto/poly1305"
var key [32]byte
var out [16]byte
poly1305.Sum(&out, msg, &key)
- 使用建議:這個包的實現已作廢,推薦使用 golang.org/x/crypto/chacha20poly1305
- Go 密碼學庫的現狀與後續方向
Gotime 在 2023 年末和今年年初對 Go 密碼學庫的前負責人 Filippo Valsorda 和現負責人 Roland Shoemaker 進行了三期訪談 (見參考資料),通過這三次訪談我們大約可以梳理出 Go 密碼學庫的現狀與後續方向:
-
RSA 後端實現的改進,提高了安全性和性能。
-
引入 godebug 機制 [10],允許在不破壞兼容性 [11] 的情況下逐步引入新的安全改進。
-
正在考慮對一些密碼學包進行 v2 版本的設計,以提供更高級和更易用的 API。
-
正在逐步棄用一些不安全的算法,如 SHA1 和 MD5。
-
簡化配置選項,減少用戶需要做的選擇,提供更多默認安全設置。
-
正在將 golang.org/x/crypto 中的重要包移入標準庫,以減少混淆,包括繼 TLS 之後的另外一個重要協議包 ssh 庫。
-
使用 BoringSSL 的 BoGo 測試套件來全面測試 Go 的 TLS 實現。
-
Go 密碼學庫正在實現這些新的後量子密碼算法 [12],但目前還沒有完全集成到標準庫中。
總的來說,Go 密碼學庫 (包括 golang.org/x/crypto) 正在積極發展和改進,同時也在爲後量子密碼學時代做準備。雖然後量子算法的完全集成和廣泛應用還需要一段時間,但 Go 團隊正在積極跟進這一領域的發展,努力在保持兼容性的同時提升安全性和性能。
- 小結
在這篇文章中,我們對 Go 生態中密碼學功能的核心:Go crypto 庫 (包括標準庫 crypto 相關包以及 golang.org/x/crypto 相關包) 進行了全面的瞭解,包括兩者的關係、整體結構設計原則以及每個庫的子包概覽。
我們看到:Go crypto 庫以其安全性、全面性、易用性、高性能以及與 Go 生態系統的高度集成而著稱。它不僅涵蓋了廣泛的加密算法和協議,還通過統一且直觀的 API 降低了使用門檻。
相信通過上述的瞭解,大家都已經理解了 Go crypto 庫的架構與設計思想,並建立起了一張 crypto 庫的 “地圖”。按照這幅圖的指示,大家可以根據具體需求,快速找到合適的密碼學包,並利用這些包構建安全可靠的 Go 應用。
- 參考資料
-
What's new in Go's cryptography libraries: Part 1[13] - https://changelog.com/gotime/295
-
What's new in Go's cryptography libraries: Part 2[14] - https://changelog.com/gotime/298
-
What's new in Go's cryptography libraries: Part 3[15] - https://changelog.com/gotime/313
-
Crypto 101: A Brief Tour of Practical Crypto in Golang[16] - https://cyberspy.io/articles/crypto101/
-
Go for Crypto Developers[17] - https://www.youtube.com/watch?v=2r_KMzXB74w
參考資料
[1]
Go crypto 庫: https://pkg.go.dev/crypto
[2]
Adam Langley(agl): https://www.imperialviolet.org/
[3]
Filippo Valsorda: https://blog.filippo.io/
[4]
Roland Shoemaker: https://github.com/rolandshoemaker
[5]
標準庫 context: https://tonybai.com/2022/11/08/understand-go-context-by-example
[6]
Go 1.23.0: https://tonybai.com/2024/08/19/some-changes-in-go-1-23/
[7]
Go1 兼容性承諾: https://go.dev/doc/go1compat
[8]
密碼存儲: https://tonybai.com/2023/10/25/understand-password-storage-of-web-app-by-example/
[9]
抵抗硬件暴力破解: https://tonybai.com/2023/10/25/understand-password-storage-of-web-app-by-example/
[10]
godebug 機制: https://tonybai.com/2024/10/11/go-evolution-dual-insurance-goexperiment-godebug
[11]
不破壞兼容性: https://tonybai.com/2023/09/10/understand-go-forward-compatibility-and-toolchain-rule
[12]
後量子密碼算法: https://en.wikipedia.org/wiki/Post-quantum_cryptography
[13]
What's new in Go's cryptography libraries: Part 1: https://changelog.com/gotime/295
[14]
What's new in Go's cryptography libraries: Part 2: https://changelog.com/gotime/298
[15]
What's new in Go's cryptography libraries: Part 3: https://changelog.com/gotime/313?ref=tonybai.com
[16]
Crypto 101: A Brief Tour of Practical Crypto in Golang: https://cyberspy.io/articles/crypto101/
[17]
Go for Crypto Developers: https://www.youtube.com/watch?v=2r_KMzXB74w
Gopher Daily(Gopher 每日新聞) - https://gopherdaily.tonybai.com
我的聯繫方式:
-
微博 (暫不可用):https://weibo.com/bigwhite20xx
-
微博 2:https://weibo.com/u/6484441286
-
博客:tonybai.com
-
github: https://github.com/bigwhite
-
Gopher Daily 歸檔 - https://github.com/bigwhite/gopherdaily
-
Gopher Daily Feed 訂閱 - https://gopherdaily.tonybai.com/feed
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/60eD5gN_QApnGkwITZRMpw