Skip to content

Marcos' auto-password generation + bits...#74

Open
JedMeister wants to merge 2 commits intoturnkeylinux:masterfrom
JedMeister:marcos-auto-pass
Open

Marcos' auto-password generation + bits...#74
JedMeister wants to merge 2 commits intoturnkeylinux:masterfrom
JedMeister:marcos-auto-pass

Conversation

@JedMeister
Copy link
Copy Markdown
Member

This is #71 plus docstrings replaced (removed in PR?) and typing fixed (the original typing was wrong (not show how?!).

The functionality that it adds remains the same as @marcos-mendez added in #71 - i.e.:


  • Add generate_password() using secrets module (CSPRNG)
  • get_password() now offers 'Generate' (recommended) or 'Manual' menu
  • Generated passwords shown in centered reverse-video box with colors
  • Confirmation step ensures user saved the password before proceeding
  • Fully backward compatible: offer_generate=True by default
  • Pass offer_generate=False for original behavior
  • Imports: added secrets, string (stdlib only)

PopSolutions and others added 2 commits March 26, 2026 05:32
- Add generate_password() using secrets module (CSPRNG)
- get_password() now offers 'Generate' (recommended) or 'Manual' menu
- Generated passwords shown in centered reverse-video box with colors
- Confirmation step ensures user saved the password before proceeding
- Fully backward compatible: offer_generate=True by default
- Pass offer_generate=False for original behavior
- Imports: added secrets, string (stdlib only)
@JedMeister JedMeister requested a review from OnGle April 10, 2026 04:34
@JedMeister JedMeister changed the title Marcos auto pass Marcos' auto-password generation + bits... Apr 10, 2026
Copy link
Copy Markdown
Member

@OnGle OnGle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good but there are issues that need addressing.

self.console.add_persistent_args(["--no-collapse"])
self.console.add_persistent_args(["--backtitle", title])
self.console.add_persistent_args(["--no-mouse"])
self.console.add_persistent_args(["--colors"])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Color support should be detected automatically, if we force it it'll make non-color supporting terminals break output inconsistent output.

Comment on lines +37 to +67
def generate_password(length: int = 20) -> str:
"""Generate a cryptographically secure random password.

Uses the secrets module (CSPRNG). Guarantees at least one character
from each of the 4 complexity categories (uppercase, lowercase,
digit, symbol). Avoids shell-problematic characters.
"""
if length < 12:
length = 12

uppercase = string.ascii_uppercase
lowercase = string.ascii_lowercase
digits = string.digits
symbols = "!@#%^&*_+-=?"

required = [
secrets.choice(uppercase),
secrets.choice(lowercase),
secrets.choice(digits),
secrets.choice(symbols),
]

all_chars = uppercase + lowercase + digits + symbols
remaining = [secrets.choice(all_chars) for _ in range(length - len(required))]

chars = required + remaining
for i in range(len(chars) - 1, 0, -1):
j = secrets.randbelow(i + 1)
chars[i], chars[j] = chars[j], chars[i]

return "".join(chars)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually quite nice. I will note that as bad as it is, we will need to remove the length < 12 check, or we should assert(length >= 12) because if an appliance actually requires a password to be smaller than that, this will silently cause a broken password.

Comment on lines +243 to +244
assert isinstance(return_tuple, tuple)
return return_tuple[0]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent handling of type assertions, earlier we wrapped a value in a str(...) call, here we assert it's type. We should do this consistently unless we have a good reason not too.

@marcos-mendez
Copy link
Copy Markdown
Member

Thanks for the review @OnGle, all fair points. Here's my take on each:

--colors

Agreed. I'll remove the forced --colors flag — the password display can work fine without color formatting, and breaking serial consoles or basic terminals isn't worth it.

Type assertion consistency

Good catch. I'll unify on str() wrapping throughout — it's more defensive and matches the existing pattern.

length < 12 — assert, not silently adjust

I agree with using assert instead of silently bumping. But I'd actually propose 16 as the minimum, not 12.

Every password set during TKL firstboot is a privileged credential — root, database root, application admin. NIST SP 800-63B already recommends 15+ characters for privileged accounts. We're already generating 20-char passwords by default in generate_password(), so assert length >= 16 just ensures nobody accidentally lowers the floor.

