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

DH#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 DH#compute_key.

DH#priv_key

The per-session private key, an OpenSSL::BN.

Example of a key exchange

# you may send the parameters (der) and own public key (pub1) publicly
# to the participating party
dh1 = OpenSSL::PKey::DH.new(2048)
der = dh1.to_der
pub1 = dh1.pub_key

# the other party generates its per-session key pair
dhparams = OpenSSL::PKey::DH.new(der)
dh2 = OpenSSL::PKey.generate_key(dhparams)
pub2 = dh2.pub_key

symm_key1 = dh1.compute_key(pub2)
symm_key2 = dh2.compute_key(pub1)
puts symm_key1 == symm_key2 # => true

Public Class Methods

generate(size, generator = 2) → dh click to toggle source

Creates a new DH instance from scratch by generating random parameters and a key pair.

See also OpenSSL::PKey.generate_parameters and OpenSSL::PKey.generate_key.

size

The desired key size in bits.

generator

The generator.

# File ext/openssl/lib/openssl/pkey.rb, line 93
def generate(size, generator = 2, &blk)
  dhparams = OpenSSL::PKey.generate_parameters("DH", {
    "dh_paramgen_prime_len" => size,
    "dh_paramgen_generator" => generator,
  }, &blk)
  OpenSSL::PKey.generate_key(dhparams)
end
new → dh click to toggle source
new(string) → dh
new(size [, generator]) → dh

Creates a new instance of OpenSSL::PKey::DH.

If called without arguments, an empty instance without any parameter or key components is created. Use set_pqg to manually set the parameters afterwards (and optionally set_key to set private and public key components).

If a String is given, tries to parse it as a DER- or PEM- encoded parameters. See also OpenSSL::PKey.read which can parse keys of any kinds.

The DH.new(size [, generator]) form is an alias of DH.generate.

string

A String that contains the DER or PEM encoded key.

size

See DH.generate.

generator

See DH.generate.

Examples:

# Creating an instance from scratch
dh = DH.new
dh.set_pqg(bn_p, nil, bn_g)

# Generating a parameters and a key pair
dh = DH.new(2048) # An alias of DH.generate(2048)

# 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
static VALUE
ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    DH *dh;
    BIO *in;
    VALUE arg;

    GetPKey(self, pkey);
    /* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */
    if (rb_scan_args(argc, argv, "01", &arg) == 0) {
        dh = DH_new();
        if (!dh)
            ossl_raise(eDHError, "DH_new");
    }
    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;
}

Public Instance Methods

compute_key(pub_bn) → string click to toggle source

Returns a String containing a shared secret computed from the other party's public value.

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

Parameters

# File ext/openssl/lib/openssl/pkey.rb, line 49
def compute_key(pub_bn)
  peer = dup
  peer.set_key(pub_bn, nil)
  derive(peer)
end
export → aString click to toggle source

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_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;
}
Also aliased as: to_pem, to_s
generate_key! → self click to toggle source

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 DH#public_key), then this method needs to be called first in order to generate the per-session keys before performing the actual key exchange.

See also OpenSSL::PKey.generate_key.

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
# File ext/openssl/lib/openssl/pkey.rb, line 71
def generate_key!
  unless priv_key
    tmp = OpenSSL::PKey.generate_key(self)
    set_key(tmp.pub_key, tmp.priv_key)
  end
  self
end
initialize_copy(p1) click to toggle source
static VALUE
ossl_dh_initialize_copy(VALUE self, VALUE other)
{
    EVP_PKEY *pkey;
    DH *dh, *dh_other;
    const BIGNUM *pub, *priv;

    GetPKey(self, pkey);
    if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
        ossl_raise(eDHError, "DH already initialized");
    GetDH(other, dh_other);

    dh = DHparams_dup(dh_other);
    if (!dh)
        ossl_raise(eDHError, "DHparams_dup");
    EVP_PKEY_assign_DH(pkey, dh);

    DH_get0_key(dh_other, &pub, &priv);
    if (pub) {
        BIGNUM *pub2 = BN_dup(pub);
        BIGNUM *priv2 = BN_dup(priv);

        if (!pub2 || (priv && !priv2)) {
            BN_clear_free(pub2);
            BN_clear_free(priv2);
            ossl_raise(eDHError, "BN_dup");
        }
        DH_set0_key(dh, pub2, priv2);
    }

    return self;
}
params → hash click to toggle source

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_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;
}
params_ok? → true | false click to toggle source

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.

See also the man page EVP_PKEY_param_check(3).

static VALUE
ossl_dh_check_params(VALUE self)
{
    int ret;
#ifdef HAVE_EVP_PKEY_CHECK
    EVP_PKEY *pkey;
    EVP_PKEY_CTX *pctx;

    GetPKey(self, pkey);
    pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
    if (!pctx)
        ossl_raise(eDHError, "EVP_PKEY_CTX_new");
    ret = EVP_PKEY_param_check(pctx);
    EVP_PKEY_CTX_free(pctx);
#else
    DH *dh;
    int codes;

    GetDH(self, dh);
    ret = DH_check(dh, &codes) == 1 && codes == 0;
#endif

    if (ret == 1)
        return Qtrue;
    else {
        /* DH_check_ex() will put error entry on failure */
        ossl_clear_error();
        return Qfalse;
    }
}
private? → true | false click to toggle source

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_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
}
public? → true | false click to toggle source

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_is_public(VALUE self)
{
    DH *dh;
    const BIGNUM *bn;

    GetDH(self, dh);
    DH_get0_key(dh, &bn, NULL);

    return bn ? Qtrue : Qfalse;
}
public_key → dhnew click to toggle source

Returns a new DH instance that carries just the DH parameters.

Contrary to the method name, the returned DH object contains only parameters and not the public key.

This method is provided for backwards compatibility. In most cases, there is no need to call this method.

For the purpose of re-generating the key pair while keeping the parameters, check OpenSSL::PKey.generate_key.

Example:

# OpenSSL::PKey::DH.generate by default generates a random key pair
dh1 = OpenSSL::PKey::DH.generate(2048)
p dh1.priv_key #=> #<OpenSSL::BN 1288347...>
dhcopy = dh1.public_key
p dhcopy.priv_key #=> nil
# File ext/openssl/lib/openssl/pkey.rb, line 33
def public_key
  DH.new(to_der)
end
set_key(pub_key, priv_key) → self

Sets pub_key and priv_key for the DH instance. priv_key may be nil.

set_pqg(p, q, g) → self

Sets p, q, g to the DH instance.

to_der → aString click to toggle source

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_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;
}
to_pem → aString

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.

Alias for: export
to_s → aString

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.

Alias for: export