Достаточно ли исходного кода Ruby для OpenSSL :: Random?

Я очень мало знаю о Ruby, поэтому, пожалуйста, простите меня, если ответ на этот вопрос очевиден. Я заметил на http://www.ruby-doc.org/stdlib-1.9.3/libdoc/securerandom/rdoc/SecureRandom.html, что Ruby использует pid и текущее время для заполнения OpenSSL :: Random при вызове random_bytes. Если что-то еще не происходит под покровом, разве это не та семя, которое Netscape использовала в своей первоначальной реализации SSL в середине 90-х? http://en.wikipedia.org/wiki/Random_number_generator_attack#Random_number_generator_attack#

Конечно, Руби не исправила ошибку 18-летней давности. Что мне здесь не хватает?

Изменить: вот источник random_bytes. Обратите внимание на первую проверку, чтобы увидеть, был ли ruby ​​скомпилирован с помощью OpenSSL, и в этом случае он заполняет его pid и текущим временем.

def self.random_bytes(n=nil)
  n = n ? n.to_int : 16

  if defined? OpenSSL::Random
    @pid = 0 if !defined?(@pid)
    pid = $$
    if @pid != pid
      now = Time.now
      ary = [now.to_i, now.nsec, @pid, pid]
      OpenSSL::Random.seed(ary.to_s)
      @pid = pid
    end
    return OpenSSL::Random.random_bytes(n)
  end

  if !defined?(@has_urandom) || @has_urandom
    flags = File::RDONLY
    flags |= File::NONBLOCK if defined? File::NONBLOCK
    flags |= File::NOCTTY if defined? File::NOCTTY
    begin
      File.open("/dev/urandom", flags) {|f|
        unless f.stat.chardev?
          raise Errno::ENOENT
        end
        @has_urandom = true
        ret = f.readpartial(n)
        if ret.length != n
          raise NotImplementedError, "Unexpected partial read from random device: only #{ret.length} for #{n} bytes"
        end
        return ret
      }
    rescue Errno::ENOENT
      @has_urandom = false
    end
  end

  if !defined?(@has_win32)
    begin
      require 'Win32API'

      crypt_acquire_context = Win32API.new("advapi32", "CryptAcquireContext", 'PPPII', 'L')
      @crypt_gen_random = Win32API.new("advapi32", "CryptGenRandom", 'LIP', 'L')

      hProvStr = " " * 4
      prov_rsa_full = 1
      crypt_verifycontext = 0xF0000000

      if crypt_acquire_context.call(hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0
        raise SystemCallError, "CryptAcquireContext failed: #{lastWin32ErrorMessage}"
      end
      @hProv, = hProvStr.unpack('L')

      @has_win32 = true
    rescue LoadError
      @has_win32 = false
    end
  end
  if @has_win32
    bytes = " ".force_encoding("ASCII-8BIT") * n
    if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
      raise SystemCallError, "CryptGenRandom failed: #{lastWin32ErrorMessage}"
    end
    return bytes
  end

  raise NotImplementedError, "No random device"
end

person iamtheneal    schedule 25.08.2012    source источник
comment
Это не очень хорошо задокументировано, не так ли? Было бы поучительно более внимательно взглянуть на источник, чтобы увидеть, что OpenSSL делает с предоставленными значениями. Он должен использовать любые доступные случайные средства уровня ОС, такие как /dev/urandom или /dev/random вместо чего-то подобного.   -  person tadman    schedule 25.08.2012
comment
Заметьте, что я нашел некоторое обсуждение того, как разветвление может привести к уязвимостям, что не предвещает ничего хорошего для того, как Ruby вызывает OpenSSL.   -  person Maarten Bodewes    schedule 25.08.2012
comment
Не могли бы вы указать, где говорится, что Ruby использует pid и текущее время как (только) начальные числа?   -  person Maarten Bodewes    schedule 25.08.2012
comment
С тех пор он был изменен на / dev / urandom FWIW bugs.ruby-lang.org/issues/ 9569 не говоря уже о другом патче, присланном в результате этого вопроса :)   -  person rogerdpack    schedule 06.03.2020


Ответы (3)


Какой ГСЧ используется, зависит от конфигурации Ruby:

Безопасный интерфейс генератора случайных чисел.

Эта библиотека представляет собой интерфейс для безопасного генератора случайных чисел, который подходит для генерации сеансового ключа в файлах cookie HTTP и т. Д.

Он поддерживает следующие безопасные генераторы случайных чисел.

  • openssl

  • /dev/urandom

  • Win32

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

Глядя на код в вопросе, становится ясно, что Ruby напрямую использует байты, сгенерированные OpenSSL, после дополнительно заполнение PID:

Всякий раз, когда добавляются начальные данные, они вставляются в «состояние» следующим образом.

