Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

If you can't keep the line between "ordinary developers shouldn't be working with AES" and "ordinary developers can write login systems" clear, you're doing people a disservice, because the two assertions are not alike in how fundamentally true they are.


By the way, I agree with you. My original point was that the "hivemind" somehow has shifted away from the reasonable conclusion.


There's nothing personal about any of this, but I'm watching the both the insane poles of this argument ("I'll be just fine inventing my own block cipher modes" guy, "Only a certified security engineer can write a permissions check" guy") go at each other, and wondering why we need to pay any attention to either of them.

I haven't so much seen the latter kind of guy, the one saying you need a certified professional to safely output-filter HTML or whatever, but I see "lol block cipher modes whatever" people on HN all the time, on almost every thread about cryptography, dunking on anyone who says "don't roll your own cryptography".


FWIW I see a lot more of the "lol I rolled my own block cipher" crowd in articles here, but a lot more of the "only experts should verify a signature" crowd in the professional world (mostly startup-biased recently).

I sort of assume that the latter is a random sampling of software engineers but the former is sampled specifically for idiots who YOLO their crypto.


Only experts should verify signatures! That's actually hard.

If you're using minisign or Sigstore or whatever to do something like verify upstream dependencies, sure. But if you're building a system that is about some novel problem domain involving signatures: you should get an expert to verify your system. The trail of dead bodies here is long and bloody.


Yeah, coming up with your own signature scheme to verify authenticity with certain properties is very difficult but also very different in kind from running a pre-designed scheme using a library baked by someone else.

I think you have a pre-defined notion when I say the word "signature" about what I meant (perhaps something about software signing or SSL certificates). I literally meant "checking that HMAC-SHA-2 of some bytes is what you expect" (using a library for the hash). Incidentally, that's how you authenticate a JWT.


I recently came across a signature check that was (correctly) checking the signature against a public key... The issue was the public key itself was unauthenticated, and provided by the (signed) ciphertext itself... Meaning the crypto was fine, but it wasn't checking anything meaningful, as any rogue message would just include its own public key in the message!

It's not only about the raw operation of checking bytes are equal (hopefully in a constant time manner, if applicable), but also about ensuring the desired security properties are actually present in the application!


A JWT? Me me! I've seen this done wrong!

  - memcmp(actual_sig, expected_sig) == 0
  - strcmp(actual_sig_base64, expected_sig_base64) == 0
  - strcasecmp(actual_sig_base64, expected_sig_base64) == 0


> If you're using minisign or Sigstore or whatever to do something like verify upstream dependencies, sure.

No, not "sure". minisign and Sigstore are completely different things, and one needs to understand how those work and what the corresponding signatures mean: A minisign signature says "the owner of that key signed this". Whoever the owner might be at the moment of signature. Whenever that might have happened.

A sigstore signature says "Google/Github/... says that this OpenID account generated that one key that the sigstore CA attests and that signed that blob at that time". Time/ordering verification is better than in minisign, because it is there, even if through a trusted party. But identity verification relies on a trusted third and fourth party, some of whom do have a history of botching their OpenID auth.

Those are not equivalent, and knowledge is needed to not mix them up. You don't need to be an expert, but you should try to understand as much as you can, identify what you don't understand and where you must trust an expert, implementation, company, recommendation or standard to be correct and trustworthy. And then decide if that is ok with you.


You're really mining a lot out of a throwaway line there.


eh, as someone who rolls my own login systems and depends on checking salted password hashes against those in a database: Assuming I block brutes after 3 or 4 attempts, is there anything I need to worry about here besides someone getting access to the database or the salt? I think your point was that people building logins off one way hashes aren't really doing anything outrageously wrong?


You'll want to look at your hashing algorithm and number of iterations to make sure they are up to snuff and you'll want to make sure that your salts are unique and properly random. (I recently learned that the PS3 private keys were reversible because Sony's random number function returned a fixed result.)

Proper password hashing is protecting against a different threat than blocking brute force login attempts (which isn't really an encryption issue.) Password hashing is more about protecting your user's passwords if your database is breached so that you limit the attackers ability to re-user those credentials to access other services the user may have re-used them with.


I mean to start with if you are literally using "salted hashes" you are boned. There's a whole literature of "password hashes" ("password KDFs"), and that literature exists for a reason; the papers are a record of the weaknesses found in "salted hashes", a construction dating back to the late 1970s.

But once you adopt something like BCrypt or scrypt or PBKDF2 or Argon2 (literally throw a dart at a dartboard), you're into the space of things where you should, as a competent engineer, be expected to figure out a sound system on your own. The only domain-specific knowledge you really need given to you by a cryptographer is "don't just use salted hashes".


Mostly, here in 2025 the question is: "Why are you using shared secrets?" - which is why this discussion comes up. These are never about a PAKE or the PIN for a Yubikey or something, it's always shared secrets when people say "passwords".

This is a terrible stopgap solution, in 1975 it's reasonable to say we have other priorities right now, we'll get to that later. But it's very silly that in 2025 you're telling people to try PBKDF2 when really they shouldn't even be in this mess in the first place.

Remember when Unix login still hadn't solved this? 1995. That was last century. And yet, here we are, still people are writing "Password" prompts and thinking they're doing a good job.


Incidentally, a presentation at the NIST crypto reading group recently pointed out some of the weaknesses of current password KDFs: Argon2i has a viable attack, bcrypt truncates input, PBKDF2 needs an utterly insane number of rounds, and scrypt and argon2d/argon2id have data-dependent computation time and seem to be vulnerable to side-channel attacks. It turns out this is a really hard problem.


I wasn't present for the NIST crypto reading group, but I documented a lot of these in 2022, if you'd like a deeper dive into that problem space: https://soatok.blog/2022/12/29/what-we-do-in-the-etc-shadow-...


None of which are material compared to someone using a salted hash.


In all seriousness, can you please stop recommending bcrypt for new systems? The input length is hard limited to a frighteningly short string and it is not a KDF since it has a fixed output length. Its internal state is small enough that it can be efficiently cracked with FPGAs (although the structure is unsuitable for GPU-based crackers).

The distinction between a KDF and a hash function is that a KDF has an output length that is configurable so you can directly use its output to generate a cryptographic key with 100% of the entropy of the input. A KDF theoretically needs to have arbitrary input length and arbitrary output length. Bcrypt has neither.

Argon2d is great, scrypt is great, PBKDF2 with 1000000+ rounds works fine if you want FIPS, but bcrypt is somehow still on many people's list as though it doesn't have these flaws. It's not at the point where it needs to be imminently replaced in a legacy system, but if you're building something new, you should use something better.


I'm still in the dark about the problem with storing a salted hash, assuming a decent hash function and a decently long random salt.

Simply replying "everyone knows what the problem is and has know since the 70s" is not as helpful as "here is the problem in three sentences".

You can assume a base level of knowledge in your answer, as I have worked in encryption for a little bit, having written the 3DES implementation for some firmware, and done EMV development.


The very short version is that decent hash functions are very, very fast, take almost no storage to compute and can thus easily be run in parallel. If you store `(,salt ,(HMAC-SHA2-256 salt password)) in your database and it leaks, an attacker can check hundreds of millions of possible passwords every second. The password ‘open sesame’ will get found pretty early, but so will ‘0p3n#s3s4m3$’. Pretty much anything which is not of the form ‘62Jm1QyJKGIZUpb5zARRLM’ will get found pretty quickly.

You want something that is slow and takes a lot of resources to run. PBKDF2 was an early attempt which uses lots and lots of CPU, but it doesn’t use a lot of space. scrypt, bcrypt and Argon2 use lots of CPU and also lots of space in an attempt to make it more expensive to run (which is the point: you want the expected cost of finding a password to be more than the expected value of knowing that password).

That’s one level of issue.

The next level of issue is that when you run a simple system like that the user shares his password with you for you to check that it’s valid. This sounds find: you trust yourself, right? But you really shouldn’t: you make mistakes, after all. An you may have employees who make mistakes or who are malicious. They might log the password the user sent. They might steal the user’s password. Better systems use a challenge-response protocol in which you issue a one-time challenge to the user, the user performs some operation on the challenge and then responds with a proof that he knows his secret.

But those have their own issues! And then there are issues with online systems and timing attacks and more. It’s a very difficult problem, and it all matters what you are protecting and what your threat model is.


> But those have their own issues! It’s a very difficult problem, and it all matters what you are protecting and what your threat model is.

it's all a trade-off - those challenge/response systems are better, but they also have more moving parts. There's more bits in the system to go wrong.

When there's only two pieces of the system (compare salted hash of user-provided password against stored salted hash) there's very little room for errors to creep in. Your auditing will all be focused on ensuring that the user-provided password is not leaked/stored/etc after a HTTP sign-in request is rxed.

When using challenge/response, there is some pre-shared information that must synchronised between the systems (algorithm in use, key length, etc depending on the specific challenge/response system chosen). That's a great deal more points of attacks for malicious actors.

And then, of course, you need to add versioning to the system (algorithms may be upgraded over time, key lengths may be expanded, etc) that all present even more points of attack.

Compare to the simple "compare salted hash of password to stored salted hash": even with upgrading the algorithms and the key lengths there still remain only one point of attack - downloading the salted hashes!

It doesn't matter how much more secure a competing system is if it introduces, in practice anyway, more points of failure.

My takeaway after doing some cryptography for some parts of my career is that by choosing a hash function to be expensive in computational power and expensive is space and keeping the "user enters a password and we verify it" is still going to have fewer points of attack than "Synchronising pre-shared information between user and authenticator as the security is upgraded over the years".

Basically, the trade-off is between "we chose a quick hash function, but can at least upgrade everything without the client software noticing" and the digital equivalent of "It's an older code, sir, but it checks out" problems.


You keep returning to salted hashes. Please read the first two paragraphs of what I wrote for why that is a mistake. If you are going to use a shared secret system, do not use salted hashes. There is almost never a good reason to use salted hashes in 2025.

> you need to add versioning to the system

You need this with salted hashes, too! And of course with any password-based system.


> Please read the first two paragraphs of what I wrote for why that is a mistake.

Okay, I read it, and then re-read it. I still don't get why (for example) `bcrypt` (a salted hash function) is a bad idea.

I fully accept that I am missing something here, but I really would like to know why using `bcrypt` is a problem.

>> you need to add versioning to the system

> You need this with salted hashes, too! And of course with any password-based system.

Not in the client software, you don't. The pre-shared information with password-based system is generally stored in the users head.

The pre-shared information in the challenge/response system means both the submitting software (interacting with the user and rxing the challenge) as well as the receiving software (txing the challenge and rxing the response) need to be synchronised.

Now, once again, I fully accept that I might be missing something here, but AFAIK, that synchronisation contains extra points of attacks; points of attacks that don't exist in the password/salted-hash system.

And since absolutely no system ever discards existing mechanisms completely when upgrading, that deprecated but still supported for a few more months is even more additional points of attack.

Once again, I am trying to understand, not be contentious, and I want to fuolly understand:

a) The problem with salted hashes like `bcrypt`

b) What changes need to be made to client software when upgrading algorithms and key lengths in a password-based system.


bcrypt is not a "salted hash function". It's a a password hash construction (at the time of its invention, it was called an "adaptive hash"; today, we'd call it a "password KDF"). If you're using bcrypt, you're fine.

What you can't do is use SHA2 with a random salt and call it a day.


My understanding of bcrypt math is that the input to the algorithm is a random salt and a message, with the output being a hash.

I believe the actual implementation gives two output fields as a single value, with that value containing the salt and the hash.

This might be why we appear to be talking past each other - I consider bcrypt to be a salted hash because it takes a salt in the inputs and produces a hash in the output.

The fact that the output also contains the salt is, in my mind, an implementation detail.


Yes. We aren't talking past each other anymore. If you aren't composing a "salted hash" out of a cryptographic hash function and a salt, but are instead using bcrypt, scrypt, PBKDF2, or Argon2, you have nothing to worry about. Just to complete your understanding: the salt --- randomizing the hash --- has very little to do with what makes bcrypt a good password hash.

You'll avoid this confusion in the future if you don't refer to bcrypt as a "salted hash". Salted hashes are the technology bcrypt was invented to replace.


OP here: I am using bcrypt to hash passwords, but I struggle to understand how not salting i.e. not randomizing it against a stored secret would still be safe for storing short strings. Be that as it may, I'm glad to hear I'm not doing anything horribly wrong when building login systems.


By salted hashes, I'm pretty sure OP meant using something like bcrypt or PBKDF2


Thanks, yes, using bcrypt. Usually just with something like PHP's password_hash() and the default algorithm. I sort of expected to trigger people with my post, and it's enlightening, but I feel pretty safe with what I'm doing. I mean, I like to know exactly how everything in my engine works. But there's a point at which I can't get paid to reinvent the wheel anymore, nor do I want to try.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: