Building a Password Generator in Python with Provable Entropy
In the earlier posts, we counted a structured generator, discussed closed-form entropy, and measured password spaces in Python. Now we combine those ideas into a real implementation: a generator that is readable, policy-friendly, cryptographically random, and still mathematically analyzable.
Password Series
Build a real generator without losing the ability to measure its entropy exactly.
Use Python’s secrets module for cryptographically secure randomness.
This design produces about 69 bits of entropy in a readable format.
What we want from the generator
Our goal is to build a password generator that is:
- Human-readable
- Easier to remember than a fully arbitrary character string
- Compatible with common enterprise password policies
- Based on cryptographically secure randomness
- Backed by mathematically provable entropy
That combination is what makes the design interesting. We are trying to balance usability and analysis, not just maximize visual complexity.
Password structure
We will generate passwords using this structure:
segment-segment-segment
Each segment follows these rules:
- Each segment contains 3–5 lowercase letters
- The three segment letter-lengths must all be different
- Exactly one segment contains a digit
- Exactly one segment contains a symbol
- The digit and symbol cannot appear in the same segment
- Digits and symbols appear only as prefixes or suffixes
Password space and entropy
From the earlier analysis, the total number of passwords is:
\[ 5760 \cdot 26^{12} \]
That gives a total space of approximately:
\[ 5.50 \times 10^{20} \]
Entropy is therefore:
\[ H = \log_2(5760 \cdot 26^{12}) \approx 68.9 \]
So this generator provides roughly 69 bits of entropy.
Why secrets matters
Python’s secrets module is designed for security-sensitive randomness such as password generation.
import secrets
import string
This matters because the standard random module is not designed for password generation. A mathematically strong output format still needs a cryptographically strong random source.
Password generator in Python
import secrets
import string
def generate_password():
letters = string.ascii_lowercase
digits = string.digits
symbols = "!@#$%^&*"
lengths = [3, 4, 5]
secrets.SystemRandom().shuffle(lengths)
number_segment = secrets.randbelow(3)
symbol_segment = (number_segment + secrets.randbelow(2) + 1) % 3
segments = []
for i, length in enumerate(lengths):
core = "".join(secrets.choice(letters) for _ in range(length))
if i == number_segment:
digit = secrets.choice(digits)
if secrets.randbelow(2):
core = digit + core
else:
core = core + digit
elif i == symbol_segment:
sym = secrets.choice(symbols)
if secrets.randbelow(2):
core = sym + core
else:
core = core + sym
segments.append(core)
return "-".join(segments)
Sample passwords
Examples that match the stated structure:
7abc-defg-hijkl!
abc$-defg9-hijkl
abc4-!defg-hijkl
abcz-7defg-hijkl@
abc#-defg-hijkl5
These examples are not special because they “look complex.” They are useful because they visibly follow the same model we analyzed mathematically.
What the generator gets right
- High entropy from a countable combinatorial structure
- Cryptographic randomness from
secrets - A readable multi-segment format
- Compatibility with systems that expect a digit and symbol
This makes the design suitable for environments where both usability and strong temporary-password generation matter.
Why provable entropy matters in provisioning workflows
In enterprise identity systems, password generators often appear inside onboarding and account-provisioning workflows.
A script might:
- Create a user via API
- Generate a temporary password
- Assign the user to a group
- Require a password change at first login
In that context, “this password comes from a generator with a measured search space” is a much better property than “this password happens to satisfy a complexity checklist.”
Frequently Asked Questions
These are the practical questions that usually come up when building a password generator whose implementation matches a measurable entropy model.
Why use secrets instead of random for password generation?
Because secrets is designed for security-sensitive randomness. A strong password format still depends on a strong random source underneath it.
Why does this generator count as “provable” entropy?
Because the structure is explicit enough to count exactly. Once the number of valid outputs is known, entropy follows directly from \(\log_2(N)\).
Does readability automatically reduce security?
Not necessarily. Structure reduces freedom, but the remaining space can still be large. The important question is how big the counted search space still is after the constraints are applied.
Why keep the digit and symbol in different segments?
That rule is part of the design model. It preserves readability, keeps the structure analyzable, and is already accounted for in the entropy calculation.
Can I change the symbol set or segment rules later?
Yes, but changing the structure changes the password space. Once the rules change, the entropy analysis needs to be recomputed from the new model.
Why is this especially useful for enterprise onboarding?
Because temporary-password workflows benefit from generators that are both policy-friendly and measurable. It is much stronger to say the generator has a defined search space than to rely only on generic complexity rules.
Conclusion
A good password generator is not just an implementation detail. It is a mathematical object expressed in code.
By combining combinatorics, entropy analysis, and cryptographically secure randomness, we can build generators that are both practical and measurable.
That gives us a much stronger position from which to evaluate traditional password policies — which is exactly where the final post in this series goes next.
Previous: Measuring Password Entropy with Python
Next in the series: Why Most Password Complexity Rules Fail Mathematically
Raell Dottin
Comments
Post a Comment