Введение
Алгоритм шифрования, который я хочу представить вам сегодня, называется bcrypt.bcrypt — это хеш-функция пароля, разработанная Нильсом Провосом и Давидом Мазьером, основанная на шифре Blowfish и предложенная USENIX в 1999 году.
Помимо добавления соли для противодействия атакам радужных таблиц, очень важной особенностью bcrypt является его адаптивность, которая может гарантировать, что скорость шифрования находится в определенном диапазоне, даже если вычислительная мощность компьютера очень высока, ее можно увеличить. за счет увеличения количества итераций. , что делает шифрование медленнее, что может противостоять атакам с перебором.
Функция bcrypt является алгоритмом хеширования паролей по умолчанию для OpenBSD и других систем, включая некоторые дистрибутивы Linux, такие как SUSE Linux.
Как работает крипто
Давайте сначала рассмотрим принцип шифрования Blowfish. Blowfish сначала должен сгенерировать массив K и S-блок для шифрования.Blowfish требуется определенное время, чтобы сгенерировать окончательный массив K и S-блок.Каждый новый ключ должен быть предварительно обработан примерно 4 КБ текста.По сравнению с другие блочные шифры, это будет медленно. Но когда генерация завершена или ключ остается неизменным, Blowfish по-прежнему остается очень быстрым методом блочного шифрования.
Так есть ли никакой выгоды, чтобы быть медленным?
Конечно есть, ведь для нормального приложения ключ не будет часто меняться. Таким образом, предварительная обработка будет сгенерирована только один раз. Это будет очень быстро при использовании его позже.
Для злоумышленников каждая попытка нового ключа требует длительной предварительной обработки, поэтому злоумышленникам очень неэкономично взламывать алгоритм Blowfish. Таким образом, Blowfish устойчив к атакам по словарю.
Прово и Мазьер воспользовались этим и пошли еще дальше. Они разработали новый алгоритм установки ключей для Blowfish, назвав полученный шифр «Eksblowfish» («дорогая схема ключей Blowfish»). Это улучшенный алгоритм для Blowfish, при первоначальной настройке ключа bcrypt для настройки подключа используются и соль, и пароль. Затем пройдите раунды стандартного алгоритма Blowfish, поочередно используя соль и пароль в качестве ключей, каждый раунд зависит от состояния предыдущего раунда подключа. Хотя теоретически сила алгоритма bcrypt не лучше, чем у blowfish, но поскольку количество раундов для сброса ключа в bcrpyt настраивается, можно лучше противостоять атакам грубой силы, увеличив количество раундов.
Реализация алгоритма bcrypt
Проще говоря, алгоритм bcrypt представляет собой строкуOrpheanBeholderScryDoubtРезультат выполнения 64 шифрований Blowfish. Некоторые друзья спросят, а разве bcrypt не используется для шифрования паролей? Как зашифровать строку?
Не волнуйтесь, bcrpyt использует пароль как фактор для шифрования строки, а также получает эффект шифрования. Давайте посмотрим на базовую реализацию алгоритма bcrypt:
Function bcrypt
Input:
cost: Number (4..31) log2(Iterations). e.g. 12 ==> 212 = 4,096 iterations
salt: array of Bytes (16 bytes) random salt
password: array of Bytes (1..72 bytes) UTF-8 encoded password
Output:
hash: array of Bytes (24 bytes)
//Initialize Blowfish state with expensive key setup algorithm
//P: array of 18 subkeys (UInt32[18])
//S: Four substitution boxes (S-boxes), S0...S3. Each S-box is 1,024 bytes (UInt32[256])
P, S <- EksBlowfishSetup(cost, salt, password)
//Repeatedly encrypt the text "OrpheanBeholderScryDoubt" 64 times
ctext <- "OrpheanBeholderScryDoubt" //24 bytes ==> three 64-bit blocks
repeat (64)
ctext <- EncryptECB(P, S, ctext) //encrypt using standard Blowfish in ECB mode
//24-byte ctext is resulting password hash
return Concatenate(cost, salt, ctext)
Вышеупомянутая функция bcrypt имеет 3 входа и 1 выход.
Во входной части стоимость представляет собой количество раундов, которое мы можем указать сами, чем больше раундов, тем медленнее шифрование.
соль — это соль шифрования, используемая для запутывания использования пароля.
password — это пароль, который мы хотим зашифровать.
Конечным результатом является зашифрованный хеш.
Имея 3 входа, мы вызовем функцию EksBlowfishSetup для инициализации 18 подразделов и 4 S-блоков размером 1 КБ для получения окончательных P и S.
Затем используйте P и S для 64 операций иглобрюха для "OrpheanbeholdersCrydoubt" и, наконец, получите результаты.
Далее рассмотрим алгоритм реализации метода EksBlowfishSetup:
Function EksBlowfishSetup
Input:
password: array of Bytes (1..72 bytes) UTF-8 encoded password
salt: array of Bytes (16 bytes) random salt
cost: Number (4..31) log2(Iterations). e.g. 12 ==> 212 = 4,096 iterations
Output:
P: array of UInt32 array of 18 per-round subkeys
S1..S4: array of UInt32 array of four SBoxes; each SBox is 256 UInt32 (i.e. 1024 KB)
//Initialize P (Subkeys), and S (Substitution boxes) with the hex digits of pi
P, S <- InitialState()
//Permutate P and S based on the password and salt
P, S <- ExpandKey(P, S, salt, password)
//This is the "Expensive" part of the "Expensive Key Setup".
//Otherwise the key setup is identical to Blowfish.
repeat (2cost)
P, S <- ExpandKey(P, S, 0, password)
P, S <- ExpandKey(P, S, 0, salt)
return P, S
Код очень прост, EksBlowfishSetup получает наши 3 параметра выше и возвращает окончательный P, содержащий 18 подразделов и 4 Sbox размером 1k.
Сначала инициализируйте, получите начальные P и S.
Затем вызовите ExpandKey, передайте соль и пароль и сгенерируйте P и S для первого раунда.
Затем зациклите квадрат стоимости 2, используйте пароль и соль в качестве параметров по очереди, чтобы сгенерировать P и S, и, наконец, вернуться.
Наконец, взгляните на реализацию ExpandKey:
Function ExpandKey
Input:
password: array of Bytes (1..72 bytes) UTF-8 encoded password
salt: Byte[16] random salt
P: array of UInt32 Array of 18 subkeys
S1..S4: UInt32[1024] Four 1 KB SBoxes
Output:
P: array of UInt32 Array of 18 per-round subkeys
S1..S4: UInt32[1024] Four 1 KB SBoxes
//Mix password into the P subkeys array
for n <- 1 to 18 do
Pn <- Pn xor password[32(n-1)..32n-1] //treat the password as cyclic
//Treat the 128-bit salt as two 64-bit halves (the Blowfish block size).
saltHalf[0] <- salt[0..63] //Lower 64-bits of salt
saltHalf[1] <- salt[64..127] //Upper 64-bits of salt
//Initialize an 8-byte (64-bit) buffer with all zeros.
block <- 0
//Mix internal state into P-boxes
for n <- 1 to 9 do
//xor 64-bit block with a 64-bit salt half
block <- block xor saltHalf[(n-1) mod 2] //each iteration alternating between saltHalf[0], and saltHalf[1]
//encrypt block using current key schedule
block <- Encrypt(P, S, block)
P2n <- block[0..31] //lower 32-bits of block
P2n+1 <- block[32..63] //upper 32-bits block
//Mix encrypted state into the internal S-boxes of state
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] //lower 32-bits
Si[2n+1] <- block[32..63] //upper 32-bits
return state
Расширька в основном используется для генерации P и S. Генерация алгоритма более сложна. Если вы заинтересованы, вы можете изучить его подробно.
Структура хэша bcrypt
Мы можем использовать bcrypt для шифрования пароля и, наконец, сохранить его в системе в виде хэша bcrypt Формат хэша bcrypt выглядит следующим образом:
$2b$[cost]$[22 character salt][31 character hash]
Например:
$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
\__/\/ \____________________/\_____________________________/
Alg Cost Salt Hash
В приведенном выше примере$2a$
Представляет уникальный флаг алгоритма хеширования. Это представляет алгоритм bcrypt.
10 представляет фактор стоимости, здесь 10-я степень 2, что составляет 1024 патрона.
N9qo8uLOickgx2ZMRZoMye — это символ длиной 22, полученный с помощью base64, кодирующего 16-байтовую (128-битную) соль.
Последний IjZAgcfl7p92ldGxad68LJZdL17lhWy — это 24-байтовый (192-битный) хеш, символ длиной 31, полученный кодировкой bash64.
История хеширования
Этот формат хэша соответствует формату модульного склепа, используемому при хранении паролей в файлах паролей OpenBSD. Первоначально определение формата было следующим:
-
$1$
: MD5-based crypt ('md5crypt') -
$2$
: Blowfish-based crypt ('bcrypt') -
$sha1$
: SHA-1-based crypt ('sha1crypt') -
$5$
: SHA-256-based crypt ('sha256crypt') -
$6$
: SHA-512-based crypt ('sha512crypt')
Но исходная спецификация не определяла, как обращаться с символами, отличными от ASCII, и как обращаться с ограничителем null. В пересмотренной спецификации указано, что при хешировании строк:
- Строка должна быть в кодировке UTF-8.
- должен содержать нулевой терминатор
Из-за этих изменений номер версии bcrypt был изменен на$2a$
.
Но в июне 2011 года из-за реализации bcypt в PHPcrypt_blowfishОшибка в , они советуют системным администраторам обновить свою существующую базу паролей с помощью$2x$
заменять$2a$
, чтобы указать, что эти хэши плохие (необходимо использовать старый алгоритм). Они также предлагают использовать заголовки crypt_blowfish для хэшей, сгенерированных новым алгоритмом.$2y$
. Конечно, это изменение ограничено PHP.crypt_blowfish.
Затем, в феврале 2014 года, также была обнаружена ошибка в реализации bcrypt в OpenBSD, где они сохраняют длину строки в беззнаковом символе (т.е. 8-битном байте). Если пароль длиннее 255 символов, он переполнится.
Потому что bcrypt был создан для OpenBSD. Поэтому, когда в их библиотеке появилась ошибка, они решили обновить номер версии до$2b$
.
Эта статья была включена вwww.flydean.com/37-bcrypt/
Самая популярная интерпретация, самая глубокая галантерея, самые краткие уроки и множество трюков, о которых вы не знаете, ждут вас!
Добро пожаловать, чтобы обратить внимание на мой официальный аккаунт: «Программируйте эти вещи», разбирайтесь в технологиях, лучше поймите себя!