модуль OpenSSL::PKey
Алгоритмы асимметричного открытого ключа
Алгоритмы асимметричного открытого ключа решают задачу создания и совместного использования секретных ключей для шифрования и расшифрования сообщений. Ключ в таком алгоритме состоит из двух частей: открытого ключа, который можно распространять, и закрытого ключа, который необходимо хранить в секрете.
Сообщения, зашифрованные открытым ключом, могут расшифровать только получатели, владеющие соответствующим закрытым ключом. Поскольку алгоритмы с открытым ключом значительно медленнее алгоритмов с симметричным ключом (ср. OpenSSL::Cipher), их часто используют для создания симметричного ключа, совместно используемого двумя сторонами, владеющими открытыми ключами друг друга.
Асимметричные алгоритмы предлагают множество полезных возможностей, применяемых в самых разных областях. Очень распространённый вариант использования — создание и проверка цифровых подписей. Для подписания документа подписывающая сторона обычно использует алгоритм хеширования сообщения (ср. OpenSSL::Digest), чтобы вычислить хеш документа, который затем шифруется (то есть подписывается) с помощью закрытого ключа. Любой владелец открытого ключа может проверить подпись: самостоятельно вычислить хеш исходного документа, расшифровать подпись с помощью открытого ключа подписавшей стороны и сравнить результат с ранее вычисленным хешем. Подпись действительна тогда и только тогда, когда расшифрованная подпись совпадает с этим хешем.
Модуль PKey поддерживает три популярных алгоритма с открытым и закрытым ключами:
-
Криптография на эллиптических кривых (
OpenSSL::PKey::EC)
Каждая из этих реализаций фактически является подклассом абстрактного класса PKey, предоставляющего интерфейс для поддержки цифровых подписей в виде методов PKey#sign и PKey#verify.
Обмен ключами Диффи — Хеллмана
Наконец, PKey также поддерживает OpenSSL::PKey::DH — реализацию протокола обмена ключами Диффи — Хеллмана, основанного на дискретном логарифмировании в конечных полях; на той же основе построен DSA. Протокол Диффи — Хеллмана можно использовать для обмена (симметричными) ключами по небезопасным каналам, не требуя предварительного наличия общих секретных данных у взаимодействующих сторон. Поскольку для обеспечения безопасности DH требуются относительно длинные «открытые ключи» (то есть данные, передаваемые между участниками в открытом виде), DH работает довольно медленно. Если для вас важнее безопасность или скорость, OpenSSL::PKey::EC предлагает другую реализацию протокола Диффи — Хеллмана.
Публичные методы класса
static VALUE
ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
{
return pkey_generate(argc, argv, self, 0);
} Создаёт новую пару ключей.
Если первым аргументом передана String, создаётся новый случайный ключ для алгоритма, заданного этим именем, так же, как это делает ::generate_parameters. Если вместо этого передан OpenSSL::PKey::PKey, создаётся новый случайный ключ для того же алгоритма, что и у этого ключа, с использованием содержащихся в нём параметров.
Подробную информацию о options и передаваемом блоке см. в разделе ::generate_parameters.
Пример
pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
pkey_params.priv_key #=> nil
pkey = OpenSSL::PKey.generate_key(pkey_params)
pkey.priv_key #=> #<OpenSSL::BN 6277...
static VALUE
ossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self)
{
return pkey_generate(argc, argv, self, 1);
} Создаёт новые параметры для алгоритма. algo_name — это String, задающая алгоритм. Необязательный аргумент options — это Hash, задающий параметры, специфичные для алгоритма. Порядок параметров может иметь значение.
Можно также передать блок. Значение аргументов, передаваемых блоку, зависит от реализации алгоритма. Блок может вызываться один или несколько раз либо не вызываться вовсе.
Сведения о поддерживаемых параметрах см. в документации по служебной команде «openssl genpkey».
Пример
pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
p pkey.p.num_bits #=> 2048
static VALUE
ossl_pkey_new_raw_private_key(VALUE self, VALUE type, VALUE key)
{
EVP_PKEY *pkey;
const EVP_PKEY_ASN1_METHOD *ameth;
int pkey_id;
size_t keylen;
StringValue(type);
StringValue(key);
ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
if (!ameth)
ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
keylen = RSTRING_LEN(key);
pkey = EVP_PKEY_new_raw_private_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
if (!pkey)
ossl_raise(ePKeyError, "EVP_PKEY_new_raw_private_key");
return ossl_pkey_new(pkey);
} См. документацию OpenSSL для EVP_PKEY_new_raw_private_key()
static VALUE
ossl_pkey_new_raw_public_key(VALUE self, VALUE type, VALUE key)
{
EVP_PKEY *pkey;
const EVP_PKEY_ASN1_METHOD *ameth;
int pkey_id;
size_t keylen;
StringValue(type);
StringValue(key);
ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
if (!ameth)
ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
keylen = RSTRING_LEN(key);
pkey = EVP_PKEY_new_raw_public_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
if (!pkey)
ossl_raise(ePKeyError, "EVP_PKEY_new_raw_public_key");
return ossl_pkey_new(pkey);
} См. документацию OpenSSL для EVP_PKEY_new_raw_public_key()
static VALUE
ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
BIO *bio;
VALUE data, pass;
rb_scan_args(argc, argv, "11", &data, &pass);
bio = ossl_obj2bio(&data);
pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));
BIO_free(bio);
if (!pkey)
ossl_raise(ePKeyError, "Could not parse PKey");
return ossl_pkey_new(pkey);
} Читает строку в формате DER или PEM из string либо io и возвращает экземпляр соответствующего класса PKey.
Параметры
-
string — строка в формате DER или PEM, содержащая произвольный закрытый или открытый ключ.
-
io — экземпляр
IO, содержащий произвольный закрытый или открытый ключ в формате DER или PEM. -
pwd — необязательный пароль на случай, если string или io содержит зашифрованные данные PEM.
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.