Random binary string generator
Strings of ones and zeros drawn from the operating system CSPRNG. One character is exactly one bit.
More options
One bit per character, with nothing rounded
The alphabet has two symbols, so log2(2) is 1 and each character carries exactly one bit. Thirty-two characters is exactly 32 bits, or 4,294,967,296 possible values. There is no rejection: 2 is a power of two, so a single random bit maps onto the alphabet directly and every draw is accepted.
The one implementation detail that matters is padding. Converting a random 32-bit integer with toString(2) in JavaScript, or Integer.toBinaryString in Java, drops the leading zeros, so roughly half the time you get a string shorter than 32 characters. That is not a cosmetic problem: a variable-length output is no longer a uniform draw from the space of 32-character strings. Pad to the full width, or generate character by character as the tool above does.
| Characters | Bits | Distinct values |
|---|---|---|
| 8 | 8 | 256 |
| 16 | 16 | 65,536 |
| 32 | 32 | 4,294,967,296 |
| 64 | 64 | 1.84 x 10^19 |
| 128 | 128 | 3.40 x 10^38 |
| 256 | 256 | 1.16 x 10^77 |
What a genuinely random 32-bit string looks like
People reject real randomness for looking insufficiently random, and binary strings make that instinct visible. In 32 fair bits the expected number of ones is 16, with a standard deviation of 2.83. So anything from 11 to 21 ones sits inside two standard deviations and is completely ordinary. Getting exactly 16 ones happens only 13.99% of the time, which surprises people who expect the average to be the common case.
Runs behave the same way. A run of five or six identical bits somewhere in a 32-character string is unremarkable, and a string with no run longer than two would be the suspicious one. The chance of drawing all zeros is 1 in 4,294,967,296, which is small but not zero, and a generator that filters that outcome out is no longer uniform.
If you are using these strings as test fixtures, this is the reason not to hand-write them. A human-authored "random" bit pattern almost always has too few long runs and a count of ones too close to half.
A binary string is not binary data
Thirty-two characters of ones and zeros is a 32-byte ASCII string that carries 32 bits of information. The eightfold gap between what it costs and what it carries is the entire trade, and it is only worth paying when a human or a text-based tool has to read the individual bits.
If you want random bytes, generate bytes. If you want a compact token, hex carries four bits per character and Base64url carries six. Carrying 256 bits of key material as a binary string means a 256-character value, against 64 in hex and 43 in a 62-character alphabet. A binary string is not a sensible format for a secret.
Parsing has its own limit. In JavaScript, parseInt(s, 2) is exact only up to 53 bits, because that is the precision of a double. Beyond that use BigInt with the 0b prefix. In Java, Integer.parseInt on a 32-character string overflows for values with the top bit set, so Long.parseLong or Integer.parseUnsignedInt is the correct call.
A random binary string is uniform over strings, which includes 00000000000000000000000000000000. If your test suite treats zero as a sentinel, exclude it deliberately at the point of use rather than expecting the generator not to produce it.
Where a binary string is actually the right output
Test vectors for bit manipulation, where the expected result is easier to check when both input and output are written out bit by bit. Stimulus for an HDL testbench, where the signal is declared as a bit vector and the literal is written in binary. Bitmask and flag-field fixtures, where the meaning is positional. Seeds and initial states for shift registers and other bit-level algorithms. Teaching material, where the point is that each character is one bit.
In all of these the value is being read, compared or reasoned about at the bit level by a person, which is the only condition under which the eightfold size cost is worth paying.
Doing this in your own code
JavaScript
// 32 characters of "0" and "1". Exactly 32 bits.
const words = crypto.getRandomValues(new Uint32Array(1));
const bits = words[0].toString(2).padStart(32, "0");
// Longer than 32: build it from bytes, one byte at a time.
function randomBits(n) {
const bytes = crypto.getRandomValues(new Uint8Array(Math.ceil(n / 8)));
let s = "";
for (const b of bytes) s += b.toString(2).padStart(8, "0");
return s.slice(0, n);
} padStart is what keeps the leading zeros. toString(2) alone drops them, which silently shortens the string.
Python 3.6+
import secrets
format(secrets.randbits(32), "032b") # 32 characters
format(secrets.randbits(256), "0256b") # 256 characters
# randbits(k) is uniform over [0, 2**k), so every bit position is fair. Go
import (
"crypto/rand"
"encoding/binary"
"fmt"
)
var b [4]byte
if _, err := rand.Read(b[:]); err != nil {
panic(err)
}
v := binary.BigEndian.Uint32(b[:])
s := fmt.Sprintf("%032b", v) // the 032 keeps the leading zeros Java 8+
import java.security.SecureRandom;
int v = new SecureRandom().nextInt();
String s = String.format("%32s", Integer.toBinaryString(v)).replace(' ', '0');
// Integer.toBinaryString treats the value as unsigned, so a negative int
// still renders as 32 characters. Shorter values need the padding above. Shell
# 32 random bits as characters, via Python
python3 -c "import secrets; print(format(secrets.randbits(32), '032b'))"
# Or from /dev/urandom with xxd
head -c 4 /dev/urandom | xxd -b -c 4 | cut -d' ' -f2-5 | tr -d ' \n'; echo Questions
How many bits does a 32-character binary string contain?
Exactly 32. The alphabet has two symbols, so each character is one bit with nothing rounded. That is 4,294,967,296 possible values, which is far too few for anything that has to resist offline guessing.
Why does my binary string sometimes come out shorter than requested?
Because it was produced by converting a number rather than by drawing characters. toString(2) in JavaScript and Integer.toBinaryString in Java both drop leading zeros, so a value below the halfway point renders short. Pad the result to the full width, or generate one character at a time.
Is a random binary string suitable as a key or a password?
No, in the sense that it is a poor format for one. Each character carries one bit, so a 128-bit key needs 128 characters against 32 in hex. The bits are just as secure, but the format is eight times larger than it needs to be and nothing accepts it directly.
Why does my string have a run of six identical bits?
Because it is random. Runs of five and six are expected in a 32-bit string, and a sequence with no run longer than two would be a sign that something is filtering the output. Human intuition consistently underestimates run length in fair coin flips.
Can I convert the string to a number?
Up to a point. parseInt(s, 2) in JavaScript is exact only to 53 bits; past that use BigInt("0b" + s). In Java, Integer.parseInt overflows on a 32-character string whose top bit is set, so use Long.parseLong or Integer.parseUnsignedInt.