OpenSSL::PKey::EC
provides access to Elliptic Curve Digital Signature Algorithm (ECDSA) and Elliptic Curve 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
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; }
Creates a new EC
instance with a new random private and public key.
static VALUE ossl_ec_key_s_generate(VALUE klass, VALUE arg) { EC_KEY *ec; VALUE obj; ec = ec_key_new_from_group(arg); obj = ec_instance(klass, ec); if (obj == Qfalse) { EC_KEY_free(ec); ossl_raise(eECError, NULL); } if (!EC_KEY_generate_key(ec)) ossl_raise(eECError, "EC_KEY_generate_key"); return obj; }
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; VALUE arg, pass; GetPKey(self, pkey); if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) ossl_raise(eECError, "EC_KEY already initialized"); rb_scan_args(argc, argv, "02", &arg, &pass); if (NIL_P(arg)) { if (!(ec = EC_KEY_new())) ossl_raise(eECError, NULL); } else if (rb_obj_is_kind_of(arg, cEC)) { EC_KEY *other_ec = NULL; GetEC(arg, other_ec); if (!(ec = EC_KEY_dup(other_ec))) ossl_raise(eECError, NULL); } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { ec = ec_key_new_from_group(arg); } else { BIO *in; pass = ossl_pem_passwd_value(pass); in = ossl_obj2bio(&arg); ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); if (!ec) { OSSL_BIO_reset(in); ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, (void *)pass); } if (!ec) { OSSL_BIO_reset(in); ec = d2i_ECPrivateKey_bio(in, NULL); } if (!ec) { OSSL_BIO_reset(in); ec = d2i_EC_PUBKEY_bio(in, NULL); } BIO_free(in); if (!ec) { ossl_clear_error(); ec = ec_key_new_from_group(arg); } } if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { EC_KEY_free(ec); ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); } return self; }
Raises an exception if the key is invalid.
See the OpenSSL
documentation for EC_KEY_check_key()
static VALUE ossl_ec_key_check_key(VALUE self) { EC_KEY *ec; GetEC(self, ec); if (EC_KEY_check_key(ec) != 1) ossl_raise(eECError, "EC_KEY_check_key"); return Qtrue; }
See the OpenSSL
documentation for ECDH_compute_key()
static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey) { EC_KEY *ec; EC_POINT *point; int buf_len; VALUE str; GetEC(self, ec); GetECPoint(pubkey, point); /* BUG: need a way to figure out the maximum string size */ buf_len = 1024; str = rb_str_new(0, buf_len); /* BUG: take KDF as a block */ buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL); if (buf_len < 0) ossl_raise(eECError, "ECDH_compute_key"); rb_str_resize(str, buf_len); return str; }
See the OpenSSL
documentation for ECDSA_sign()
static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data) { EC_KEY *ec; unsigned int buf_len; VALUE str; GetEC(self, ec); StringValue(data); if (EC_KEY_get0_private_key(ec) == NULL) ossl_raise(eECError, "Private EC key needed!"); str = rb_str_new(0, ECDSA_size(ec)); if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1) ossl_raise(eECError, "ECDSA_sign"); rb_str_set_len(str, buf_len); return str; }
See the OpenSSL
documentation for ECDSA_verify()
static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig) { EC_KEY *ec; GetEC(self, ec); StringValue(data); StringValue(sig); switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(sig), (int)RSTRING_LEN(sig), ec)) { case 1: return Qtrue; case 0: return Qfalse; default: break; } ossl_raise(eECError, "ECDSA_verify"); UNREACHABLE; }
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) { VALUE cipher, passwd; rb_scan_args(argc, argv, "02", &cipher, &passwd); return ossl_ec_key_to_string(self, cipher, passwd, EXPORT_PEM); }
Generates a new random private and public key.
See also the OpenSSL
documentation for 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) { EC_KEY *ec; GetEC(self, ec); if (EC_KEY_generate_key(ec) != 1) ossl_raise(eECError, "EC_KEY_generate_key"); return self; }
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) { 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); }
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) { 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; }
static VALUE ossl_ec_key_initialize_copy(VALUE self, VALUE other) { EVP_PKEY *pkey; EC_KEY *ec, *ec_new; GetPKey(self, pkey); if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE) ossl_raise(eECError, "EC already initialized"); GetEC(other, ec); ec_new = EC_KEY_dup(ec); if (!ec_new) ossl_raise(eECError, "EC_KEY_dup"); if (!EVP_PKEY_assign_EC_KEY(pkey, ec_new)) { EC_KEY_free(ec_new); ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); } return self; }
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) { EC_KEY *ec; GetEC(self, ec); return EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse; }
See the OpenSSL
documentation for EC_KEY_get0_private_key()
static VALUE ossl_ec_key_get_private_key(VALUE self) { 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); }
See the OpenSSL
documentation for EC_KEY_set_private_key()
static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key) { 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; default: ossl_raise(eECError, "EC_KEY_set_private_key"); } return private_key; }
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) { EC_KEY *ec; GetEC(self, ec); return EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse; }
See the OpenSSL
documentation for EC_KEY_get0_public_key()
static VALUE ossl_ec_key_get_public_key(VALUE self) { 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)); }
See the OpenSSL
documentation for EC_KEY_set_public_key()
static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key) { 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; default: ossl_raise(eECError, "EC_KEY_set_public_key"); } return public_key; }
See the OpenSSL
documentation for i2d_ECPrivateKey_bio()
static VALUE ossl_ec_key_to_der(VALUE self) { return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER); }
See the OpenSSL
documentation for EC_KEY_print()
static VALUE ossl_ec_key_to_text(VALUE self) { EC_KEY *ec; BIO *out; VALUE str; GetEC(self, ec); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eECError, "BIO_new(BIO_s_mem())"); } if (!EC_KEY_print(out, ec, 0)) { BIO_free(out); ossl_raise(eECError, "EC_KEY_print"); } str = ossl_membio2str(out); return str; }