On this page
class OpenSSL::PKey::DH
An implementation of the Diffie-Hellman key exchange protocol based on discrete logarithms in finite fields, the same basis that DSA is built on.
Accessor methods for the Diffie-Hellman parameters
- Kernel#p
-
The prime (an OpenSSL::BN) of the Diffie-Hellman parameters.
- DH#g
-
The generator (an OpenSSL::BN) g of the Diffie-Hellman parameters.
- DH#pub_key
-
The per-session public key (an OpenSSL::BN) matching the private key. This needs to be passed to #compute_key.
- DH#priv_key
-
The per-session private key, an OpenSSL::BN.
Example of a key exchange
dh1 = OpenSSL::PKey::DH.new(2048)
der = dh1.public_key.to_der #you may send this publicly to the participating party
dh2 = OpenSSL::PKey::DH.new(der)
dh2.generate_key! #generate the per-session key pair
symm_key1 = dh1.compute_key(dh2.pub_key)
symm_key2 = dh2.compute_key(dh1.pub_key)
puts symm_key1 == symm_key2 # => true
Public Class Methods
static VALUE
ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass)
{
DH *dh ;
int g = 2;
VALUE size, gen, obj;
if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) {
g = NUM2INT(gen);
}
dh = dh_generate(NUM2INT(size), g);
obj = dh_instance(klass, dh);
if (obj == Qfalse) {
DH_free(dh);
ossl_raise(eDHError, NULL);
}
return obj;
}
Creates a new DH instance from scratch by generating the private and public components alike.
Parameters
size
is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure.generator
is a small number > 1, typically 2 or 5.
static VALUE
ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
DH *dh;
int g = 2;
BIO *in;
VALUE arg, gen;
GetPKey(self, pkey);
if(rb_scan_args(argc, argv, "02", &arg, &gen) == 0) {
dh = DH_new();
}
else if (RB_INTEGER_TYPE_P(arg)) {
if (!NIL_P(gen)) {
g = NUM2INT(gen);
}
if (!(dh = dh_generate(NUM2INT(arg), g))) {
ossl_raise(eDHError, NULL);
}
}
else {
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
if (!dh){
OSSL_BIO_reset(in);
dh = d2i_DHparams_bio(in, NULL);
}
BIO_free(in);
if (!dh) {
ossl_raise(eDHError, NULL);
}
}
if (!EVP_PKEY_assign_DH(pkey, dh)) {
DH_free(dh);
ossl_raise(eDHError, NULL);
}
return self;
}
Either generates a DH instance from scratch or by reading already existing DH parameters from string
. Note that when reading a DH instance from data that was encoded from a DH instance by using #to_pem or #to_der the result will not contain a public/private key pair yet. This needs to be generated using #generate_key! first.
Parameters
size
is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure.generator
is a small number > 1, typically 2 or 5.string
contains the DER or PEM encoded key.
Examples
DH.new # -> dh
DH.new(1024) # -> dh
DH.new(1024, 5) # -> dh
#Reading DH parameters
dh = DH.new(File.read('parameters.pem')) # -> dh, but no public/private key yet
dh.generate_key! # -> dh with public and private key
Public Instance Methods
static VALUE
ossl_dh_compute_key(VALUE self, VALUE pub)
{
DH *dh;
const BIGNUM *pub_key, *dh_p;
VALUE str;
int len;
GetDH(self, dh);
DH_get0_pqg(dh, &dh_p, NULL, NULL);
if (!dh_p)
ossl_raise(eDHError, "incomplete DH");
pub_key = GetBNPtr(pub);
len = DH_size(dh);
str = rb_str_new(0, len);
if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) {
ossl_raise(eDHError, NULL);
}
rb_str_set_len(str, len);
return str;
}
Returns a String containing a shared secret computed from the other party's public value. See DH_compute_key() for further information.
Parameters
pub_bn
is a OpenSSL::BN, not the DH instance returned by #public_key as that contains the DH parameters only.
static VALUE
ossl_dh_export(VALUE self)
{
DH *dh;
BIO *out;
VALUE str;
GetDH(self, dh);
if (!(out = BIO_new(BIO_s_mem()))) {
ossl_raise(eDHError, NULL);
}
if (!PEM_write_bio_DHparams(out, dh)) {
BIO_free(out);
ossl_raise(eDHError, NULL);
}
str = ossl_membio2str(out);
return str;
}
Encodes this DH to its PEM encoding. Note that any existing per-session public/private keys will not get encoded, just the Diffie-Hellman parameters will be encoded.
static VALUE
ossl_dh_generate_key(VALUE self)
{
DH *dh;
GetDH(self, dh);
if (!DH_generate_key(dh))
ossl_raise(eDHError, "Failed to generate key");
return self;
}
Generates a private and public key unless a private key already exists. If this DH instance was generated from public DH parameters (e.g. by encoding the result of #public_key), then this method needs to be called first in order to generate the per-session keys before performing the actual key exchange.
Example
dh = OpenSSL::PKey::DH.new(2048)
public_key = dh.public_key #contains no private/public key yet
public_key.generate_key!
puts public_key.private? # => true
static VALUE
ossl_dh_get_params(VALUE self)
{
DH *dh;
VALUE hash;
const BIGNUM *p, *q, *g, *pub_key, *priv_key;
GetDH(self, dh);
DH_get0_pqg(dh, &p, &q, &g);
DH_get0_key(dh, &pub_key, &priv_key);
hash = rb_hash_new();
rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(p));
rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(q));
rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(g));
rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pub_key));
rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(priv_key));
return hash;
}
Stores all parameters of key to the hash INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! Don't use :-)) (I's up to you)
static VALUE
ossl_dh_check_params(VALUE self)
{
DH *dh;
int codes;
GetDH(self, dh);
if (!DH_check(dh, &codes)) {
return Qfalse;
}
return codes == 0 ? Qtrue : Qfalse;
}
Validates the Diffie-Hellman parameters associated with this instance. It checks whether a safe prime and a suitable generator are used. If this is not the case, false
is returned.
static VALUE
ossl_dh_is_private(VALUE self)
{
DH *dh;
const BIGNUM *bn;
GetDH(self, dh);
DH_get0_key(dh, NULL, &bn);
#if !defined(OPENSSL_NO_ENGINE)
return (bn || DH_get0_engine(dh)) ? Qtrue : Qfalse;
#else
return bn ? Qtrue : Qfalse;
#endif
}
Indicates whether this DH instance has a private key associated with it or not. The private key may be retrieved with DH#priv_key.
static VALUE
ossl_dh_is_public(VALUE self)
{
DH *dh;
const BIGNUM *bn;
GetDH(self, dh);
DH_get0_key(dh, &bn, NULL);
return bn ? Qtrue : Qfalse;
}
Indicates whether this DH instance has a public key associated with it or not. The public key may be retrieved with DH#pub_key.
static VALUE
ossl_dh_to_public_key(VALUE self)
{
DH *orig_dh, *dh;
VALUE obj;
GetDH(self, orig_dh);
dh = DHparams_dup(orig_dh); /* err check perfomed by dh_instance */
obj = dh_instance(rb_obj_class(self), dh);
if (obj == Qfalse) {
DH_free(dh);
ossl_raise(eDHError, NULL);
}
return obj;
}
Returns a new DH instance that carries just the public information, i.e. the prime p
and the generator g
, but no public/private key yet. Such a pair may be generated using #generate_key!. The “public key” needed for a key exchange with #compute_key is considered as per-session information and may be retrieved with DH#pub_key once a key pair has been generated. If the current instance already contains private information (and thus a valid public/private key pair), this information will no longer be present in the new instance generated by #public_key. This feature is helpful for publishing the Diffie-Hellman parameters without leaking any of the private per-session information.
Example
dh = OpenSSL::PKey::DH.new(2048) # has public and private key set
public_key = dh.public_key # contains only prime and generator
parameters = public_key.to_der # it's safe to publish this
Sets pub_key
and priv_key
for the DH instance. priv_key
may be nil.
Sets p
, q
, g
for the DH instance.
static VALUE
ossl_dh_to_der(VALUE self)
{
DH *dh;
unsigned char *p;
long len;
VALUE str;
GetDH(self, dh);
if((len = i2d_DHparams(dh, NULL)) <= 0)
ossl_raise(eDHError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_DHparams(dh, &p) < 0)
ossl_raise(eDHError, NULL);
ossl_str_adjust(str, p);
return str;
}
Encodes this DH to its DER encoding. Note that any existing per-session public/private keys will not get encoded, just the Diffie-Hellman parameters will be encoded.
static VALUE
ossl_dh_to_text(VALUE self)
{
DH *dh;
BIO *out;
VALUE str;
GetDH(self, dh);
if (!(out = BIO_new(BIO_s_mem()))) {
ossl_raise(eDHError, NULL);
}
if (!DHparams_print(out, dh)) {
BIO_free(out);
ossl_raise(eDHError, NULL);
}
str = ossl_membio2str(out);
return str;
}
Prints all parameters of key to buffer INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! Don't use :-)) (I's up to you)
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.