Random string generator

Random strings with the entropy worked out honestly — including the fact that requiring one of each character class makes the keyspace SMALLER, and by exactly how much. Nothing you type here leaves your browser — it is worked out on your own device, so there is nothing to send and nothing to log.

This page will not fall back to Math.random(). Everything here is drawn from crypto.getRandomValues(), which the browser backs with the operating system's cryptographic source. If that is unavailable the page says so and produces nothing — because output from a weak source looks exactly like output from a strong one, and that is the whole problem.

“Must contain one of each” makes it weaker

This is the rule on almost every sign-up form, and almost everybody has it backwards. Requiring at least one digit and one symbol does not add strength. It removes every string that does not have them, so the set of allowed passwords gets smaller.

The size of the reduction is exactly computable, by inclusion-exclusion. Over the full 94-character set:

LengthNo rule All four classes requiredCost
852.44 bits51.32 bits 1.12 bits
1278.66 bits78.14 bits 0.51 bits
16104.87 bits104.59 bits 0.28 bits

The cost is small, and it is a cost. The rule is not useless — it stops a human choosing “password” — but applied to a string that was already random it can only subtract. If a generator quotes log₂(948) while enforcing the rule, its figure is wrong, and this page shows both.

The real lesson is the other way round: length beats character classes. Adding two characters to a lower-case-only string is worth 9.4 bits; adding symbols to an eight-character one is worth 14.8. Adding four characters beats both.

When two of these will collide

If you are using these as identifiers rather than passwords, the question is not “can it be guessed” but “when will two be the same”. The answer is the birthday problem: a 50% chance of a repeat after about 1.177 × √N draws, where N is the number of possible strings.

That square root is brutal. Eight lower-case letters and digits give 2.8 × 1012 possibilities — and an even chance of a collision after fewer than two million of them.

Where the randomness comes from

Every character is drawn with crypto.getRandomValues() and the uneven tail of the range is rejected rather than reduced with a remainder — which would quietly favour the first few characters of the alphabet. If the source is missing, this page produces nothing.

Where to go next