Входные данные разбиваются на блоки по 20 байтов (или меньше для последнего блока). Каждый из этих блоков проходит через хеш-функцию следующим образом: данные, передаваемые в хеш-функцию, представляют собой текущее 'md', такое же количество байтов из 'состояния' (местоположение, определяемое увеличивающимся индексом цикла), что и текущее «блок», «блок» новых ключевых данных и «счетчик» (который увеличивается после каждого использования). Результат этого сохраняется в «md», а также фиксируется в «состоянии» в тех же местах, которые использовались в качестве входных данных для хеш-функции. Я считаю, что эта система адресует точки 1 (хеш-функция; в настоящее время SHA-1), 3 («состояние»), 4 (через «md»), 5 (с помощью хеш-функции и xor).

person Maarten Bodewes    schedule 25.08.2012
comment
Насколько безопасен, зависит от фактической реализации и базовой платформы, но это должно быть очевидно. - person Maarten Bodewes; 25.08.2012
comment
В частности, это зависит от того, правильно ли засеян рассматриваемый prng, и отвечает ли вызывающий за предоставление такого начального числа, или сами семена prng. - person iamtheneal; 25.08.2012
comment
@iamtheneal, если я посмотрю на код SecureRandom.rb, на котором он основан стандартное заполнение библиотеки openssl или операционной системы, что должно быть абсолютно нормально, если с библиотекой / операционной системой все в порядке. - person Maarten Bodewes; 25.08.2012
comment
Из кода Ruby было непонятно (мне), подходит ли раздача. Из источника вы можете видеть, что SecureRandom.rb предоставляет собственное семя для OpenSSL. Мне (ну, моему коллеге) пришлось покопаться в коде OpenSSL, чтобы убедиться, что предоставление собственного начального числа не подавляет собственное внутреннее заполнение OpenSSL. - person iamtheneal; 25.08.2012
comment
Есть некоторые различия в отношении заполнения между библиотеками. Большинство будет смешано с семенами в бассейне. Но иногда первое семя используется только как случайное (так что вы можете сгенерировать тот же поток), иногда повторное семя полностью сбрасывает ГСЧ. Я думаю, что все трое, упомянутые здесь, добавляют семя в пул, так что тогда вы в безопасности. В большинстве случаев это не совсем документировано. - person Maarten Bodewes; 25.08.2012
comment
Согласованный. В этом случае все идет хорошо, поскольку семя добавляется, а не используется в качестве замены. Меня беспокоит то, что я не понимаю, что OpenSSL делает под прикрытием. Кроме того, я определенно согласен с вашим мнением о документации. Мне кажется, что все вовлеченные стороны (Ruby и OpenSSL) могли бы гораздо лучше документировать вещи. - person iamtheneal; 25.08.2012
comment
Я добавил документацию, о которой идет речь, для функции OpenSSL rand. - person Maarten Bodewes; 25.08.2012

Начальное число, используемое в SecureRandom, запрещает предсказуемые случайные числа, возникающие при повторном использовании PID. Без исправления в SecureRandom генератор случайных чисел OpenSSL будет выдавать одни и те же значения в разных процессах, имеющих один и тот же PID.

# 4579 описывает, как это может происходить, а соответствующая запись в списке рассылки OpenSSL более или менее сообщает нам, что это должно быть решено в клиентском коде. Вот почему этот сид был выбран в Ruby для предотвращения угрозы безопасности. Если вы не уверены, запустите скрипт Эрика Вонга, прикрепленного к версии Ruby до этого исправления, чтобы увидеть о чем все это было.

Добавляя к объяснению Оулстеда, заполнение ГСЧ OpenSSL на этом этапе не ставит под угрозу безопасность, потому что неинициализированный генератор случайных чисел всегда будет сначала вызывать RAND_poll, который будет собирать достаточную энтропию независимо от того, были ли ранее добавлены / добавлены значения или нет.

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

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

В заключение, выбор значений (PID и время) был разумным, он даже увеличивает общую безопасность (предотвращая «атаку переработанного PID») вместо того, чтобы уменьшать ее.

person emboss    schedule 27.08.2012
comment
Я согласен. По общему признанию, моя риторика была ненужной и контрпродуктивной. В конце концов, мне кажется, что это вопрос документации. Было несколько сложно подтвердить, что реализация SecureRandom в Ruby не снижает безопасность. В любом случае, спасибо за ваш вклад. Кроме того, я отредактировал свой ответ, чтобы сделать его менее вызывающим. - person iamtheneal; 27.08.2012
comment
@iamtheneal Спасибо! Я удалил комментарий и тоже изменил свой ответ. - person emboss; 27.08.2012

Мой коллега исследовал это и обнаружил, что выбор семени был введен как ответ на эту ошибку:

http://bugs.ruby-lang.org/issues/4579

К счастью, OpenSSL засевает себя 256 битами энтропии из / dev / urandom (если доступно) или egd («демон сбора энтропии» - предшественник / dev / urandom) в зависимости от того, как он был скомпилирован. Заполнение происходит автоматически при первом вызове RAND_status () или RAND_bytes () и не подавляется, если RAND_seed () вызывается явно. Престижность людям OpenSSL за это решение. Вот ссылка на конкретный код OpenSSL:

http://cvs.openssl.org/dir?d=openssl/crypto/rand

Интересные файлы: md_rand.c, rand_lib.c и rand_unix.c.

person iamtheneal    schedule 25.08.2012