class OpenSSL::Digest
OpenSSL::Digest позволяет вычислять дайджесты сообщений (иногда их также называют «хешами») для произвольных данных, обеспечивая криптографическую безопасность; то есть Digest реализует безопасную одностороннюю функцию.
Односторонние функции обладают рядом полезных свойств. Например, для двух различных входных данных вероятность того, что они дадут одинаковый результат, крайне мала. В сочетании с тем, что каждый алгоритм дайджеста сообщения выдаёт результат фиксированной длины — всего несколько байтов, — это свойство позволяет использовать дайджесты для создания уникальных идентификаторов произвольных данных. Распространённый пример — создание уникального идентификатора для двоичных документов, хранящихся в базе данных.
Ещё одна полезная характеристика односторонних функций (что отражено и в их названии) заключается в том, что по дайджесту нельзя определить исходные данные, на основе которых он был получен; то есть единственный способ определить исходные данные — перебрать все возможные комбинации входных данных.
Эти характеристики также делают односторонние функции идеальным дополнением к алгоритмам подписи с открытым ключом: вместо подписания всего документа сначала вычисляется его хеш с помощью значительно более быстрого алгоритма дайджеста сообщения, а затем с использованием более медленного алгоритма с открытым ключом подписываются всего несколько байтов результата. Чтобы проверить целостность подписанного документа, достаточно повторно вычислить хеш и убедиться, что он совпадает с хешем в подписи.
Список всех алгоритмов дайджеста, поддерживаемых в вашей системе, можно получить, выполнив в терминале следующую команду:
openssl list -digest-algorithms
Среди алгоритмов дайджеста сообщений, поддерживаемых OpenSSL 1.1.1, есть:
-
SHA224, SHA256, SHA384, SHA512, SHA512-224 и SHA512-256
-
SHA3-224, SHA3-256, SHA3-384 и SHA3-512
-
BLAKE2s256 и BLAKE2b512
Каждый из этих алгоритмов можно создать, указав его имя:
digest = OpenSSL::Digest.new('SHA256')
«Взлом» алгоритма дайджеста сообщения означает нарушение свойств его односторонней функции, то есть создание коллизии или поиск способа получить исходные данные более эффективным методом, чем полный перебор и т. п. Большинство поддерживаемых алгоритмов дайджеста можно считать взломанными в этом смысле, в том числе очень популярные алгоритмы MD5 и SHA1. Если для вас безопасность имеет первостепенное значение, следует использовать SHA224, SHA256, SHA384 или SHA512.
Хеширование файла
data = File.binread('document')
sha256 = OpenSSL::Digest.new('SHA256')
digest = sha256.digest(data)
Хеширование нескольких фрагментов данных за один раз
data1 = File.binread('file1')
data2 = File.binread('file2')
data3 = File.binread('file3')
sha256 = OpenSSL::Digest.new('SHA256')
sha256 << data1
sha256 << data2
sha256 << data3
digest = sha256.digest
Повторное использование экземпляра Digest
data1 = File.binread('file1')
sha256 = OpenSSL::Digest.new('SHA256')
digest1 = sha256.digest(data1)
data2 = File.binread('file2')
sha256.reset
digest2 = sha256.digest(data2)
Общедоступные методы класса
# File ext/openssl/lib/openssl/digest.rb, line 25 def self.digest(name, data) super(data, name) end
static VALUE
ossl_s_digests(VALUE self)
{
VALUE ary;
ary = rb_ary_new();
OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
add_digest_name_to_ary,
(void*)ary);
return ary;
} Возвращает массив с именами всех доступных алгоритмов дайджеста.
static VALUE
ossl_digest_initialize(int argc, VALUE *argv, VALUE self)
{
EVP_MD_CTX *ctx;
const EVP_MD *md;
VALUE type, data, md_holder;
rb_scan_args(argc, argv, "11", &type, &data);
md = ossl_evp_md_fetch(type, &md_holder);
if (!NIL_P(data)) StringValue(data);
TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx);
if (!ctx) {
RTYPEDDATA_DATA(self) = ctx = EVP_MD_CTX_new();
if (!ctx)
ossl_raise(eDigestError, "EVP_MD_CTX_new");
}
if (!EVP_DigestInit_ex(ctx, md, NULL))
ossl_raise(eDigestError, "Digest initialization failed");
rb_ivar_set(self, id_md_holder, md_holder);
if (!NIL_P(data)) return ossl_digest_update(self, data);
return self;
} Создаёт экземпляр Digest на основе string, которое является полным именем (ln) или сокращённым именем (sn) поддерживаемого алгоритма дайджеста. Список поддерживаемых алгоритмов можно получить вызовом OpenSSL::Digest.digests.
Если задано data (объект String), оно используется как начные входные данные для экземпляра Digest, то есть:
digest = OpenSSL::Digest.new('sha256', 'digestdata')
эквивалентно
digest = OpenSSL::Digest.new('sha256')
digest.update('digestdata')
Общедоступные методы экземпляра
static VALUE
ossl_digest_block_length(VALUE self)
{
EVP_MD_CTX *ctx;
GetDigest(self, ctx);
return INT2NUM(EVP_MD_CTX_block_size(ctx));
} Возвращает длину блока алгоритма дайджеста, то есть длину отдельного блока в байтах. Большинство современных алгоритмов разбивают обрабатываемое сообщение на последовательность блоков фиксированного размера, которые обрабатываются по очереди.
Пример
digest = OpenSSL::Digest.new('SHA1')
puts digest.block_length # => 64
static VALUE
ossl_digest_size(VALUE self)
{
EVP_MD_CTX *ctx;
GetDigest(self, ctx);
return INT2NUM(EVP_MD_CTX_size(ctx));
} Возвращает размер выходных данных дайджеста, то есть длину итогового дайджеста сообщения в байтах.
Пример
digest = OpenSSL::Digest.new('SHA1')
puts digest.digest_length # => 20
static VALUE
ossl_digest_name(VALUE self)
{
EVP_MD_CTX *ctx;
GetDigest(self, ctx);
return rb_str_new_cstr(EVP_MD_name(EVP_MD_CTX_get0_md(ctx)));
} static VALUE
ossl_digest_reset(VALUE self)
{
EVP_MD_CTX *ctx;
GetDigest(self, ctx);
if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_get0_md(ctx), NULL) != 1) {
ossl_raise(eDigestError, "Digest initialization failed.");
}
return self;
} Сбрасывает Digest: все выполненные вызовы Digest#update отменяются, а Digest возвращается в исходное состояние.
static VALUE
ossl_digest_update(VALUE self, VALUE data)
{
EVP_MD_CTX *ctx;
StringValue(data);
GetDigest(self, ctx);
if (!EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)))
ossl_raise(eDigestError, "EVP_DigestUpdate");
return self;
} Не каждый дайджест сообщения можно вычислить за один проход. Если дайджест сообщения вычисляется по нескольким последовательным источникам данных, каждый из них можно по отдельности передать экземпляру Digest.
Пример
digest = OpenSSL::Digest.new('SHA256')
digest.update('First input')
digest << 'Second input' # equivalent to digest.update('Second input')
result = digest.digest
Приватные методы экземпляра
static VALUE
ossl_digest_finish(VALUE self)
{
EVP_MD_CTX *ctx;
VALUE str;
GetDigest(self, ctx);
str = rb_str_new(NULL, EVP_MD_CTX_size(ctx));
if (!EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL))
ossl_raise(eDigestError, "EVP_DigestFinal_ex");
return str;
}
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.