Understanding crypto/rand in Go (Hardware to Software)
Secure Randomness (Hardware, OS, Software)
Understanding crypto/rand in Go (Hardware to Software)
Secure Randomness (Hardware, OS, Software)
Photo by Agê Barros on Unsplash
Random number generation is at the heart of modern cryptography. Whether you’re generating passwords, tokens, nonces, or cryptographic keys — predictability is your enemy. That’s where Go’s crypto/rand package comes in.
Table of Contents
- Why Not Just Use math/rand?
- Introducing crypto/rand
- Code Examples
- How crypto/rand Works Under the Hood
- What is a CSPRNG?
- OS and Hardware Entropy
- Production Tips & Pitfalls
- Conclusion
Why Not Just Use math/rand?
Before diving into crypto/rand, let’s briefly understand the problem. The math/rand package is deterministic
rand.Seed(19)
fmt.Println(rand.Intn(100)) // Always the same value for seed 19
It’s fine for simulations or games, but It’s not secure. Given the seed, outputs are entirely predictable. If you use math/rand to generate passwords, an attacker can regenerate the same values, cause It uses a deterministic algorithm (a linear congruential generator).
Enter crypto/rand
The crypto/rand package provides cryptographically secure random numbers
It provides functions like:
rand.Read([]byte)rand.Int(rand.Reader, *big.Int)rand.Prime(rand.Reader, bits)
These are backed by true entropy sources and cryptographically secure algorithms.
Code Examples
- Generate a Secure Random Integer
package main
import (
"crypto/rand"
"fmt"
"math/big"
)
func main() {
max := big.NewInt(100)
n, err := rand.Int(rand.Reader, max)
if err != nil {
panic(err)
}
fmt.Println("Secure random number:", n)
}
- Generate Secure Random Bytes (Token)
func generateSecureToken(n int) (string, error) {
b := make([]byte, n)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return fmt.Sprintf("%x", b), nil
}
- Generate a Secure Prime (for crypto keys)
prime, err := rand.Prime(rand.Reader, 128)
if err != nil {
log.Fatal(err)
}
fmt.Println("Secure prime:", prime)
How Does crypto/rand Work Internally?
1. The rand.Reader
rand.Reader is a global, platform-specific source of random bytes. It's an io.Reader that wraps the OS’s secure randomness source.
- On Unix/Linux/macOS — Reads from
/dev/urandom - On Windows:Calls
BCryptGenRandomorCryptGenRandom(based on system version)
2. Behind the Scenes:
Here’s what happens when you call rand.Int(...)
n, err := rand.Int(rand.Reader, big.NewInt(100))
- Internally calls
rand.Reader.Read(...) - That calls a platform-specific implementation:
runtime/rand_unix.go: opens/dev/urandomor usesgetrandomsyscall.rand_windows.go: wraps Windows CSPRNG.- OS sources use entropy pools (collected from hardware-level noise) and generate random bytes via a CSPRNG like ChaCha20 or SHA-256.
What is a CSPRNG?
RNG stands for Random Number Generator. An RNG algorithm is a method (or function) that produces a sequence of numbers that appear to be random.
But there are two broad types:
1. True RNG (TRNG)
- Uses physical processes (e.g., radioactive decay, electrical noise).
- Hardware-based.
- Used when real randomness is needed (e.g., cryptography, lotteries).
2. Pseudo RNG (PRNG) — What most programming languages use
- Completely deterministic: given a seed, it always produces the same sequence.
- Fast and reproducible.
- Used for simulations, games, procedural content, etc.
CSPRNG: A Cryptographically Secure Pseudo-Random Number Generator:
- Generates random-looking numbers.
- Resistant to prediction — even if the attacker knows some outputs.
- Periodically reseeded with real entropy.
- Used in key generation, session tokens, TLS, etc.
Hardware and OS: How Entropy Gets to Go
Hardware Entropy Sources
- Thermal noise in CPUs
- Clock drift/jitter
- User input timing
- TPM (Trusted Platform Module)
- CPU instructions like RDRAND/RDSEED
OS Entropy Pool
The OS maintains an internal entropy pool that’s constantly fed by:
- Hardware noise
- Kernel events (disk IO timing, IRQ timing)
- Daemons like
havegedorrngd
Linux uses ChaCha20-based CSPRNG since kernel 5.6 to generate random data from this pool. /dev/urandom and getrandom() both draw from this. Go reads from this OS-level secure randomness via rand.Reader.
Production Tips & Pitfalls
- Avoid
/dev/randomin production—it can block if entropy is low./dev/randomgathers environmental noise (entropy) from hardware events like keyboard strokes, mouse movements, disk activity, and network traffic. If the entropy pool is depleted,/dev/randomwill block, waiting for more entropy to be gathered. This can cause significant delays in applications that rely on it. /dev/urandomalso uses the kernel's entropy pool, but it doesn't block. If the entropy pool is low, it will generate pseudo-random numbers using a cryptographically secure pseudo-random number generator (CSPRNG).- VMs and containers often lack direct access to physical hardware events that generate entropy (e.g., disk I/O, hardware interrupts). Cloud providers and data centers often equip their host systems with HRNGs. AWS usses its Nitro System, which includes a dedicated HRNG.

Fig: Flow of entropy and randomness read
Conclusion
The crypto/rand package in Go provides a high-level, secure, and cross-platform interface to generate unpredictable random data—essential for any cryptographic operation.
By relying on the operating system’s secure entropy pool and modern cryptographic algorithms, it ensures that the randomness you get is safe, reliable, and production-ready. Security is only as strong as your randomness. Don’t roll your own — use crypto/rand
메타데이터
- post_id
- 51798d3ebcbd
- slug
- understanding-crypto-rand-in-go-hardware-to-software-51798d3ebcbd
- url
- https://medium.com/@smafjal/understanding-crypto-rand-in-go-hardware-to-software-51798d3ebcbd
- canonical_url
- https://medium.com/@smafjal/understanding-crypto-rand-in-go-hardware-to-software-51798d3ebcbd
- author_url
- https://medium.com/@smafjal
- status
- ok
- fetched_at
- 2026-07-20 09:42:25