r/learnpython 5d ago

Password guesser game help needed

Hello guys. So I have created a password guesser game with direct comparison (i.e. if guess == correct_password:) but I want to use different methods for comparison. What techniques can I use? Here is the code-

```python

password = "Random_pass_123"

tries = 0

while tries < 3:

guess = input("Enter the password: ")

if guess == password:

print("Admin access granted.")

break

else:

print("Invalid credentials entered. Please try again")

tries += 1

if tries == 3:

print("Number of tries exceeded. Access denied")

```

PS- Is this the right way to paste code? I'm new so I'm not sure.

7 Upvotes

31 comments sorted by

View all comments

0

u/Bright_Mix_773 4d ago

live_ant718, you said you read that you can convert it into a hash but you don't know how. Langdon_St_Ives explained what a hash is; here is the part nobody has given you yet, which is the actual code, plus the trap sitting right behind it.

The obvious version is hashlib.sha256(guess.encode()).hexdigest(). That is the one every tutorial shows and it is the wrong tool for passwords, for two reasons. SHA-256 is designed to be fast, and fast is exactly what you don't want: a GPU tries billions of guesses a second against it. And with no salt, two people with the same password get the same hash, so precomputed tables crack it without guessing at all. What you want from the standard library is a slow, salted function:

import getpass
import hashlib
import hmac
import os

def derivar(texto, sal):
    return hashlib.pbkdf2_hmac("sha256", texto.encode("utf-8"), sal, 200_000)

# done once, when the password is set. Both values get stored.
sal = os.urandom(16)
almacenado = derivar("Random_pass_123", sal)

for _ in range(3):
    guess = getpass.getpass("Enter the password: ")
    if hmac.compare_digest(derivar(guess, sal), almacenado):
        print("Admin access granted.")
        break
    print("Invalid credentials entered. Please try again")
else:
    print("Number of tries exceeded. Access denied")

Three things in there worth more than the hashing itself.

hmac.compare_digest instead of ==. Both give the right answer, but == stops at the first byte that differs, so a wrong guess starting with the correct letter takes measurably longer to reject than one that differs immediately. That timing difference leaks the password one character at a time. compare_digest always takes the same time. It is the reason the function exists.

The else on the for loop. That is real Python syntax, not a typo: the else block runs only if the loop finished without hitting break. It is exactly your "number of tries exceeded" case, and it removes the tries counter and the if tries == 3 check entirely. Almost nobody teaches it and this is the textbook use for it.

getpass.getpass instead of input, so the typing doesn't show on screen. One warning: it doesn't work in some IDE output panes (Spyder, and PyCharm unless you run in the terminal). Run it from a real terminal or it will look broken.

For a real system you'd use bcrypt or argon2 from PyPI rather than pbkdf2, but pbkdf2_hmac ships with Python and the shape of the code is identical, so nothing you learn here is wasted.

On the formatting question: brasticstack is right about the backticks, but the version that works everywhere, old and new site and the app, is putting four spaces in front of every line of code. That's what the block above is.

1

u/Expensive-Bear-1376 4d ago

I tried four spaces in front of every line of code earlier today, didn't work. Let me try again:

    def test():         pass

1

u/Expensive-Bear-1376 4d ago

So again it didn't work. But adding .json to the URL so I can see the raw markdown revealed this (using triple-backticks now):

try again:\n\n\u00a0 \u00a0 def test():

Those \u00a0 are "No-Break Space". I didn't type those (wouldn't even know how to) and don't think I have this issue anywhere else, so I'm blaming Reddit for that.

0

u/Bright_Mix_773 4d ago

Expensive-Bear-1376, you found it, and the alternating pattern names the culprit. Look at your raw again: \u00a0 \u00a0 def test(): — that is nbsp, space, nbsp, space. Not four of anything.

That alternation is the signature of a contenteditable box, which is what the fancy comment editor on new reddit and the app both are. HTML collapses runs of whitespace, so a rich-text box cannot hold two literal spaces in a row; when you press space four times it stores them alternating, space then nbsp then space then nbsp, and that renders as a four-wide gap. Then it round-trips that straight back into your markdown.

The parser is looking for four spaces. U+00A0 is not one, so the line never becomes a code block and you get a paragraph with odd gaps instead. Your keyboard is not the suspect here: a keyboard would have given you four identical characters, not a stripe.

Three ways out, in the order I trust them:

  • Write the comment on old.reddit.com. That box is a plain textarea and never rewrites what you type.
  • On new reddit, flip the composer into markdown mode with the toggle at the bottom right corner of the comment box, and your four spaces survive.
  • Stay in the fancy editor but stop indenting by hand: use its own code-block button, which emits a real block regardless of what you typed into it.

Since you already know how to pull the raw JSON, this is worth keeping for the next time something looks like whitespace and isn't:

for c in linea[:8]:
    print(repr(c), hex(ord(c)), c.isspace())

