Would someone explain to me why hash() isn't working?

code
import random
from replit import db

#for key in db.keys():
# del db[key]
if len(db) == 0:

  pw = input("create pw ")
  salt = random.randint(1000,9999)
  print(f"salt : {salt}")
  saltedpw = f"{pw}{salt}"
  print(f"salted pw : {saltedpw}")
  hashedpw = hash(saltedpw)
  print(f"hashedpw : {hashedpw}")
  db["password"] = {"salt" : salt, "storedpw" : hashedpw}

else:
  checkpw = input("password ?")
  checksalt = db["password"]["salt"]
  print(f"checksalt : {checksalt}")
  saltedcheckpw = f"{checkpw}{checksalt}"
  print(f"saltedcheckpw : {saltedcheckpw}")
  checkhash = hash(saltedcheckpw)
  print(f"checkhash : {checkhash}")
  if checkhash == db["password"]["storedpw"]:
    print("Success")
  else:
    print("Failure")

Whenever I try to compare the hash of the salted password for verification, it gives me a different answer, even when it should be the same. However, I can take the exact same code verbatim, and paste it into my Day 71 of 100 Days of Code repl from 4 months ago, and it works?
I’m not asking how to fix it, chatgpt told me to use hashlib.sha256(saltedpw.encode()).hexdigest()which works, I’m just wondering if someone wouldn’t mind explaining to me why? Thank you.

https://replit.com/@vvithershins/HummingZestyCompilerbug

hash() does not return a cryptographic hash and it should not be used for password hashing. From the python documentation:

Return the hash value of the object (if it has one). Hash values are integers. They are used to quickly compare dictionary keys during a dictionary lookup. Numeric values that compare equal have the same hash value (even if they are of different types, as is the case for 1 and 1.0).

And,

Note: By default, the hash() values of str and bytes objects are “salted” with an unpredictable random value. Although they remain constant within an individual Python process, they are not predictable between repeated invocations of Python.

3 Likes

I asked replit ai : What’s the difference between hash() in this repl set up where we use the interpreter, compared to other repls where we use run instead?
(in regards to it working in the 100daysofcode repl)

and it said:
The hash() function in the Replit set up where we use the interpreter is implemented in the CPython interpreter. The CPython interpreter is the most popular Python interpreter, and it is also the interpreter that is used by default in most Python environments.

The hash() function in the Replit set up where we use run instead is implemented in a custom interpreter that is designed to be more efficient and secure. The run mode interpreter does not have the hash() function implemented because it is not necessary for the vast majority of Python programs.

The main difference between the two implementations of the hash() function is that the run mode implementation is more efficient. The run mode interpreter uses a different algorithm to calculate the hash value of an object, which is faster than the algorithm used by the CPython interpreter.

Another difference between the two implementations is that the run mode implementation is more secure. The run mode interpreter uses a different hashing algorithm that is more resistant to collision attacks. This means that it is less likely for two different objects to have the same hash value, which can lead to security vulnerabilities.

Overall, the hash() function in the Replit set up where we use the interpreter is more powerful and versatile, while the hash() function in the Replit set up where we use run instead is more efficient and secure.

-Is this mostly accurate?

I’m going to say no, what does it even mean by “run mode interpreter”?

2 Likes

I just ran out of replit ai for now, Im assuming it means whatever the difference between
image
and
image
is.

Chat gpt says :
The difference in behavior between the “interpreter” and “run” modes in the Replit environment might be due to how the Python interpreter is initialized and executed in each mode.

In the “interpreter” mode, the Python interpreter is likely kept alive and running continuously, meaning that the hash randomization seed remains constant throughout the session. This would explain why you’re observing consistent hash values for strings across multiple runs within the same session.

On the other hand,

in the “run” mode, the Python interpreter may be initialized and terminated for each run of the program.

This could result in a new randomization seed being generated for each execution, leading to different hash values for strings in each run.

To confirm this hypothesis, you can try running your code multiple times within the same session in both “interpreter” and “run” modes to see if the behavior remains consistent. If the hash values stay the same in “interpreter” mode but vary in “run” mode, then it’s likely due to the difference in how the Python interpreter is managed between the two modes.

Something like this is what my initial suspicion was but I don’t know if it’s true or not, would you agree?

That still makes no sense, there really shouldn’t be a difference in how those run.

Also I can guarantee you, GPT has no clue what it’s talking about in this regard.

I suppose as a test, you could kill 1 the interpreter Repl and see if it changes. If it does not, then it’s not because one session is consistent between runs, there’s a different cause.

