类 OpenSSL::PKey::EC
OpenSSL::PKey::EC
提供对椭圆曲线数字签名算法 (ECDSA) 和椭圆曲线 Diffie-Hellman (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
公共类方法
获取 OpenSSL
中所有预定义曲线的列表。曲线名称以 sn 返回。
请参阅 OpenSSL
文档以了解 EC_get_builtin_curves()。
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; }
创建一个新的 EC
实例,其中包含新的随机私钥和公钥。
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; }
公共实例方法
如果密钥无效,则引发异常。
另请参阅手册页 EVP_PKEY_public_check(3)。
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; }
通过 ECDH 推导出共享密钥。pubkey 必须是 OpenSSL::PKey::EC::Point
的实例,并且必须属于同一组。
此方法是为了向后兼容而提供的,它在内部调用 derive
。
# 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
在版本 3.0 中已弃用。请考虑使用 PKey::PKey#sign_raw
和 PKey::PKey#verify_raw
代替。
# 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
将私钥或公钥序列化为 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,并在 OpenSSL 的传统 PEM 加密格式中对其进行加密。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_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); }
生成新的随机私钥和公钥。
另请参阅 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_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 }
返回与密钥关联的 EC::Group
。修改返回的组不会影响 key。
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
。组结构在内部复制,因此在分配给密钥后对 group 的修改不会影响密钥。
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 }
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; }
返回此 EC
实例是否具有私钥。可以使用 EC#private_key
获取私钥 (BN
)。
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; }
请参阅 OpenSSL
文档以了解 EC_KEY_get0_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_set_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 }
返回此 EC
实例是否具有公钥。可以使用 EC#public_key
获取公钥 (EC::Point
)。
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; }
请参阅 OpenSSL
文档以了解 EC_KEY_get0_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_set_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 }
将私钥或公钥序列化为 DER 编码。
有关详细信息,请参阅 to_pem
。
此方法保留用于兼容性。 这仅应在需要 SEC 1/RFC 5915 ECPrivateKey 格式时使用。
请考虑使用 public_to_der
或 private_to_der
代替。
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); }
将私钥或公钥序列化为 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,并在 OpenSSL 的传统 PEM 加密格式中对其进行加密。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) 代替。