модуль OpenSSL::PKCS5
Предоставляет функциональность шифрования на основе паролей, основанную на PKCS#5. Обычно используется для безопасного получения симметричных ключей произвольной длины для использования с OpenSSL::Cipher из паролей. Другой сценарий использования — хранение паролей: благодаря возможности настраивать сложность вычислений путём увеличения количества итераций, вычисления могут быть искусственно замедлены, чтобы сделать возможные атаки неэффективными.
PKCS5 поддерживает PBKDF2 с HMAC на основе OpenSSL::Digest::SHA1 или произвольный Digest, если базовая версия OpenSSL уже поддерживает его (>= 0.9.4).
Параметры
Пароль
Обычно произвольная строка, представляющая пароль, используемый для получения ключа.
Соль
Предотвращает атаки, основанные на словарях распространённых паролей. Это общедоступное значение, которое можно безопасно хранить вместе с паролем (например, если PBKDF2 используется для хранения паролей). Для максимальной безопасности для каждого хранимого пароля должна генерироваться новая случайная соль. Согласно PKCS#5, соль должна быть не короче 8 байт.
Количество итераций
Позволяет настраивать длительность фактических вычислений. Чем больше количество итераций, тем дольше это займёт.
Длина ключа
Определяет длину вывода в байтах, который будет сгенерирован. Обычно длина ключа должна быть больше или равна длине вывода функции хеширования, в противном случае злоумышленник мог бы просто попытаться перебрать ключ. Согласно PKCS#5, безопасность ограничена длиной вывода функции хеширования, т. е. безопасность не улучшается, если выбранная длина ключа строго больше длины вывода хеширования. Поэтому, при использовании PKCS5 для хранения паролей достаточно хранить значения, равные длине вывода хеширования, хранение больших значений не даёт преимущества.
Примеры
Генерация 128-битного ключа для Cipher (например, AES)
pass = "secret" salt = OpenSSL::Random.random_bytes(16) iter = 20000 key_len = 16 key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(pass, salt, iter, key_len)
Хранение паролей
pass = "secret" salt = OpenSSL::Random.random_bytes(16) #store this with the generated value iter = 20000 digest = OpenSSL::Digest::SHA256.new len = digest.digest_length #the final value to be stored value = OpenSSL::PKCS5.pbkdf2_hmac(pass, salt, iter, len, digest)
Важное примечание по проверке паролей
При сравнении паролей, введённых пользователем, с предварительно сохранёнными значениями, распространённой ошибкой является сравнение двух значений с помощью оператора “==”. Обычно “==” выполняется по умолчанию, а значит уязвим к атакам, основанным на замерах времени выполнения. Правильный способ — использовать метод, который всегда затрачивает одинаковое количество времени при сравнении двух значений, не раскрывая никакой информации потенциальным злоумышленникам. Для сравнения двух значений можно использовать следующее:
def eql_time_cmp(a, b)
unless a.length == b.length
return false
end
cmp = b.bytes.to_a
result = 0
a.bytes.each_with_index {|c,i|
result |= c ^ cmp[i]
}
result == 0
end
Обратите внимание, что преждевременное возвращение в случае разной длины обычно не раскрывает ценной информации — при использовании PKCS#5 длина сравниваемых значений имеет фиксированный размер.
Методы открытого класса
static VALUE
ossl_pkcs5_pbkdf2_hmac(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen, VALUE digest)
{
VALUE str;
const EVP_MD *md;
int len = NUM2INT(keylen);
StringValue(pass);
StringValue(salt);
md = GetDigestPtr(digest);
str = rb_str_new(0, len);
if (PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LENINT(pass),
(unsigned char *)RSTRING_PTR(salt), RSTRING_LENINT(salt),
NUM2INT(iter), md, len,
(unsigned char *)RSTRING_PTR(str)) != 1)
ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC");
return str;
} Параметры
-
pass- строка -
salt- строка - длина должна быть не менее 8 байт. -
iter- целое число - должно быть больше 1000. 20000 лучше. -
keylen- целое число -
digest- строка или объект OpenSSL::Digest.
Доступно в OpenSSL 0.9.4.
Хеширования, отличные от SHA1, могут не поддерживаться другими библиотеками криптографии.
static VALUE
ossl_pkcs5_pbkdf2_hmac_sha1(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen)
{
VALUE str;
int len = NUM2INT(keylen);
StringValue(pass);
StringValue(salt);
str = rb_str_new(0, len);
if (PKCS5_PBKDF2_HMAC_SHA1(RSTRING_PTR(pass), RSTRING_LENINT(pass),
(const unsigned char *)RSTRING_PTR(salt), RSTRING_LENINT(salt), NUM2INT(iter),
len, (unsigned char *)RSTRING_PTR(str)) != 1)
ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC_SHA1");
return str;
} Параметры
-
pass- строка -
salt- строка - длина должна быть не менее 8 байт. -
iter- целое число - должно быть больше 1000. 20000 лучше. -
keylen- целое число
Этот метод доступен практически во всех версиях OpenSSL.
Соответствует rfc2898.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.