# class OpenSSL::PKey::EC

`OpenSSL::PKey::EC` provides access to Elliptic Curve Digital Signature Algorithm (ECDSA) and Elliptic Curve Diffie-Hellman (ECDH).

### Key exchange¶ ↑

    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

### Constants

EXPLICIT_CURVE
NAMED_CURVE

### Public Class Methods

builtin_curves → [[sn, comment], ...] click to toggle source

Obtains a list of all predefined curves by the `OpenSSL`. Curve names are returned as sn.

See the `OpenSSL` documentation for 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;
    }

generate(ec_group) → ec click to toggle source
generate(string) → ec

Creates a new `EC` instance with a new random private and public key.

    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;
    }

OpenSSL::PKey::EC.new click to toggle source
OpenSSL::PKey::EC.new(ec_key)
OpenSSL::PKey::EC.new(ec_group)
OpenSSL::PKey::EC.new("secp112r1")
OpenSSL::PKey::EC.new(pem_string [, pwd])
OpenSSL::PKey::EC.new(der_string)

Creates a new `EC` object from given arguments.

    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;
    }

### Public Instance Methods

check_key → true click to toggle source

Raises an exception if the key is invalid.

See also the man page 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;
    }

dh_compute_key(pubkey) → string click to toggle source

Derives a shared secret by ECDH. pubkey must be an instance of `OpenSSL::PKey::EC::Point` and must belong to the same group.

This method is provided for backwards compatibility, and calls `derive` internally.

    # 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

dsa_sign_asn1(data) → String click to toggle source

Deprecated in version 3.0. Consider using `PKey::PKey#sign_raw` and `PKey::PKey#verify_raw` instead.

    # 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

dsa_verify_asn1(data, sig) → true | false click to toggle source

Deprecated in version 3.0. Consider using `PKey::PKey#sign_raw` and `PKey::PKey#verify_raw` instead.

    # 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

export([cipher, pass_phrase]) → String click to toggle source

Outputs the `EC` key in PEM encoding. If cipher and pass_phrase are given they will be used to encrypt the key. cipher must be an `OpenSSL::Cipher` instance. Note that encryption will only be effective for a private key, public keys will always be encoded in plain text.

    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);
    }

Also aliased as: to_pem
generate_key()

Generates a new random private and public key.

See also the `OpenSSL` documentation for EC_KEY_generate_key()

### Example¶ ↑

    ec = OpenSSL::PKey::EC.new("prime256v1")
    p ec.private_key # => nil
    ec.generate_key!
    p ec.private_key # => #<OpenSSL::BN XXXXXX>

Alias for: generate_key!
generate_key! → self click to toggle source

Generates a new random private and public key.

See also the `OpenSSL` documentation for EC_KEY_generate_key()

### Example¶ ↑

    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
    }

Also aliased as: generate_key
group → group click to toggle source

Returns the `EC::Group` that the key is associated with. Modifying the returned group does not affect 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);
    }

group = group click to toggle source

Sets the `EC::Group` for the key. The group structure is internally copied so modification to group after assigning to a key has no effect on the 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
    }

initialize_copy(p1) click to toggle source

    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;
    }

private? → true or false click to toggle source

Returns whether this `EC` instance has a private key. The private key (`BN`) can be retrieved with `EC#private_key`.

    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;
    }

Also aliased as: private_key?
private_key → OpenSSL::BN click to toggle source

See the `OpenSSL` documentation for 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);
    }

private_key = openssl_bn click to toggle source

See the `OpenSSL` documentation for 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
    }

private_key?()

Returns whether this `EC` instance has a private key. The private key (`BN`) can be retrieved with `EC#private_key`.

Alias for: private?
public? → true or false click to toggle source

Returns whether this `EC` instance has a public key. The public key (`EC::Point`) can be retrieved with `EC#public_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;
    }

Also aliased as: public_key?
public_key → OpenSSL::PKey::EC::Point click to toggle source

See the `OpenSSL` documentation for 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));
    }

public_key = ec_point click to toggle source

See the `OpenSSL` documentation for 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
    }

public_key?()

Returns whether this `EC` instance has a public key. The public key (`EC::Point`) can be retrieved with `EC#public_key`.

Alias for: public?
to_der → String click to toggle source

See the `OpenSSL` documentation for i2d_ECPrivateKey_bio()

    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);
    }

to_pem([cipher, pass_phrase]) → String

Outputs the `EC` key in PEM encoding. If cipher and pass_phrase are given they will be used to encrypt the key. cipher must be an `OpenSSL::Cipher` instance. Note that encryption will only be effective for a private key, public keys will always be encoded in plain text.

Alias for: export