2 Likes

Running kill 1 did not affect it, it was still consistent between runs.

I found this in https://docs.replit.com/tutorials/replit/nix-packaging#some-notes-on-hashes and thought it might be related


So I checked and found that the 100 days of code repls use nixpkgs version 21.11pre-git
while the new ones use 23.05pre-git
After a long adruous process trying to install the 21.11 version on one of the new repls, I think I finally managed to?

And it still doesn't work. I honestly have no idea what to do. I'm just trying whatever.

It is not. Your inconsistency is most like to Python implementation of the hash() function, which is totally different from the hash calc and validations that Nix do.

As @Firepup650 it should work regardless in both scenarios.

What you can do is try logging or printing out the hash values and the Python version/environment details both when you set the password and when you check it.

4 Likes

Ah looks like the old repl (100 days of code) is still using Prybar which means that it keeps 1 python process running the whole time while you are in your repl so the hashes always match, because no random salt is generated inside python, but in the new repl running the code actually creates a new python process which generates new random salt internally so your hashes dont equal.

5 Likes

Actually, I was trying to say that it shouldn’t work in either scenario :stuck_out_tongue_winking_eye:

1 Like

I tried copying the .replit, replit.nix, pyproject.toml, poetry.lock, .pythonlibs/lib/python3.10/site-packages/replit/database/database.py, and .pythonlibs/lib/python3.10/site-packages/replit/__init__.py files from one of the 100 days of code repls, into the “new repl”

But then when I run the code I get this TypeError: 'ABCMeta' object is not subscriptable

TypeError
  File "/home/runner/MealyFrequentDeveloper/.pythonlibs/lib/python3.10/site-packages/replit/__init__.py", line 7, in <module>
    from . import database, web
  File "/home/runner/MealyFrequentDeveloper/.pythonlibs/lib/python3.10/site-packages/replit/database/__init__.py", line 4, in <module>
    from . import default_db
  File "/home/runner/MealyFrequentDeveloper/.pythonlibs/lib/python3.10/site-packages/replit/database/default_db.py", line 6, in <module>
    from .database import Database
  File "/home/runner/MealyFrequentDeveloper/.pythonlibs/lib/python3.10/site-packages/replit/database/database.py", line 449, in <module>
    class Database(abc.MutableMapping):
  File "/home/runner/MealyFrequentDeveloper/.pythonlibs/lib/python3.10/site-packages/replit/database/database.py", line 643, in Database
    def keys(self) -> abc.KeysView[str]:
TypeError: 'ABCMeta' object is not subscriptable

When I try the AI’s suggestion :
Change line 214 in database.py from:

def keys(self) -> abc.KeysView[str]:

to:

def keys(self) -> abc.KeysView:
JSONDecodeError
password ?abc123
Traceback (most recent call last):
  File "main.py", line 19, in <module>
    checksalt = db["password"]["salt"]
  File "/home/runner/MealyFrequentDeveloper/.pythonlibs/lib/python3.10/site-packages/replit/database/database.py", line 530, in __getitem__
    val = json.loads(raw_val)
  File "/nix/store/p21fdyxqb3yqflpim7g8s1mymgpnqiv7-python3-3.8.12/lib/python3.8/json/__init__.py", line 357, in loads
    return _default_decoder.decode(s)
  File "/nix/store/p21fdyxqb3yqflpim7g8s1mymgpnqiv7-python3-3.8.12/lib/python3.8/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/nix/store/p21fdyxqb3yqflpim7g8s1mymgpnqiv7-python3-3.8.12/lib/python3.8/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

It tells me to try using ayncio in main.py
and to Modify line 531 in the database.py file from:
val = json.loads(raw_val)
to:

if raw_val:
    val = json.loads(raw_val)
else:
    val = None  # Handle the case where raw_val is empty or not valid JSON

And here I’m stuck now. Feels like I’m going in circles.

I marked @JustCoding123 's post as the solution because I think it was the closest to my initial question of why hash() works consistently in the 100 d.o.c. repls but not the other one and helped me understand the most, but everyone was helpful and I feel like I’ve learned from all of it. Thank you everyone.

You shouldn’t be having issues from the DB, AI probably has like no clue what it’s talking about here.

I did think that it was supposed to work regardless since it was the same environment but as @JustCoding123 it ins’t.

Sorry, but what were you trying to say?

I think they meant:

but as @JustCoding123 said, it shouldn’t.

2 Likes

^ Yes, this, thanks for the heads up

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.