класс 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
Возвращает значение хэша, вычисленное с помощью алгоритма name Digest. name — это длинное или короткое имя поддерживаемого алгоритма хэширования.
Пример
OpenSSL::Digest.digest("SHA256", "abc")
Исходный код
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;
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 на основе строки, которая является длинным (ln) или коротким (sn) именем поддерживаемого алгоритма хэширования. Список поддерживаемых алгоритмов можно получить, вызвав OpenSSL::Digest.digests.
Если данные (строка) указаны, они используются как начальные данные для экземпляра 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_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;
} Исходный код
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
Исходный код
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–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.