crypto, hash, rand, and regexp
crypto, hash, rand, and regexp
Overview
Last stdlib essentials for integrity, randomness, and text matching.
| Package | Use |
|---|---|
crypto/sha256 (etc.) |
Content hashes, integrity |
crypto/hmac |
Message authentication |
crypto/rand |
Secure random bytes |
math/rand/v2 |
Non-secure randomness / sims |
crypto/subtle |
Constant-time compare |
crypto/mldsa |
Post-quantum ML-DSA signatures (Go 1.27+; also TLS/x509) |
uuid |
Generate/parse UUIDs (Go 1.27+; RFC 9562) |
regexp |
Regular expressions |
net/url |
URL parse (with HTTP chapter) |
TLS deep dive: Security hardening.
Hashing
sum := sha256.Sum256([]byte("hello"))
fmt.Printf("%x\n", sum)
h := sha256.New()
io.Copy(h, r)
digest := h.Sum(nil)Streaming hash large inputs — do not ReadAll multi-GB files first.
HMAC
mac := hmac.New(sha256.New, key)
mac.Write(msg)
sig := mac.Sum(nil)
if !hmac.Equal(sig, expected) {
return errUnauthorized
}Use hmac.Equal / subtle.ConstantTimeCompare — not == on strings for secrets.
Randomness
// Secure tokens / keys
b := make([]byte, 16)
if _, err := rand.Read(b); err != nil { // crypto/rand
return err
}
token := hex.EncodeToString(b)
// Simulations, randomized tests (not secrets)
n := rand.IntN(100) // math/rand/v2Never use math/rand for session IDs, API keys, or CSRF tokens.
uuid (Go 1.27+)
Stdlib uuid covers the common cases that used to need github.com/google/uuid:
import "uuid"
id := uuid.New() // currently v4
id = uuid.NewV7() // time-ordered; good for DB keys
s := id.String()
parsed, err := uuid.Parse(s)New() is the default; use NewV7() when insertion order / index locality matters. Random bits come from a cryptographically secure generator.
Go 1.27 also adds crypto/mldsa (FIPS 204) with crypto/x509 and crypto/tls integration for post-quantum signatures. Treat it as an opt-in for new PKI work, not a drop-in replacement for existing ECDSA certs.
regexp
re := regexp.MustCompile(`(?i)^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$`)
ok := re.MatchString(email)
parts := re.FindStringSubmatch(s)Performance tips
- Compile once (
var re = regexp.MustCompile(...)at package scope). - Prefer
strings/bytesfor fixed-prefix checks. - Beware catastrophic backtracking on untrusted patterns/input — keep patterns simple.
- Use
regexp.Compilewhen pattern comes from config; handle errors.
const max = 1024
if len(s) > max {
return false
}
return re.MatchString(s)Password hashing note
Stdlib does not include bcrypt/argon2. For passwords use golang.org/x/crypto/bcrypt or argon2 — do not roll SHA256(password).
Runnable example
go mod init example
go run .package main
import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
"fmt"
mrand "math/rand/v2"
"regexp"
)
func main() {
sum := sha256.Sum256([]byte("hello"))
fmt.Println("sha256", hex.EncodeToString(sum[:])[:16]+"...")
key := []byte("secret-key")
msg := []byte("payload")
mac := hmac.New(sha256.New, key)
mac.Write(msg)
sig := mac.Sum(nil)
mac2 := hmac.New(sha256.New, key)
mac2.Write(msg)
fmt.Println("hmac ok?", hmac.Equal(sig, mac2.Sum(nil)))
// constant-time compare demo
a := []byte("abcd")
b := []byte("abce")
fmt.Println("subtle", subtle.ConstantTimeCompare(a, b) == 1)
tok := make([]byte, 8)
_, _ = rand.Read(tok)
fmt.Println("token", hex.EncodeToString(tok))
fmt.Println("sim roll", mrand.IntN(6)+1)
re := regexp.MustCompile(`^item-(\d+)$`)
m := re.FindStringSubmatch("item-42")
fmt.Println("submatch", m)
}Expected output (token varies):
sha256 2cf24dba5fb0a30e...
hmac ok? true
subtle false
token a1b2c3d4e5f67890
sim roll 4
submatch [item-42 42]
What to notice: - HMAC equality is constant-time via hmac.Equal. - crypto/rand for tokens; math/rand/v2 for games/sims. - Submatch index 0 is the full match; 1+ are groups.
Try next: Stream-hash a file with sha256.New + io.Copy and compare to shasum -a 256 on the command line.
Stdlib tour wrap-up
You now have a map of the packages that appear in nearly every Go binary. Next steps:
- Rebuild a small CLI using only parts 980–992.
- Rebuild a tiny JSON API with timeouts and
slog. - Jump to specialized parts only when stdlib friction is real.
Return to the stdlib overview checklist and mark what you can do without docs.