crypto/*, compress & math/rand/v2
Hashing, encryption primitives, compression, and randomness live in focused stdlib packages.
Security-sensitive randomness comes from crypto/rand; simulation and shuffling use math/rand/v2.
Compression packages wrap io.Reader and io.Writer so HTTP and file pipelines stay streaming.
Summary
Use crypto/sha256 and friends for checksums and content addressing.
Use crypto/tls and crypto/x509 for HTTPS listeners and mutual TLS.
Use compress/gzip to shrink payloads without loading entire files into memory.
Treat math/rand/v2 as the modern API for non-crypto randomness with explicit Rand values.
Recipe
Quick-reference recipe card - copy-paste ready.
import (
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"io"
)
h := sha256.New()
_, _ = io.Copy(h, reader)
sum := hex.EncodeToString(h.Sum(nil))
token := make([]byte, 32)
_, _ = rand.Read(token)When to reach for this:
- Computing stable hashes for cache keys or integrity checks.
- Generating session tokens, API keys, or nonce bytes.
- Compressing log archives or HTTP responses with gzip.
- Shuffling test fixtures or running simulations with seeded
rand/v2.
Working Example
package main
import (
"bytes"
"compress/gzip"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"math/rand/v2"
)
func hashAndCompress(in []byte) (digest string, compressed []byte, err error) {
h := sha256.New()
if _, err = h.Write(in); err != nil {
return "", nil, err
}
digest = hex.EncodeToString(h.Sum(nil))
var buf bytes.Buffer
zw := gzip.NewWriter(&buf)
if _, err = zw.Write(in); err != nil {
zw.Close()
return "", nil, err
}
if err = zw.Close(); err != nil {
return "", nil, err
}
return digest, buf.Bytes(), nil
}
func secureToken(n int) (string, error) {
b := make([]byte, n)
if _, err := rand.Read(b); err != nil {
return "", err
}
return hex.EncodeToString(b), nil
}
func shuffleDemo(seed uint64, items []string) []string {
r := rand.New(rand.NewPCG(seed, seed^0x9e3779b97f4a7c15))
out := append([]string(nil), items...)
r.Shuffle(len(out), func(i, j int) { out[i], out[j] = out[j], out[i] })
return out
}
func main() {
payload := []byte("hello stdlib")
digest, gz, err := hashAndCompress(payload)
if err != nil {
panic(err)
}
fmt.Println("sha256:", digest)
fmt.Println("gzip bytes:", len(gz))
tok, err := secureToken(16)
if err != nil {
panic(err)
}
fmt.Println("token:", tok)
fmt.Println(shuffleDemo(42, []string{"a", "b", "c", "d"}))
}What this demonstrates:
sha256.Newasio.Writerfor incremental hashing.gzip.NewWriterwith mandatoryCloseto flush trailers.crypto/rand.Readfor unpredictable tokens.math/rand/v2with explicitPCGsource andShuffle.
Deep Dive
How It Works
- Hash functions implement
hash.Hash(Write,Sum,Reset) for streaming input. crypto/randreads from the OS CSPRNG (getrandom,/dev/urandom, etc.).gzip.Writercompresses into an underlyingio.Writer; readers decompress symmetrically.math/rand/v2removes global mutable state from the legacymath/randpackage design.
Package Map
| Package | Role | Crypto-safe? |
|---|---|---|
crypto/sha256 | Digest | N/A (hash, not secrecy) |
crypto/rand | Random bytes | Yes |
crypto/tls | TLS config and handshakes | Yes (when configured correctly) |
compress/gzip | DEFLATE + gzip framing | N/A |
math/rand/v2 | Fast pseudo-random | No |
Go Notes
// Compare digests in constant time when guarding secrets:
import "crypto/subtle"
subtle.ConstantTimeCompare(a, b) == 1
// TLS minimum version for servers:
cfg := &tls.Config{MinVersion: tls.VersionTLS12}Gotchas
- Using math/rand for tokens - Predictable output enables session hijacking. Fix:
crypto/rand.Readfor secrets; rand/v2 only for non-security uses. - Forgetting gzip.Writer.Close - Missing gzip footer corrupts compressed output. Fix: always
Closeand check error. - Reusing hash.Hash after Sum without Reset - Appends to prior state unexpectedly. Fix: call
Resetbefore hashing a new payload on the same instance. - Assuming SHA-256 is encryption - Hashes are one-way; they do not encrypt confidential data. Fix: use
crypto/aesor TLS for confidentiality. - Global math/rand in libraries - Tests become flaky when order changes. Fix: inject
*rand.Randfrom rand/v2 with explicit seed in tests. - Compressing small payloads - Gzip headers can enlarge tiny bodies. Fix: skip compression below a size threshold (often 1-2 KiB).
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
blake2 / bcrypt modules | Password hashing needs | Simple content checksums (sha256 suffices) |
zstd third-party | Better compression ratio | Stdlib-only deployment required |
openssl bindings | Legacy cipher requirements | Go tls covers modern deployments |
| Hardware security modules | Key material never in RAM | Local dev and small services |
FAQs
When do I use crypto/rand versus math/rand/v2?
crypto/rand for keys, tokens, and anything an attacker guessing would break.
math/rand/v2 for simulations, load test jitter, and deterministic test shuffles with explicit seeds.
What changed in math/rand/v2?
Explicit Rand values replace hidden global state.
Algorithms like PCG and ChaCha8 are available with clearer seeding APIs.
Legacy math/rand remains for compatibility.
How do I hash large files without loading RAM?
Open the file, io.Copy into sha256.New(), then Sum(nil).
Same pattern works for MD5 and SHA-512 hashers.
Is gzip the same as zip?
No.
compress/gzip is a single-stream gzip wrapper.
ZIP archives need archive/zip, a different format.
Where do TLS certificates live in Go servers?
Pass tls.Config with Certificates or GetCertificate to http.Server or tls.Listen.
Load PEM files with tls.LoadX509KeyPair or use ACME automation externally.
Can I compress HTTP responses with stdlib only?
Yes.
Wrap ResponseWriter with gzip.NewWriter, set Content-Encoding: gzip, and flush on handler completion.
Respect Accept-Encoding from clients.
What is crypto/subtle for?
Constant-time comparison and byte operations that reduce timing side channels.
Use when comparing MACs or hashed secrets.
Should I use MD5 for checksums?
Fine for non-adversarial duplicate detection.
Avoid MD5 for security contexts; prefer SHA-256 when attackers can pick inputs.
How do I seed rand/v2 for reproducible tests?
rand.New(rand.NewPCG(seed1, seed2)) and pass the *rand.Rand into code under test.
Do not rely on global seed functions in parallel tests.
Does compress/gzip support best compression level?
gzip.NewWriterLevel(w, gzip.BestCompression) trades CPU for size.
Default is DefaultCompression balancing speed and ratio.
Are hash outputs safe to log?
Hashes of public content are fine.
Hashes of secrets still leak equality information; treat carefully in multi-tenant logs.
How does flate relate to gzip?
compress/flate implements DEFLATE.
compress/gzip adds gzip headers and checksum around flate streams.
Related
- os, io, bufio & path/filepath - Streaming data into hashers
- database/sql & net Package Family Overview - TLS listeners and drivers
- log, regexp & text/template - Encoding tokens in logs safely
- Standard Library Best Practices - Security and dependency rules
- net/http Best Practices - TLS and response compression
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).