Crypto recipe
Secure random bytes
Generate cryptographically secure random bytes for keys, nonces, salts, and tokens.
Almost everything in cryptography starts with unpredictable bytes: keys, nonces, IVs, salts, tokens, password-reset codes. Get this wrong and nothing built on top of it is safe.
Every language ships a cryptographically secure pseudo-random number generator (CSPRNG) backed by the operating system. Use it. The fast, seedable, general-purpose PRNGs — Go's math/rand, Python's random, Java's java.util.Random, C's rand() — are predictable and must never produce secrets.
Get it right
- Use the CSPRNG, never a general-purpose PRNG, for anything secret.
- Never seed a CSPRNG yourself — the OS manages entropy for you.
- Generate a fresh value wherever one is required; don't reuse nonces or salts.
- To choose a number in a range, use a dedicated helper so you avoid modulo bias.
Implementation
Setup Standard library (crypto/rand). Never use math/rand for secrets.
package main
import (
"crypto/rand"
"encoding/hex"
"fmt"
)
func main() {
// 32 cryptographically secure random bytes — e.g. an AES-256 key or a token.
key := make([]byte, 32)
if _, err := rand.Read(key); err != nil {
panic(err) // the OS CSPRNG failed; do not continue with weak randomness.
}
fmt.Println(hex.EncodeToString(key))
} Setup Standard library (secrets). Never use the random module for secrets.
import secrets
# 32 cryptographically secure random bytes — e.g. a key.
key = secrets.token_bytes(32)
# Need a URL-safe string token instead (session id, reset code)?
token = secrets.token_urlsafe(32) Setup Built in (node:crypto). Never use Math.random() for secrets.
import { randomBytes, randomInt } from 'node:crypto';
// 32 cryptographically secure random bytes — e.g. a key.
const key = randomBytes(32);
// A random int in [0, 100) with no modulo bias:
const n = randomInt(0, 100);
console.log(key.toString('hex')); In the browser/edge runtimes use WebCrypto: crypto.getRandomValues(new Uint8Array(32)).
Setup Built in (System.Security.Cryptography). Never use System.Random for secrets.
using System.Security.Cryptography;
// 32 cryptographically secure random bytes — e.g. a key.
byte[] key = RandomNumberGenerator.GetBytes(32);
// A random int in [0, 100) with no modulo bias:
int n = RandomNumberGenerator.GetInt32(0, 100); Setup libsodium: apt install libsodium-dev, compile with -lsodium.
#include <sodium.h>
int main() {
if (sodium_init() < 0) return 1; // library failed to initialise
unsigned char key[32];
randombytes_buf(key, sizeof key); // OS CSPRNG; cannot fail once initialised
} Setup Built in (java.security.SecureRandom).
import java.security.SecureRandom;
// One shared, thread-safe instance; the default is a strong OS-backed CSPRNG.
SecureRandom random = new SecureRandom();
byte[] key = new byte[32];
random.nextBytes(key); // 32 cryptographically secure random bytes Don't call setSeed() before first use, and never use java.util.Random for secrets.
Setup Cargo.toml: rand = "0.8". (The getrandom crate alone also returns raw OS bytes.)
use rand::rngs::OsRng;
use rand::RngCore;
fn main() {
let mut key = [0u8; 32];
OsRng.fill_bytes(&mut key); // 32 bytes straight from the OS CSPRNG
}