BCrypt говорит, что длинные похожие пароли эквивалентны — проблема во мне, в драгоценном камне или в области криптографии?

Я экспериментировал с BCrypt и обнаружил следующее. Если это имеет значение, я использую ruby ​​1.9.2dev (2010-04-30 trunk 27557) [i686-linux]

require 'bcrypt' # bcrypt-ruby gem, version 2.1.2

@long_string_1 = 'f287ed6548e91475d06688b481ae8612fa060b2d402fdde8f79b7d0181d6a27d8feede46b833ecd9633b10824259ebac13b077efb7c24563fce0000670834215'
@long_string_2 = 'f6ebeea9b99bcae4340670360674482773a12fd5ef5e94c7db0a42800813d2587063b70660294736fded10217d80ce7d3b27c568a1237e2ca1fecbf40be5eab8'

def salted(string)
  @long_string_1 + string + @long_string_2
end

encrypted_password = BCrypt::Password.create(salted('password'), :cost => 10)
puts encrypted_password #=> $2a$10$kNMF/ku6VEAfLFEZKJ.ZC.zcMYUzvOQ6Dzi6ZX1UIVPUh5zr53yEu

password = BCrypt::Password.new(encrypted_password)

puts password.is_password?(salted('password')) #=> true
puts password.is_password?(salted('passward')) #=> true
puts password.is_password?(salted('75747373')) #=> true
puts password.is_password?(salted('passwor')) #=> false

Сначала я думал, что как только пароли достигнут определенной длины, различия просто потеряются при всем хэшировании, и только если они будут очень непохожими (т.е. разной длины), они будут признаны разными. Из того, что я знаю о хеш-функциях, мне это показалось не очень правдоподобным, но лучшего объяснения я не нашел.

Затем я попытался сократить каждую из длинных строк, чтобы увидеть, где BCrypt сможет различать их, и обнаружил, что если я укорочу каждую из длинных строк до 100 символов или около того, последняя попытка («пароль») начнется. также возвращает true. Так что теперь я не знаю, что думать.

Какое объяснение этому?


person PreciousBodilyFluids    schedule 09.06.2010    source источник


Ответы (2)


Хорошая новость заключается в том, что математические основы шифрования не разрушены. :)

Плохая новость заключается в том, что существует 8-битное ограничение на длину ключа в bcrypt.c, которое молча дает сбой:

uint8_t key_len, salt_len, logr, minor;

Тогда позже:

key_len = strlen(key) + (minor >= 'a' ? 1 : 0);

То, что вы передаете для шифрования, составляет 263 символа, но в итоге он думает, что это только 8. Таким образом, вы получаете сравнения только с самой первой частью строк.

Тем не менее, у меня это отлично работает, когда я урезаю длину long_strings, поэтому, если вы действительно столкнетесь с проблемой в диапазоне менее 255, это может быть связано с чем-то еще.

person HostileFork says dont trust SE    schedule 09.06.2010
comment
Я предполагаю, что исправление, вероятно, будет состоять в том, чтобы заставить bcrypt() возвращать NULL, когда есть слишком длинный ключ. Кроме того, поскольку в структуре пароля уже есть соль, а bcrypt якобы предназначен для решения проблемы безопасности, которая вас беспокоит, я бы не стал здесь заниматься солью. - person HostileFork says dont trust SE; 09.06.2010
comment
Кажется, нет веской причины, по которой key_len вообще такой короткий тип. - person caf; 09.06.2010
comment
@caf - я вижу много строк кода в Интернете. И, к сожалению, большой процент этих строк, похоже, не мотивирован вескими причинами. :) - person HostileFork says dont trust SE; 09.06.2010

P-массив Blowfish состоит из 18 4-байтовых целых чисел. BCrypt XOR этого массива по паролю + null, затем повторяет процедуру, пока не дойдет до конца. Скажем, мой пароль был 12345, это будет XOR P-массива на 12345 (ноль) 12345 (ноль) 12345 (ноль) и т. д.

Полное описание EksBlowfish находится здесь. Короткая версия: BCrypt использует только первые 72 байта.

person Zer    schedule 23.01.2011