For context, the current headless preseed (29preseed) uses mcookie | cut --bytes 1-8 — that's 8 hex-only characters from [0-9a-f]. This was already flagged as broken in tracker #889 because it didn't meet Samba4's complexity requirements. The preseed should probably be updated to use generate_password() too.

A note on hashing algorithms and post-quantum readiness

The password length discussion is really only half the picture — the other half is how the password gets hashed and stored. We're entering a transition period in electronic security, and I think it's worth having an honest conversation about where TKL stands, even if the full solution is beyond the scope of this PR.

What TKL can control (system-level):

  • Linux root / PAM: Debian Trixie defaults to yescrypt in /etc/pam.d/common-password. This is good — yescrypt is memory-hard, resistant to GPU/ASIC attacks, and its security properties hold even under Grover's algorithm (which halves effective entropy for quantum brute-force). Argon2id would be the gold standard, but it's [still not in libxcrypt]([RFC] Add argon2 backend. besser82/libxcrypt#113). We should at least verify that TKL v19 ships with yescrypt as the default and document it.

  • PostgreSQL: Default is scram-sha-256 since PG 14. SHA-256 provides 128-bit security under quantum (Grover halves 256→128), which is adequate. We should ensure the TKL PostgreSQL appliance enforces password_encryption = 'scram-sha-256' and doesn't fall back to md5.

  • MariaDB: caching_sha2_password (SHA-256 based) should be the default. We should verify no appliance is still using mysql_native_password.

What TKL can't control (application-level):

Each web application (WordPress, Nextcloud, GitLab, etc.) uses its own password hashing — bcrypt, Argon2, PBKDF2, or worse. That's out of TKL's scope, but at the infrastructure level (root + database), we can and should set a strong baseline.

The practical takeaway: A 16-char password with full complexity gives ~100 bits of classical entropy, ~50 bits under Grover's. Combined with memory-hard hashing (yescrypt), brute-force remains infeasible even with quantum. The password length floor and the hashing algorithm are complementary defenses — getting both right now avoids rework later.

If any appliance today requires passwords shorter than 16 characters, that's a bug in the appliance — not a reason to weaken the generator.

Apologies for the long response, but I believe we should always invest in a solid foundation — it saves a lot of headaches down the road.


I'll push the fixes once we align on the approach. Happy to open a separate issue for the hashing algorithm audit if there's interest.

@OnGle
Copy link
Copy Markdown
Member

OnGle commented Apr 14, 2026

Good catch. I'll unify on str() wrapping throughout — it's more defensive and matches the existing pattern.

I personally don't like defensive programming on anything that isn't public facing, but this is a side concern for a later date, probably in the policy discussion. For now this addresses my explicit concern.

For context, the current headless preseed (29preseed) uses mcookie | cut --bytes 1-8 — that's 8 hex-only characters from [0-9a-f]. This was already flagged as broken in tracker #889 because it didn't meet Samba4's complexity requirements. The preseed should probably be updated to use generate_password() too.

Good point, but out of scope for this PR.

A note on hashing algorithms and post-quantum readiness

Good points, but out of scope for this PR.

I agree with using assert instead of silently bumping. But I'd actually propose 16 as the minimum, not 12.
...
If any appliance today requires passwords shorter than 16 characters, that's a bug in the appliance — not a reason to weaken the generator.

I agree broadly, but this may break legacy systems, legacy game servers, services that users might need for backwards compatibility with existing systems they are not able to upgrade or migrate and aren't publicly exposed anyway.

Setting the requirement too high here risks causing issues for developers who never even intended on producing public images or using them on a public network.

Apologies for the long response, but I believe we should always invest in a solid foundation — it saves a lot of headaches down the road.

I appreciate your intention and agree, but please try and keep discussion relevant to the specific PRs/issues being worked on. At this time in our release cycle larger more broad concerns should be added as separate issues and deferred until after 19.0


Also I just realized that we need to be able to configure which characters are included and which are not, I don't recall if there still is but I believe there was at least one appliance that explicitly blacklisted "

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants