Bcrypt

Bcrypt

Bcrypt – представляет собой функцию хэширования паролей, основанную на шифре Blowfish. Впервые была представлена в USENIX в 1999 году разработчиками Niels Provos и David Mazières. Помимо включения salt для защиты от атаки Rainbow Table, bcrypt является адаптивной функцией: со временем, счетчик итераций может быть увеличен, чтобы сделать процесс медленнее, и таким образом повысить устойчивость к Brute-forse, даже с увеличением вычислительной мощности.

Функция bcrypt – это хэш-алгоритм пароля по умолчанию для OpenBSD и других систем, включая некоторые дистрибутивы Linux, такие как SUSE Linux. Существуют реализации bcrypt для C, C ++, C #, Go, Java, JavaScript, Perl, PHP, Python, Ruby и других языков.

Содержание

История

Blowfish примечателен среди блочных шифров для его дорогостоящей фазы настройки ключа. Он начинается с подключений в стандартном состоянии, затем использует это состояние для выполнения блочного шифрования с использованием части ключа и использует результат этого шифрования (более точно хеширование) для замены некоторых из подраздела. Затем он использует это измененное состояние для шифрования другой части ключа и использует результат для замены большего количества подразделов. Это происходит таким образом: используется прогрессивно измененное состояние для хеширования ключа и замены бит состояния, пока не будут установлены все подразделы.

Прово и Мазьер воспользовались этим и продолжили. Они разработали новый алгоритм настройки ключей для Blowfish, дублируя полученный шифр «Eksblowfish» («дорогой ключевой график Blowfish»). Настройка ключа начинается с измененной формы стандартной настройки ключа Blowfish, в которой и salt, и пароль используются для установки всех подразделов. Затем выполняется ряд раундов, в которых применяется стандартный алгоритм Key Blowfish, используя альтернативу salt и пароль в качестве ключа, каждый раунд, начинается с состояния подраздела из предыдущего раунда. Теоретически это не более сильное, чем стандартное расписание ключевых событий Blowfish, но количество раундов переключения настраивается; поэтому этот процесс можно сделать произвольно медленным, что помогает предотвратить атаки грубой силы на хэш или salt.

Описание

Префикс «$ 2a $» или «$ 2b $» (или «$ 2y $») в хэш-строке в файле теневого пароля указывает, что хэш-строка является хэшем bcrypt в модульном формате склепа. Остальная часть хэш-строки включает параметр стоимости, 128-битную salt ( Radix-64, закодированную как 22 символа) и 184 бит полученного хеш-значения ( Radix-64, закодированное как 31 символ). Кодировка Radix-64 использует алфавит unix / crypt и не является «стандартным» Base-64 . Параметр cost указывает количество итераций расширения ключа как мощность двух, что является входом в алгоритм.

Например, запись теневого пароля $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWyуказывает параметр стоимости 10, что указывает на 2 10 раундов расширения ключа. Salt тут N9qo8uLOickgx2ZMRZoMyeи полученный хеш IjZAgcfl7p92ldGxad68LJZdL17lhWy. В стандартной практике пароль пользователя не сохраняется.

Версии Bcrypt

$ 2 $ (1999)

В исходной спецификации Bcrypt определен префикс $2$. Это следует за форматом Modular Crypt Format, используемым при хранении паролей в файле паролей OpenBSD:

  • $1$: MD5
  • $2$: Bcrypt
  • $sha1$: SHA-1
  • $5$: SHA-256
  • $6$: SHA-512

$ 2a $

Изначально, в спецификации не значилось, как обрабатывать не-ASCII-символ и нулевой ограничитель, поэтому она была дополнена, чтобы утвердить следующие положения:

  • строка должна кодироваться в кодировке UTF-8
  • нулевой ограничитель должен быть включен

С этим изменением версия была изменена на $2a$]

$ 2x $, $ 2y $ (июнь 2011 г.)

В июне 2011 года была обнаружена ошибка в crypt_blowfish, в PHP-реализации Bcrypt, которая заключалась в некорректности символов с 8-м битом. Они предложили, чтобы системные администраторы обновили свою существующую базу паролей, заменив ее $2a$на $2x$, чтобы указать, что эти хэши не рабочие (и нужно использовать старый сломанный алгоритм). Они также предложили идею иметь crypt_blowfish выпускающий $2y$для хешей, генерируемых фиксированным алгоритмом.

Никто, включая канонический OpenBSD, не принял идею 2x / 2y. Это изменение маркера версии было ограничено crypt_blowfish .

$ 2b $ (февраль 2014 г.)

Обнаружена ошибка в реализации bcrypt OpenBSD. Они сохраняли длину своих строк в unsigned char ( т.е. 8-битный Byte).] Если пароль был длиннее 255 символов, он переполнялся и завершался на 255.

BCrypt был создан для OpenBSD. Когда у них была ошибка в их библиотеке, они решили поднять номер версии.

Алгоритм

Алгоритм bcrypt является результатом шифрования текста «OrpheanBeholderScryDoubt» 64 раза с использованием Blowfish. В bcrypt обычная функция настройки ключа Blowfish заменяется функцией дорогостоящей настройки ключа (EksBlowfishSetup):

Function bcrypt

  Input:      cost:     Number (4..31)                      log 2 (итерации). например, 12 ==> 2 12 = 4096 итераций      salt:     array of Bytes (16 bytes)           случайный salt      password: array of Bytes (1..72 bytes)        Пароль с кодировкой UTF-8   Output:       hash:     array of Bytes (24 bytes) 
  // Инициализировать состояние Blowfish        state   EksBlowfishSetup(cost, salt, password)  
  // Повторно шифровать текст «OrpheanBeholderScryDoubt» 64 раза       ctext   "OrpheanBeholderScryDoubt" // 24 байта ==> три 64-битных блока       repeat (64)      ctext   EncryptECB(state, ctext) // шифрование с использованием стандартного Blowfish в режиме ECB 
  // 24-байтовый ctext    return Concatenate(cost, salt, ctext)  

Установка дорогостоящего ключа

Алгоритм bcrypt в значительной степени зависит от алгоритма настройки ключа «Eksblowfish», который работает следующим образом: Function EksBlowfishSetup

 Input:      cost:     Number (4..31)                   log 2 (итерации). например, 12 ==> 2 12 = 4096 итераций      salt:     array of Bytes (16 bytes)        случайный salt        password: array of Bytes (1..72 bytes)     Пароль с кодировкой UTF-8      Output:       state:    opaque BlowFish state structure       state   InitialState()      state   ExpandKey(state, salt, password)      repeat (2cost)      state   ExpandKey(state, 0, password)      state   ExpandKey(state, 0, salt) 
   return state   

InitialState работает как в оригинальном алгоритме Blowfish, заполняя записи P-массива и S-box дробной частью Pi в шестнадцатеричном формате.

Расширение ключа

Функция ExpandKey выполняет следующие действия: Function ExpandKey(state, salt, password)

  Input:      state:    Opaque BlowFish state structure     Внутренне содержит записи массива P-массива и S-поля      salt:     array of Bytes (16 bytes)           случайный salt      password: array of Bytes (1..72 bytes)        Пароль с кодировкой UTF-8   Output:       state:    opaque BlowFish state structure    // Смешиваем пароль во внутренний P-массив state   for n   1 to 18 do      Pn   Pn xor password[32(n-1)..32n-1] // обрабатываем пароль как циклический 
  // Шифруем состояние, используя более низкие 8 байт соли, и сохраняем результат 8 байтов в P1|P2      block   Encrypt(state, salt[0..63])      P1   block[0..31]  //lower 32-bits      P2   block[32..63] //upper 32-bits 
  // Продолжаем шифрование состояния с salt и сохранение результатов в оставшемся P-массиве   for n   2 to 9 do      block   Encrypt(state, block xor salt[64(n-1)..64n-1]) // шифруем с использованием текущего ключа графика           P2n-1   block[0..31] //lower 32-bits      P2n   block[32..63]  //upper 32-bits 
  // Перемещаем зашифрованное состояние во внутренние S-поля e   for i   1 to 4 do      for n   0 to 127 do         block   Encrypt(state, block xor salt[64(n-1)..64n-1]) //as above         Si[2n]     block[0..31]  //ниже 32-bits         Si[2n+1]   block[32..63]  //выше 32-bits    return state  

Следовательно, это то же самое, что и регулярное расписание ключей Blowfish, поскольку все XOR с нулевым значением соли неэффективны. Аналогичен, но использует salt в виде 128-битного ключа. ExpandKey(state, 0, key)ExpandKey(state, 0, salt)

Вход пользователя

Многие реализации bcrypt урезают пароль до первых 72 байтов. Сам математический алгоритм требует инициализации с 18 32-разрядными подразделами (эквивалентно 72 октетам / байтам). Исходная спецификация bcrypt не предусматривает какого-либо одного конкретного метода для преобразования паролей на основе текста из userland в числовые значения для алгоритма. Один краткий комментарий в тексте упоминает, но не дает мандата, о возможности просто использовать кодированное значение ASCII символьной строки: «Наконец, ключевым аргументом является секретный ключ шифрования, который может быть выбранным пользователем паролем до 56 байтов (включая завершающий нулевой байт, когда ключ является строкой ASCII)”.

Обратите внимание, что в приведенной выше цитате упоминаются пароли «до 56 байтов», хотя сам алгоритм использует начальное значение в 72 байта. Хотя Provos и Mazières не указывают причину более короткого ограничения, они, возможно, были мотивированы следующим утверждением от первоначальной спецификации Bruce Schneier «Blowfish» «Ограничение по размеру ключа 448 [бит] гарантирует, что [ sic ] каждый бит каждого подраздела зависит от каждого бита ключа”.

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

См. также на BitcoinWiki

Подробнее