Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify Crypto::BCrypt #15276

Open
ysbaddaden opened this issue Dec 13, 2024 · 1 comment
Open

Simplify Crypto::BCrypt #15276

ysbaddaden opened this issue Dec 13, 2024 · 1 comment

Comments

@ysbaddaden
Copy link
Contributor

ysbaddaden commented Dec 13, 2024

The discussion on #15270 led to an interesting argument: we don't need the Crypto::BCrypt nor the Crypto::BCrypt::Password classes. We only need a couple methods:

  1. Crypto::BCrypt.hash(password : String, *, cost = DEFAULT_COST) : String to generate the bcrypt hash for password, using the provided cost and a randomly generated salt (RNG must be of cryptography quality).

  2. Crypto::BCrypt.verify(hash : String, password : String) : Bool to encode password using the hash salt then safely compare it (in constant time) against the provided hash digest.

The only useful case for the classes is to compare the same bcrypt hash against multiple passwords... but what's the use-case outside of rainbow tables?

Bonus: we allocate multiple intermediate objects (Array(String), Bytes, Crypto::BCrypt or Crypt::BCrypt::Password) and we could avoid all of them but the final, fixed size, String for the .hash method 🤔

@straight-shoota
Copy link
Member

I agree that Bcrypt::Password seems unnecessary for its primary function of verifying a password.

However, there are other use cases: It exposes an API to make properties of the hash available. version and cost are relevant diagnostic information. You might want to know whether a hash was created with an obsolete version or obsolete cost policy, for example.
salt and digest are maybe less generally useful.

So I believe we need more than just a hash and verify methods for a comprehensive API.
But two relatively simple methods for quering the version and cost of a hash could be enought for this.

Bonus: we allocate multiple intermediate objects (Array(String), Bytes, Crypto::BCrypt or Crypt::BCrypt::Password) and we could avoid all of them but the final, fixed size, String for the .hash method 🤔

I believe it should be possible to do most of the optimizations within the Bcrypt::Password class. For example, the getters could allocate lazily. And the bcrypt algorithm could be fed allocation-free subslices.
So I feel the optimization story is not directly related to the API (although having a smaller/simpler API would probably make optimizing easier).

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

No branches or pull requests

2 participants