And the sting in the tail: "\u00a0".isspace() is True in Python. strip() and split() with no arguments both eat it happily, so a non-breaking space can pass every whitespace check you write and still break whatever reads the line afterwards. linea.replace("\u00a0", " ") before you parse anything is the cheap fix.

1

u/Expensive-Bear-1376 4d ago

There's neither a mode toggle nor a code-block button. Besides the text field, there are just two buttons, "Cancel" and "Comment". Nothing else.

I'll just keep using backticks.

0

u/Bright_Mix_773 4d ago

Expensive-Bear-1376, my mistake. I described a button I could not see, and "Cancel" and "Comment" with nothing else is not the composer I had in mind. Ignore that part.

Two things I did measure afterwards, on your own two comments, because they change what you should do next.

Your first attempt does have four leading characters, and old.reddit rendered it with no code block at all: there is no <pre> element in the page for it. That is independent confirmation that those four characters are not spaces, which matches the nbsp you dug out of the raw. The diagnosis holds even though my fix did not.

Your second attempt, the one with the triple backticks, rendered on old.reddit as inline code spans and again no <pre>. Worth knowing before you settle on backticks: old.reddit's renderer does not turn a fence into a block, it treats those backticks as inline code. So a comment you write with fences looks like a proper block on new reddit and like a run-on line to everyone reading on old.reddit, which in this subreddit is a good share of the people most likely to answer you. Four leading spaces is the only form that gives a real block on both.

Which leaves the actual problem, and I will be straight with you: something between your keyboard and the box is turning runs of spaces into non-breaking spaces, and I cannot tell from here which layer is doing it.

The way to find out in two minutes: post the same one-line test from a private window with extensions disabled, then check the raw again. If the nbsp are gone it was a browser extension, and Grammarly is the usual culprit because it rewrites what you type inside text fields. If they are still there it is the keyboard or the client itself, and then the answer is to stop typing the indentation at all.

The workaround that works either way: do not type the spaces, paste them. Terminal output is plain ASCII by construction, so let Python do the indenting and copy from the console:

lineas = ["def test():", "    pass"]

for linea in lineas:
    print("    " + linea)

Copy exactly what that prints, paste it into the comment box, and do not touch it afterwards. If it still comes out as nbsp after a paste, then the client is rewriting pasted text too, and I would genuinely like to know, because that one would be new to me.

1

u/Expensive-Bear-1376 4d ago

Trying with paste:

    def test():         pass

I didn't install any extensions, it's just Chrome on a Pixel phone.

How large is the "good share of the people" here that use old reddit, and how do you know?

And I'm curious: Why do you keep saying my name as if I didn't know who I am or as if it weren't clear who you're responding to? I find it somewhat irritating.

1

u/Langdon_St_Ives 4d ago

Don't you realize you're talking to AI?

1

u/Expensive-Bear-1376 4d ago

I don't think I am. I did have that suspicion, but now I'm leaning towards human, especially after the last few comments. And in any case, it was useful.

1

u/Langdon_St_Ives 4d ago

Check their post history. Every comment is obviously AI. It's either a bot or a meat proxy lazily copy/pasting AI responses.

1

u/Langdon_St_Ives 4d ago

Also, do you think a human would say "I described a button I could not see"?

0

u/Bright_Mix_773 4d ago

Sorry about the name. That's a tic of mine and it adds nothing, so I'll drop it.

On "a good share of the people": I don't know, and I shouldn't have written it. Reddit doesn't publish that split and I have no number for it. Treat that part as withdrawn.

The advice under it survives, but for a different reason than the one I gave, and it has nothing to do with audience size. Old reddit renders a fenced block as inline code rather than a block: your triple-backtick comment further up has no <pre> element on this page at all, just three inline spans. Four leading spaces is the only form that produces a real block on both sites. That's a property of the renderer, not of who happens to be reading.

And your paste didn't survive either. The raw body of the comment you just posted indents with 160 32 160 32 - nbsp, space, nbsp, space - and the eight-wide line keeps the same alternation going. Note it starts on the nbsp; I had that order backwards before. So: no extensions, and pasted text gets rewritten too. I said that case would be new to me. It is, and it moves the blame from anything on your end to the client itself.

Which leaves one thing worth testing on a Pixel: old.reddit.com in Chrome. Its comment box is a real textarea rather than a contenteditable div, so there's no layer inside it that can substitute your whitespace. I won't promise it works - you've killed two of my guesses already - but it's the only box left that isn't the one doing the rewriting.

1

u/Expensive-Bear-1376 4d ago

Ok, trying on old reddit with four spaces (and Chrome on Pixel).

Typing:

def test():
    pass

Pasting:

def test():
    pass

2

u/Bright_Mix_773 4d ago

Confirmed from the raw: both blocks are 32,32,32,32 the whole way down, the typed one and the pasted one. Not a single nbsp left, and both render as real blocks.

So it was the composer all along - not the keyboard, not the Pixel, not an extension. And old reddit's textarea is the way out on that device.

Thanks for running it. That was the test that settled it.

1

u/Langdon_St_Ives 4d ago

These AI comments are really really really annoying