Ruby: создать контрольную сумму MD5 с солью?

Я пытаюсь создать контрольную сумму MD5 в ruby с помощью соли, но не могу найти способ сделать это с помощью стандартного пакета digest/md5.

Я знаю, что могу сделать это:

require 'digest/md5'
checksum = '$1$' + (Digest::MD5.new << plaintext).to_s

Однако, похоже, нет никакого способа указать соль для этой генерации контрольной суммы MD5 с помощью digest, и я не нашел никакого другого пакета, который я мог бы использовать для этого в ruby.

Это вообще возможно в ruby?

Можете ли вы добавить пример ввода и ожидаемый результат?

spickermann 25.12.2020 21:22

открытый текст => hippo, соль => q2w3e4, ожидаемый результат: $1$q2w3e4$WzKE5mnfb45yU6XNRLNJQ0

HippoMan 25.12.2020 21:26
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
0
2
1 057
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете добавить вычислить дайджест нескольких чанков вот так:

require 'digest/md5'

md5 = Digest::MD5.new
md5 << '$1$'
md5 << plaintext

checksum = md5.to_s

Или путем объединения строки соли и текста в одном вызове метода:

salt = '$1$'
checksum = Digest::MD5.hexdigest("#{salt}#{plaintext}")

Большое спасибо. Я пробовал это, но это не дало того же результата, что и хэширование для /etc/passwd. Я думаю, что соль не $1$ в этом случае. Однако я наткнулся на решение, и теперь я публикую его как свой ответ.

HippoMan 25.12.2020 21:20
Ответ принят как подходящий

Я нашел следующее, и он делает то, что я хочу...

https://github.com/mogest/unix-crypt

Это работает следующим образом:

require 'unix_crypt'
checksum = UnixCrypt::MD5.build(plaintext, salt)

Это генерирует ту же контрольную сумму, что и в /etc/shadow, для чего я и хочу ее использовать,

UnixCrypt не просто добавляет соль к паролю. Внутри он делает более сложные вещи и даже несколько раз хеширует пароль.
spickermann 26.12.2020 09:10

Да, но он прост в использовании и работает так, как мне нужно для моей конкретной цели.

HippoMan 26.12.2020 19:40

Создание/проверка записей MD5 в стиле *nix с солью

Если вы пытаетесь управлять системными паролями *nix, вам лучше просто использовать системные утилиты, а не создавать свои собственные. Однако, если вы хотите генерировать или проверять соленые пароли, используя только возможности ядра Ruby или стандартной библиотеки, вы, безусловно, можете это сделать.

Вычисленный пароль MD5 с солью обычно хранится в базе данных с плоскими файлами (например, /etc/shadow), где $ — разделитель полей:

$1$salt$hashed_pw

Обратите внимание, что первые два поля хранятся в открытом виде, потому что они необходимы для перестроения и хеширования правильной строки, когда представлен только пароль для проверки. В результате вам нужно рассматривать соль как переменную, отдельную от открытого текста пароля, хотя соль включается в пароль при хешировании.

Если у вас нет ограничения на количество символов, наложенного вашими утилитами, один из способов создать сильную соль — использовать SecureRandom#uuid для генерации значения UUIDv4. Например:

require 'securerandom'

salt = SecureRandom.uuid
#=> "c05280ef-151c-4ebc-83c6-f5f0906f89c2"

Затем вы можете вызвать свой хэш MD5 на salt + pw или pw + salt в зависимости от реализации пароля вашего приложения. Например:

require 'digest/md5'

MD5_STR_FMT = '$1$%s$%s'.freeze

salt = 'c05280ef-151c-4ebc-83c6-f5f0906f89c2'
pw   = 'plaintext password gathered securely'

pw_digest = Digest::MD5.new << salt + pw
pw_entry  = MD5_STR_FMT % [salt, pw_digest]
#=> "$1$c05280ef-151c-4ebc-83c6-f5f0906f89c2$87dcc23c0008e45526e474d0364e4aa5"

Затем вы сохраняете pw_entry в файле базы данных паролей, а затем анализируете соль, чтобы добавить ее перед предлагаемым паролем при повторном вычислении хэша во время аутентификации. Например:

require 'digest/md5'

# this is how we'll validate a password from user
# input against an entry from the password database
def valid_pw? pw, salt, hashed_pw
  pw_digest = Digest::MD5.new << salt + pw
  pw_digest.to_s.eql? hashed_pw.to_s
end

# extract salt and password from a database entry
def parse_pw_entry str
  str.split(?$).slice -2, 2
end

# get this from your password database in whatever
# way you like
pw_entry = '$1$c05280ef-151c-4ebc-83c6-f5f0906f89c2$87dcc23c0008e45526e474d0364e4aa5'

# for demonstration purposes only; gather password
# securely from user, then perform your validation
['foo', 'plaintext password gathered securely'].map do |pw|
  valid_pw? pw, *parse_pw_entry(pw_entry)
end
#=> [false, true]

Спасибо. Это очень полезная и полезная информация. Моя цель — проверить пароли в хранилище данных, отличном от /etc/shadow, которое используется для другого приложения, но в котором используется тот же механизм хеширования crypt-md5, что и в /etc/shadow.

HippoMan 26.12.2020 19:39

Другие вопросы по теме