Generate Safe Random Bytes with OpenSSL rand
You will generate random bytes with the OpenSSL rand command, choose an output encoding, and verify the byte count without accidentally printing binary data in your terminal. The examples use OpenSSL 3.0.13 from the installed openssl package, version 3.0.13-0ubuntu3.15.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes. You need a shell and the OpenSSL package. The commands are ordinary, unprivileged operations. They generate new data, but do not alter system configuration or services.
1. Check the installed command
Confirm which executable you will run and inspect its version:
$ command -v openssl
/usr/bin/openssl
$ /usr/bin/openssl version
OpenSSL 3.0.13 30 Jan 2024 (Library: OpenSSL 3.0.13 30 Jan 2024)
The subcommand is written as openssl rand, not as a separate executable named openssl-rand. The manpage describes num as the number of random bytes to generate. Keep that unit in mind when comparing it with encoded output, whose character count is usually larger.
Checkpoint
If command -v openssl points somewhere else, stop and check that version's documentation before copying examples into a script.
2. Generate binary bytes into a file
Use -out when the result is binary or when another program will consume it. This example creates a new file in /tmp:
$ /usr/bin/openssl rand -out /tmp/example-random.bin 32
$ stat -c '%n: %s bytes' /tmp/example-random.bin
/tmp/example-random.bin: 32 bytes
The command asks for 32 random bytes, so the file size should be exactly 32. The contents are intentionally unpredictable, and there is no useful fixed output to compare. Use stat or a programmatic length check rather than opening the file in a terminal.
The destination is truncated if it already exists. That is a destructive change to that one file. Choose a new pathname, or protect an existing file first:
$ cp --preserve=all /path/to/existing.bin /path/to/existing.bin.bak
$ /usr/bin/openssl rand -out /path/to/existing.bin.new 32
$ stat -c '%s' /path/to/existing.bin.new
32
$ mv /path/to/existing.bin.new /path/to/existing.bin
The final mv is the point at which the replacement happens. If generation or verification fails, remove only the .new file and the original remains. Restore the backup with mv /path/to/existing.bin.bak /path/to/existing.bin if you need to undo the replacement. Do not remove the backup until the new file has been checked.
3. Print hexadecimal for text-oriented uses
Use -hex when a human or a configuration field needs printable characters. Eight bytes become 16 hexadecimal characters:
$ /usr/bin/openssl rand -hex 8
<16 lowercase hexadecimal characters>
The line ends with a newline, but the random value itself contains 16 characters. Verify the shape without displaying the value again:
$ value=$(/usr/bin/openssl rand -hex 8)
$ test "${#value}" -eq 16 && printf '%s\n' 'hex value has 16 characters'
hex value has 16 characters
Hexadecimal is an encoding, not extra randomness. The command still generated eight bytes. If a service requests a 32-byte secret, use -hex 32, which produces 64 hexadecimal characters, rather than assuming that 32 visible characters represent 32 bytes.
4. Use Base64 when compact text matters
-base64 encodes the requested bytes as Base64. It is more compact than hexadecimal, but the output is still text and may contain characters such as +, / and =. Treat it as one opaque value and quote it when assigning it to a shell variable:
$ token=$(/usr/bin/openssl rand -base64 24)
$ printf 'Base64 characters: %s\n' "${#token}"
Base64 characters: 32
Twenty-four bytes encode to 32 Base64 characters in this case. Do not trim padding or pass the value through a command that changes whitespace unless the receiving protocol explicitly requires that. For a password, token or key, avoid putting the value in a command line or shell history. Prefer the receiving program's protected secret-input mechanism.
Base64 output is normally followed by a newline. If a consumer needs the exact encoded value without a line ending, remove only that final newline in a controlled shell assignment, or use the consumer's documented input format. Do not remove arbitrary characters from a value you have not decoded and verified.
5. Check failures and security boundaries
OpenSSL uses its cryptographically secure pseudo-random number generator. The installed manpage says the command succeeds only if it seeds itself from a trusted operating-system entropy source. A non-zero status means generation failed; do not substitute timestamps, process IDs or an old output file.
$ /usr/bin/openssl rand -out /tmp/example-random.bin 32
$ status=$?
$ printf 'openssl rand status: %s\n' "$status"
openssl rand status: 0
Capture the status immediately. A later command changes $?. For scripts, fail closed if the command does not return zero and verify the destination size before using it:
output=/tmp/example-random.bin
if ! /usr/bin/openssl rand -out "$output" 32; then
printf '%s\n' 'random-byte generation failed' >&2
exit 1
fi
if [ "$(stat -c '%s' "$output")" -ne 32 ]; then
printf '%s\n' 'random output has the wrong size' >&2
exit 1
fi
Do not use sudo just because the value is security-sensitive. Generate it as the account that will safely store or consume it. Use elevated privileges only when the destination directory genuinely requires them, and check ownership and permissions afterwards. A random value is not protected merely because it was generated with OpenSSL.
6. Avoid the common traps
- Do not run binary output directly in a terminal. Redirect it to a file or pipe it to the program that expects bytes.
- Do not confuse bytes with encoded characters:
-hex 16prints 32 hex characters, while-base64 16prints 24 Base64 characters. - Do not overwrite an existing key, seed or token casually. Use a temporary destination and verify it before an atomic replacement.
- Do not treat a successful command as proof that a secret is stored safely. Review file permissions, logs, shell history and process arguments separately.
- The
-engineoption is deprecated in OpenSSL 3.0. The provider options are for selecting OpenSSL providers and properties; leave them at their defaults unless your deployment has a documented provider requirement.
Done means
- You confirmed the intended OpenSSL executable and version.
- You generated the requested number of bytes and checked the output size.
- You selected binary, hexadecimal or Base64 output for the actual consumer.
- Your script checks the command status before using generated data.
- You avoided terminal display, accidental overwrite and unnecessary privilege escalation.