Spec-Zone.ru › Ruby 3.4
  1. OpenSSL::
  2. Digest

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)

Общедоступные методы класса

digest (name, data) Показать исходный код
# File ext/openssl/lib/openssl/digest.rb, line 25
def self.digest(name, data)
  super(data, name)
end

Возвращает значение хеша, вычисленное с помощью Digest name. name — это полное или краткое имя поддерживаемого алгоритма хеширования.

Пример

OpenSSL::Digest.digest("SHA256", "abc")
Вызов метода суперкласса
OpenSSL::Digest.digests → array[string...] Показать исходный код
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;
}

Возвращает массив имён всех доступных алгоритмов хеширования.

new(string [, data]) → Digest Показать исходный код
static VALUE
ossl_digest_initialize(int argc, VALUE *argv, VALUE self)
{
    EVP_MD_CTX *ctx;
    const EVP_MD *md;
    VALUE type, data;

    rb_scan_args(argc, argv, "11", &type, &data);
    md = ossl_evp_get_digestbyname(type);
    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");

    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')

Общедоступные методы экземпляра

<<
Псевдоним для: update
block_length → integer Показать исходный код
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
digest_length → integer Показать исходный код
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
initialize_copy (p1) Показать исходный код
static VALUE
ossl_digest_copy(VALUE self, VALUE other)
{
    EVP_MD_CTX *ctx1, *ctx2;

    rb_check_frozen(self);
    if (self == other) return self;

    TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx1);
    if (!ctx1) {
        RTYPEDDATA_DATA(self) = ctx1 = EVP_MD_CTX_new();
        if (!ctx1)
            ossl_raise(eDigestError, "EVP_MD_CTX_new");
    }
    GetDigest(other, ctx2);

    if (!EVP_MD_CTX_copy(ctx1, ctx2)) {
        ossl_raise(eDigestError, NULL);
    }
    return self;
}
name → string Показать исходный код
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)));
}

Возвращает краткое имя алгоритма Digest, которое может немного отличаться от исходного имени.

Пример

digest = OpenSSL::Digest.new('SHA512')
puts digest.name # => SHA512
reset → self Показать исходный код
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 снова переводится в исходное состояние.

update(string) → aString Показать исходный код
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
Также имеет псевдоним: <<

Закрытые методы экземпляра

finish → aString Показать исходный код
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.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API