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.

Go
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.

Python
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.

Node.js
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.

.NET
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.

C++
#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).

Java
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.)

Rust
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
}