Почему хэши scrypt узла одинаковы при одинаковых входных данных? - PullRequest
0 голосов
/ 15 декабря 2018

Я пытался найти функцию сравнения или проверки для встроенного криптомодуля узла, специально для scrypt, так как большинство используемых мной хеш-паролей имеют такую ​​функцию.Затем я обнаружил, почему это было невыполнимой задачей: все хэши, созданные с помощью этих алгоритмов с использованием одинаковых параметров, генерируют одну и ту же строку (технически буфер).Это относится ко многим хеш-функциям crypto, включая реализацию pbkdf2.

Почему это безопасно?Разве не весь (современный) смысл функции хеширования пароля / сообщения заключается в том, что вы не можете сгенерировать тот же пароль / сообщение снова, используя тот же ввод?Вот как работают различные модули bcrypt, а также оригинальная версия scrypt, из которой получена встроенная версия, о которой я спрашиваю.

Например:

let scryptHash1;
let scryptHash2;
let scryptHash3;

let pbkdfHash1;
let pbkdfHash2;
let pbkdfHash3;

const key1 = 'my secret key';
const key2 = 'my other secret key';

const salt = 'my salt';

crypto.scrypt(key1, salt, 16, hash => scryptHash1 = hash);
crypto.scrypt(key1, salt, 16, hash => scryptHash2 = hash);
crypto.scrypt(key2, salt, 16, hash => scryptHash3 = hash);

scryptHash1.toString() === scryptHash2.toString(); // true
scryptHash1.toString() === scryptHash3.toString(); // false

crypto.pbkdf2(key1, salt, 16, 16, 'sha256', hash => pbkdfHash1 = hash);
crypto.pbkdf2(key1, salt, 16, 16, 'sha256', hash => pbkdfHash2 = hash);
crypto.pbkdf2(key2, salt, 16, 16, 'sha256', hash => pbkdfHash3 = hash);

pbkdfHash1.toString() === pbkdfHash2.toString(); // true
pbkdfHash1.toString() === pbkdfHash3.toString(); // false

Первоначально я задавал этот вопрос на Cryptography, так как меня больше заботит безопасность, чем что-либо еще, поскольку я хочу перейти от bcrypt к scrypt.Однако, как отмечали несколько человек, и, как я и опасался, вопрос скорее в разработке API.При этом любой принятый ответ должен включать, почему этот метод является безопасным или достаточно безопасным для переключения (предоставление этого «достаточно безопасного» никогда не является достаточно безопасным).Я выбрал безопасность в качестве основного специалиста, но теперь я веб-разработчик, и безопасность все время меняется, хотя основные концепции остаются в основном неизменными.

1 Ответ

0 голосов
/ 15 декабря 2018

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

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

Для функции хеширования пароля H вы хотите, чтобы для любого фиксированного пароля m и любых двух солей s ≠ s 'itне только считает, что H (m, s) ≠ H (m, s '), но также учитывая значения хеш-функции и соли, вы не сможете обнаружить, что они являются значениями хеш-функции одного и того же m.

То, что вы, кажется, смущены, это разные варианты дизайна API.В частности, кто может выбрать соль.Каждый раз, когда хэшируется новый пароль m (например, для ввода в базу данных), должна быть выбрана свежая равномерно случайная соль s, а затем вычисляется значение хеша h: = H (m, s) и сохраняются оба значения h и s.в базе данных.Всякий раз, когда кто-то, претендующий на то, чтобы быть тем же пользователем, отправляет пароль m 'для аутентификации, происходит то, что (h, s) извлекается и проверяется, является ли h = H (m', s).

ТеперьВопрос в том, кто выбирает соль.Похоже, что знакомые вам API не доверяют пользователю.Поэтому, когда вы вызываете хэш-пароль m, библиотека выберет соль s, вычислит h и выведет h '= (h, s) в качестве «значения хеша».Чтобы проверить, верен ли пароль m ', вы затем отправляете h', m ', и библиотека извлекает соль, пересчитывает хеш и сравнивает.

Библиотека, которую вы сейчас просматриваете, ожидает, что пользователь выберетсоль.То есть каждый раз, когда вы создаете новую запись в базе данных паролей , вам приходится выбирать новую соль, вычислять h = H (m, s) и сохранять обе (h, s).Поскольку библиотека в этом случае не пытается «что-то скрыть» от вас, вам нужно позаботиться о сравнении.

...