класс OpenSSL::PKey::EC
OpenSSL::PKey::EC предоставляет доступ к алгоритму цифровых подписей эллиптических кривых (ECDSA) и алгоритму обмена ключами Диффи-Хеллмана эллиптических кривых (ECDH).
Обмен ключами
ec1 = OpenSSL::PKey::EC.generate("prime256v1")
ec2 = OpenSSL::PKey::EC.generate("prime256v1")
# ec1 and ec2 have own private key respectively
shared_key1 = ec1.dh_compute_key(ec2.public_key)
shared_key2 = ec2.dh_compute_key(ec1.public_key)
p shared_key1 == shared_key2 #=> true
Константы
- EXPLICIT_CURVE
- NAMED_CURVE
Общедоступные методы класса
static VALUE ossl_s_builtin_curves(VALUE self)
{
EC_builtin_curve *curves = NULL;
int n;
int crv_len = rb_long2int(EC_get_builtin_curves(NULL, 0));
VALUE ary, ret;
curves = ALLOCA_N(EC_builtin_curve, crv_len);
if (curves == NULL)
return Qnil;
if (!EC_get_builtin_curves(curves, crv_len))
ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves");
ret = rb_ary_new2(crv_len);
for (n = 0; n < crv_len; n++) {
const char *sname = OBJ_nid2sn(curves[n].nid);
const char *comment = curves[n].comment;
ary = rb_ary_new2(2);
rb_ary_push(ary, rb_str_new2(sname));
rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil);
rb_ary_push(ret, ary);
}
return ret;
} Получает список всех предопределённых кривых библиотекой OpenSSL. Имена кривых возвращаются как sn.
См. документацию OpenSSL по EC_get_builtin_curves().
static VALUE
ossl_ec_key_s_generate(VALUE klass, VALUE arg)
{
EVP_PKEY *pkey;
EC_KEY *ec;
VALUE obj;
obj = rb_obj_alloc(klass);
ec = ec_key_new_from_group(arg);
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
EVP_PKEY_free(pkey);
EC_KEY_free(ec);
ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
}
RTYPEDDATA_DATA(obj) = pkey;
if (!EC_KEY_generate_key(ec))
ossl_raise(eECError, "EC_KEY_generate_key");
return obj;
} Создаёт новый экземпляр EC с новым случайным закрытым и открытым ключом.
static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
EC_KEY *ec;
BIO *in;
VALUE arg, pass;
int type;
TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
if (pkey)
rb_raise(rb_eTypeError, "pkey already initialized");
rb_scan_args(argc, argv, "02", &arg, &pass);
if (NIL_P(arg)) {
if (!(ec = EC_KEY_new()))
ossl_raise(eECError, "EC_KEY_new");
goto legacy;
}
else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
ec = ec_key_new_from_group(arg);
goto legacy;
}
pass = ossl_pem_passwd_value(pass);
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
pkey = ossl_pkey_read_generic(in, pass);
BIO_free(in);
if (!pkey) {
ossl_clear_error();
ec = ec_key_new_from_group(arg);
goto legacy;
}
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_EC) {
EVP_PKEY_free(pkey);
rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
legacy:
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
EVP_PKEY_free(pkey);
EC_KEY_free(ec);
ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
} Создаёт новый объект EC из заданных аргументов.
Общедоступные методы экземпляра
static VALUE ossl_ec_key_check_key(VALUE self)
{
#ifdef HAVE_EVP_PKEY_CHECK
EVP_PKEY *pkey;
EVP_PKEY_CTX *pctx;
const EC_KEY *ec;
GetPKey(self, pkey);
GetEC(self, ec);
pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
if (!pctx)
ossl_raise(eECError, "EVP_PKEY_CTX_new");
if (EC_KEY_get0_private_key(ec) != NULL) {
if (EVP_PKEY_check(pctx) != 1) {
EVP_PKEY_CTX_free(pctx);
ossl_raise(eECError, "EVP_PKEY_check");
}
}
else {
if (EVP_PKEY_public_check(pctx) != 1) {
EVP_PKEY_CTX_free(pctx);
ossl_raise(eECError, "EVP_PKEY_public_check");
}
}
EVP_PKEY_CTX_free(pctx);
#else
EC_KEY *ec;
GetEC(self, ec);
if (EC_KEY_check_key(ec) != 1)
ossl_raise(eECError, "EC_KEY_check_key");
#endif
return Qtrue;
} Вызывает исключение, если ключ недействителен.
См. также страницу руководства EVP_PKEY_public_check(3).
# File ext/openssl/lib/openssl/pkey.rb, line 284
def dh_compute_key(pubkey)
obj = OpenSSL::ASN1.Sequence([
OpenSSL::ASN1.Sequence([
OpenSSL::ASN1.ObjectId("id-ecPublicKey"),
group.to_der,
]),
OpenSSL::ASN1.BitString(pubkey.to_octet_string(:uncompressed)),
])
derive(OpenSSL::PKey.read(obj.to_der))
end Вычисляет общий секрет с помощью ECDH. pubkey должен быть экземпляром OpenSSL::PKey::EC::Point и принадлежать той же группе.
Этот метод предоставляется для обратной совместимости и вызывает derive внутри.
# File ext/openssl/lib/openssl/pkey.rb, line 259 def dsa_sign_asn1(data) sign_raw(nil, data) rescue OpenSSL::PKey::PKeyError raise OpenSSL::PKey::ECError, $!.message end
Устарело в версии 3.0. Вместо этого используйте PKey::PKey#sign_raw и PKey::PKey#verify_raw.
# File ext/openssl/lib/openssl/pkey.rb, line 270 def dsa_verify_asn1(data, sig) verify_raw(nil, sig, data) rescue OpenSSL::PKey::PKeyError raise OpenSSL::PKey::ECError, $!.message end
Устарело в версии 3.0. Вместо этого используйте PKey::PKey#sign_raw и PKey::PKey#verify_raw.
static VALUE
ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
{
OSSL_3_const EC_KEY *ec;
GetEC(self, ec);
if (EC_KEY_get0_public_key(ec) == NULL)
ossl_raise(eECError, "can't export - no public key set");
if (EC_KEY_get0_private_key(ec))
return ossl_pkey_export_traditional(argc, argv, self, 0);
else
return ossl_pkey_export_spki(self, 0);
} Сериализует закрытый или открытый ключ в формате PEM.
- Если ключ содержит только открытые компоненты
-
Сериализует его в X.509 SubjectPublicKeyInfo. Параметры cipher и password игнорируются.
PEM-закодированный ключ будет выглядеть так:
-----BEGIN PUBLIC KEY----- [...] -----END PUBLIC KEY-----
Вместо этого используйте
public_to_pem. Это сериализует ключ в X.509 SubjectPublicKeyInfo независимо от того, является ли он открытым или закрытым ключом. - Если ключ содержит закрытые компоненты и параметры не заданы
-
Сериализует его в SEC 1/RFC 5915 ECPrivateKey.
PEM-закодированный ключ будет выглядеть так:
-----BEGIN EC PRIVATE KEY----- [...] -----END EC PRIVATE KEY-----
- Если ключ содержит закрытые компоненты, и cipher и password заданы
-
Сериализует его в SEC 1/RFC 5915 ECPrivateKey и шифрует его в традиционном формате PEM OpenSSL. cipher должен быть именем шифра, понятным для
OpenSSL::Cipher.newили экземпляромOpenSSL::Cipher.Зашифрованный PEM-закодированный ключ будет выглядеть так:
-----BEGIN EC PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0 [...] -----END EC PRIVATE KEY-----
Обратите внимание, что этот формат использует MD5 для вывода ключа шифрования и, следовательно, не будет доступен в системах, совместимых с FIPS.
Этот метод сохраняется для совместимости. Его следует использовать только тогда, когда требуется формат SEC 1/RFC 5915 ECPrivateKey.
Вместо этого используйте public_to_pem (X.509 SubjectPublicKeyInfo) или private_to_pem (PKCS #8 PrivateKeyInfo или EncryptedPrivateKeyInfo).
static VALUE ossl_ec_key_generate_key(VALUE self)
{
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
GetEC(self, ec);
if (EC_KEY_generate_key(ec) != 1)
ossl_raise(eECError, "EC_KEY_generate_key");
return self;
#endif
} Генерирует новый случайный закрытый и открытый ключ.
См. также документацию OpenSSL для EC_KEY_generate_key()
Пример
ec = OpenSSL::PKey::EC.new("prime256v1")
p ec.private_key # => nil
ec.generate_key!
p ec.private_key # => #<OpenSSL::BN XXXXXX>
static VALUE
ossl_ec_key_get_group(VALUE self)
{
OSSL_3_const EC_KEY *ec;
const EC_GROUP *group;
GetEC(self, ec);
group = EC_KEY_get0_group(ec);
if (!group)
return Qnil;
return ec_group_new(group);
} Возвращает EC::Group, с которым связан ключ. Изменение возвращенной группы не влияет на key.
static VALUE
ossl_ec_key_set_group(VALUE self, VALUE group_v)
{
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
EC_GROUP *group;
GetEC(self, ec);
GetECGroup(group_v, group);
if (EC_KEY_set_group(ec, group) != 1)
ossl_raise(eECError, "EC_KEY_set_group");
return group_v;
#endif
} Устанавливает EC::Group для ключа. Структура группы копируется внутри, поэтому изменения group после присваивания ключу не влияют на ключ.
HAVE_EVP_PKEY_DUP
static VALUE
ossl_ec_key_initialize_copy(VALUE self, VALUE other)
{
EVP_PKEY *pkey;
EC_KEY *ec, *ec_new;
TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
if (pkey)
rb_raise(rb_eTypeError, "pkey already initialized");
GetEC(other, ec);
ec_new = EC_KEY_dup(ec);
if (!ec_new)
ossl_raise(eECError, "EC_KEY_dup");
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec_new) != 1) {
EC_KEY_free(ec_new);
ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
} static VALUE ossl_ec_key_is_private(VALUE self)
{
OSSL_3_const EC_KEY *ec;
GetEC(self, ec);
return EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse;
} Возвращает, содержит ли этот экземпляр EC закрытый ключ. Закрытый ключ (BN) можно получить с помощью EC#private_key.
static VALUE ossl_ec_key_get_private_key(VALUE self)
{
OSSL_3_const EC_KEY *ec;
const BIGNUM *bn;
GetEC(self, ec);
if ((bn = EC_KEY_get0_private_key(ec)) == NULL)
return Qnil;
return ossl_bn_new(bn);
} См. документацию OpenSSL для EC_KEY_get0_private_key()
static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
{
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
BIGNUM *bn = NULL;
GetEC(self, ec);
if (!NIL_P(private_key))
bn = GetBNPtr(private_key);
switch (EC_KEY_set_private_key(ec, bn)) {
case 1:
break;
case 0:
if (bn == NULL)
break;
/* fallthrough */
default:
ossl_raise(eECError, "EC_KEY_set_private_key");
}
return private_key;
#endif
} См. документацию OpenSSL для EC_KEY_set_private_key()
static VALUE ossl_ec_key_is_public(VALUE self)
{
OSSL_3_const EC_KEY *ec;
GetEC(self, ec);
return EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse;
} Возвращает, содержит ли этот экземпляр EC открытый ключ. Открытый ключ (EC::Point) можно получить с помощью EC#public_key.
static VALUE ossl_ec_key_get_public_key(VALUE self)
{
OSSL_3_const EC_KEY *ec;
const EC_POINT *point;
GetEC(self, ec);
if ((point = EC_KEY_get0_public_key(ec)) == NULL)
return Qnil;
return ec_point_new(point, EC_KEY_get0_group(ec));
} См. документацию OpenSSL для EC_KEY_get0_public_key()
static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
{
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
EC_POINT *point = NULL;
GetEC(self, ec);
if (!NIL_P(public_key))
GetECPoint(public_key, point);
switch (EC_KEY_set_public_key(ec, point)) {
case 1:
break;
case 0:
if (point == NULL)
break;
/* fallthrough */
default:
ossl_raise(eECError, "EC_KEY_set_public_key");
}
return public_key;
#endif
} См. документацию OpenSSL для EC_KEY_set_public_key()
static VALUE
ossl_ec_key_to_der(VALUE self)
{
OSSL_3_const EC_KEY *ec;
GetEC(self, ec);
if (EC_KEY_get0_public_key(ec) == NULL)
ossl_raise(eECError, "can't export - no public key set");
if (EC_KEY_get0_private_key(ec))
return ossl_pkey_export_traditional(0, NULL, self, 1);
else
return ossl_pkey_export_spki(self, 1);
} Сериализует закрытый или открытый ключ в кодировке DER.
См. to_pem для подробностей.
Этот метод сохранён для совместимости. Его следует использовать только в случае необходимости формата ECPrivateKey SEC 1/RFC 5915.
Вместо этого рассмотрите использование public_to_der или private_to_der.
Сериализует закрытый или открытый ключ в кодировке PEM.
- Когда ключ содержит только открытые компоненты
-
Сериализует его в X.509 SubjectPublicKeyInfo. Параметры cipher и password игнорируются.
PEM-закодированный ключ будет выглядеть так:
-----BEGIN PUBLIC KEY----- [...] -----END PUBLIC KEY-----
Вместо этого рассмотрите использование
public_to_pem. Это сериализует ключ в X.509 SubjectPublicKeyInfo независимо от того, является ли он открытым или закрытым ключом. - Когда ключ содержит закрытые компоненты и параметры не указаны
-
Сериализует его в SEC 1/RFC 5915 ECPrivateKey.
PEM-закодированный ключ будет выглядеть так:
-----BEGIN EC PRIVATE KEY----- [...] -----END EC PRIVATE KEY-----
- Когда ключ содержит закрытые компоненты, и заданы cipher и password
-
Сериализует его в SEC 1/RFC 5915 ECPrivateKey и шифрует его в традиционном формате шифрования PEM OpenSSL. cipher должен быть именем шифра, понятным
OpenSSL::Cipher.new, или экземпляромOpenSSL::Cipher.Зашифрованный PEM-закодированный ключ будет выглядеть так:
-----BEGIN EC PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0 [...] -----END EC PRIVATE KEY-----
Обратите внимание, что этот формат использует MD5 для вывода ключа шифрования, и поэтому не будет доступен на системах, совместимых с FIPS.
Этот метод сохранён для совместимости. Его следует использовать только в случае необходимости формата ECPrivateKey SEC 1/RFC 5915.
Вместо этого рассмотрите использование public_to_pem (X.509 SubjectPublicKeyInfo) или private_to_pem (PKCS #8 PrivateKeyInfo или EncryptedPrivateKeyInfo).
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.