class OpenSSL::Digest
OpenSSL::Digest позволяет вычислить дайджесты сообщений (иногда взаимозаменяемо называемые «хешами») произвольных данных, которые являются криптографически безопасными, т.е. Digest реализует безопасную одностороннюю функцию.
Односторонние функции предлагают некоторые полезные свойства. Например, при двух различных входных данных вероятность того, что оба дадут один и тот же результат, очень мала. В сочетании с тем, что каждый алгоритм дайджеста сообщений имеет выходные данные фиксированной длины всего в несколько байтов, дайджесты часто используются для создания уникальных идентификаторов произвольных данных. Типичный пример — создание уникального идентификатора для двоичных документов, хранящихся в базе данных.
Еще одной полезной характеристикой односторонних функций (и, следовательно, их названием) является то, что, зная дайджест, нет информации об исходных данных, которые его произвели, т.е. единственный способ идентифицировать исходный вход — это «перебор» всех возможных комбинаций входов.
Эти характеристики также делают односторонние функции идеальными компаньонами для алгоритмов подписи с открытым ключом: вместо подписи всего документа сначала вычисляется хэш документа с помощью значительно более быстрого алгоритма дайджеста сообщений, и только несколько байтов его результата необходимо подписать с помощью более медленного алгоритма с открытым ключом. Для проверки целостности подписанного документа достаточно повторно вычислить хэш и проверить, что он равен хэшу в подписи.
Среди поддерживаемых алгоритмов дайджестов сообщений:
-
SHA, SHA1, SHA224, SHA256, SHA384 и SHA512
-
MD2, MD4, MDC2 и MD5
-
RIPEMD160
-
DSS, DSS1 (Псевдоалгоритмы, используемые для подписей DSA. DSS эквивалентен SHA, а DSS1 эквивалентен SHA1)
Для каждого из этих алгоритмов существует подкласс Digest, который можно инициализировать так же просто, как, например,
digest = OpenSSL::Digest::SHA1.new
Сопоставление класса Digest и sn/ln
sn (короткое имя) и ln (полное имя) определены в <openssl/object.h> и <openssl/obj_mac.h>. Это текстовые представления идентификаторов OBJECT ASN.1. Каждый поддерживаемый алгоритм дайджеста имеет связанный с ним идентификатор OBJECT, у которых, в свою очередь, есть короткие/полные имена. Например, идентификатор OBJECT для SHA-1 — 1.3.14.3.2.26, его sn — «SHA1», а ln — «sha1».
MD2
-
sn: MD2
-
ln: md2
MD4
-
sn: MD4
-
ln: md4
MD5
-
sn: MD5
-
ln: md5
SHA
-
sn: SHA
-
ln: SHA
SHA-1
-
sn: SHA1
-
ln: sha1
SHA-224
-
sn: SHA224
-
ln: sha224
SHA-256
-
sn: SHA256
-
ln: sha256
SHA-384
-
sn: SHA384
-
ln: sha384
SHA-512
-
sn: SHA512
-
ln: sha512
«Взлом» алгоритма дайджеста сообщений означает нарушение его характеристик односторонней функции, т.е. получение коллизии или поиск способа получения исходных данных способами, более эффективными, чем перебор и т.д. Большинство поддерживаемых алгоритмов дайджестов сообщений могут считаться взломанными в этом смысле, даже очень популярные алгоритмы MD5 и SHA1. Если безопасность является для вас наивысшим приоритетом, то, вероятно, вам следует полагаться на SHA224, SHA256, SHA384 или SHA512.
Хэширование файла
data = File.read('document')
sha256 = OpenSSL::Digest::SHA256.new
digest = sha256.digest(data)
Хэширование нескольких кусков данных одновременно
data1 = File.read('file1')
data2 = File.read('file2')
data3 = File.read('file3')
sha256 = OpenSSL::Digest::SHA256.new
sha256 << data1
sha256 << data2
sha256 << data3
digest = sha256.digest
Использование экземпляра Digest
data1 = File.read('file1')
sha256 = OpenSSL::Digest::SHA256.new
digest1 = sha256.digest(data1)
data2 = File.read('file2')
sha256.reset
digest2 = sha256.digest(data2)
Публичные методы класса
# File ext/openssl/lib/openssl/digest.rb, line 34 def self.digest(name, data) super(data, name) end
Возвращает data хэш, вычисленный с помощью name Digest. name — это либо полное, либо короткое имя поддерживаемого алгоритма дайджеста.
Примеры
OpenSSL::Digest.digest("SHA256", "abc")
что эквивалентно:
OpenSSL::Digest::SHA256.digest("abc")
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 = GetDigestPtr(type);
if (!NIL_P(data)) StringValue(data);
GetDigest(self, ctx);
if (EVP_DigestInit_ex(ctx, md, NULL) != 1) {
ossl_raise(eDigestError, "Digest initialization failed.");
}
if (!NIL_P(data)) return ossl_digest_update(self, data);
return self;
} Создает экземпляр Digest на основе string, что является либо полным (ln), либо коротким (sn) именем поддерживаемого алгоритма дайджеста. Если data (строка) задано, оно используется в качестве начального входных данных для экземпляра Digest, т.е.
digest = OpenSSL::Digest.new('sha256', 'digestdata')
равно
digest = OpenSSL::Digest.new('sha256')
digest.update('digestdata')
Пример
digest = OpenSSL::Digest.new('sha1')
Публичные методы экземпляра
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::SHA1.new 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::SHA1.new puts digest.digest_length # => 20
static VALUE
ossl_digest_name(VALUE self)
{
EVP_MD_CTX *ctx;
GetDigest(self, ctx);
return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx)));
} Возвращает sn этого экземпляра Digest.
Пример
digest = OpenSSL::Digest::SHA512.new 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_md(ctx), NULL) != 1) {
ossl_raise(eDigestError, "Digest initialization failed.");
}
return self;
} Сбрасывает Digest так, что любые выполненные #update отменяются, и Digest устанавливается в начальное состояние.
VALUE
ossl_digest_update(VALUE self, VALUE data)
{
EVP_MD_CTX *ctx;
StringValue(data);
GetDigest(self, ctx);
EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data));
return self;
} Не каждый дайджест сообщения можно вычислить за один проход. Если дайджест сообщения необходимо вычислить из нескольких последующих источников, то каждый из них может быть передан в экземпляр Digest по отдельности.
Пример
digest = OpenSSL::Digest::SHA256.new
digest.update('First input')
digest << 'Second input' # equivalent to digest.update('Second input')
result = digest.digest
Приватные методы экземпляра
static VALUE
ossl_digest_finish(int argc, VALUE *argv, VALUE self)
{
EVP_MD_CTX *ctx;
VALUE str;
rb_scan_args(argc, argv, "01", &str);
GetDigest(self, ctx);
if (NIL_P(str)) {
str = rb_str_new(NULL, EVP_MD_CTX_size(ctx));
} else {
StringValue(str);
rb_str_resize(str, EVP_MD_CTX_size(ctx));
}
EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL);
return str;
}
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.