peterhellberg / hashids.rb

A small Ruby gem to generate YouTube-like hashes from one or many numbers. Use hashids when you do not want to expose your database ids to the user.
http://www.hashids.org/ruby/
MIT License
976 stars 46 forks source link

Validate salt length? #31

Open hoffi opened 1 year ago

hoffi commented 1 year ago

The salt appears to have a maximum length after which it has no longer impacts the generated hash.

Here some examples:

Hashids.new('a' * 41).encode(1)
=> "pn" 
Hashids.new('a' * 42).encode(1)
=> "nd" 
Hashids.new('a' * 43).encode(1)
=> "yQ" 
Hashids.new('a' * 44).encode(1)
=> "yQ" 
Hashids.new('a' * 45).encode(1)
=> "yQ" 

If i change the alphabet it also affects this maximum length:

Hashids.new('a' * 22, 0, 'abcdefghijkmnopqrstuvwxyz023456789').encode(1)
=> "b0" 
Hashids.new('a' * 23, 0, 'abcdefghijkmnopqrstuvwxyz023456789').encode(1)
=> "bd" 
Hashids.new('a' * 24, 0, 'abcdefghijkmnopqrstuvwxyz023456789').encode(1)
=> "bd" 
Hashids.new('a' * 25, 0, 'abcdefghijkmnopqrstuvwxyz023456789').encode(1)
=> "bd" 

Looks like something around (alphabet.length * 0.7).floor is the maximum length?

Should this be validated and raise a SaltError when the salt is too long?

maslenkov commented 1 month ago

@hoffi Yes, there is a maximum length after which it has no effect on the generated hash. But still salt is used and if you change the letter in your snippet you will see an effect.

https://github.com/peterhellberg/hashids.rb/blob/master/lib/hashids.rb#L157 Hashids uses idx = (idx + 1) % salt_length to provide looping/cycling through indices in the alphabet shuffling process. At the same time it depends on the initial alphabet length - separators length - guards - lottery. So if salt length is quite larger then alphabet then it would use only first part of salt for alphabet shuffling. And it would be enough to shuffle the whole alphabet. Anyway, shuffling will happen. And yes, the last part of the salt would not be used. I agree that this is not obvious, but this is not an exception. Using a random string would generate uniq values.