Class: OpenSSL::PKey::DH
- Includes:
- Marshal
- Defined in:
- ext/openssl/ossl_pkey_dh.c,
lib/openssl/pkey.rb,
ext/openssl/ossl_pkey_dh.c
Overview
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
Class Method Summary collapse
-
.generate(size, generator = 2, &blk) ⇒ Object
:call-seq: DH.generate(size, generator = 2) -> dh.
-
.new(*args, &blk) ⇒ Object
Handle DH.new(size, generator) form here; new(str) and new() forms are handled by #initialize.
Instance Method Summary collapse
-
#compute_key(pub_bn) ⇒ Object
:call-seq: dh.compute_key(pub_bn) -> string.
-
#export ⇒ Object
(also: #to_pem, #to_s)
Serializes the DH parameters to a PEM-encoding.
-
#generate_key! ⇒ Object
:call-seq: dh.generate_key! -> self.
-
#initialize(*args) ⇒ Object
constructor
Creates a new instance of OpenSSL::PKey::DH.
-
#initialize_copy(other) ⇒ Object
:nodoc:.
-
#params ⇒ Object
:call-seq: dh.params -> hash.
-
#params_ok? ⇒ Boolean
Validates the Diffie-Hellman parameters associated with this instance.
-
#private? ⇒ Boolean
Indicates whether this DH instance has a private key associated with it or not.
-
#public? ⇒ Boolean
Indicates whether this DH instance has a public key associated with it or not.
-
#public_key ⇒ Object
:call-seq: dh.public_key -> dhnew.
-
#set_key(pub_key, priv_key) ⇒ self
Sets pub_key and priv_key for the DH instance.
-
#set_pqg(p, q, g) ⇒ self
Sets p, q, g to the DH instance.
-
#to_der ⇒ aString
Serializes the DH parameters to a DER-encoding.
Methods included from Marshal
Methods inherited from PKey
#compare?, #decrypt, #derive, #encrypt, #inspect, #oid, #private_to_der, #private_to_pem, #public_to_der, #public_to_pem, #raw_private_key, #raw_public_key, #sign, #sign_raw, #to_text, #verify, #verify_raw, #verify_recover
Constructor Details
#new ⇒ Object #new(string) ⇒ Object #new(size[, generator]) ⇒ Object
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). This form is not compatible with OpenSSL 3.0 or later.
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
# Note that this is deprecated and will result in ArgumentError when
# using OpenSSL 3.0 or later.
dh = OpenSSL::PKey::DH.new
dh.set_pqg(bn_p, nil, bn_g)
# Generating a parameters and a key pair
dh = OpenSSL::PKey::DH.new(2048) # An alias of OpenSSL::PKey::DH.generate(2048)
# Reading DH parameters from a PEM-encoded string
dh_params = OpenSSL::PKey::DH.new(File.read('parameters.pem')) # loads parameters only
dh = OpenSSL::PKey.generate_key(dh_params) # generates a key pair
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'ext/openssl/ossl_pkey_dh.c', line 75 static VALUE ossl_dh_initialize(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; int type; DH *dh; BIO *in = NULL; VALUE arg; TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); if (pkey) rb_raise(rb_eTypeError, "pkey already initialized"); /* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */ if (rb_scan_args(argc, argv, "01", &arg) == 0) { #ifdef OSSL_HAVE_IMMUTABLE_PKEY rb_raise(rb_eArgError, "OpenSSL::PKey::DH.new cannot be called " \ "without arguments; pkeys are immutable with OpenSSL 3.0"); #else dh = DH_new(); if (!dh) ossl_raise(ePKeyError, "DH_new"); goto legacy; #endif } arg = ossl_to_der_if_possible(arg); in = ossl_obj2bio(&arg); /* * On OpenSSL <= 1.1.1 and current versions of LibreSSL, the generic * routine does not support DER-encoded parameters */ dh = d2i_DHparams_bio(in, NULL); if (dh) goto legacy; OSSL_BIO_reset(in); pkey = ossl_pkey_read_generic(in, Qnil); BIO_free(in); if (!pkey) ossl_raise(ePKeyError, "could not parse pkey"); type = EVP_PKEY_base_id(pkey); if (type != EVP_PKEY_DH) { EVP_PKEY_free(pkey); rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type)); } RTYPEDDATA_DATA(self) = pkey; return self; legacy: BIO_free(in); pkey = EVP_PKEY_new(); if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) { EVP_PKEY_free(pkey); DH_free(dh); ossl_raise(ePKeyError, "EVP_PKEY_assign_DH"); } RTYPEDDATA_DATA(self) = pkey; return self; } |
Class Method Details
.generate(size, generator = 2, &blk) ⇒ Object
:call-seq:
DH.generate(size, generator = 2) -> dh
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.
133 134 135 136 137 138 139 |
# File 'lib/openssl/pkey.rb', line 133 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(*args, &blk) ⇒ Object
Handle DH.new(size, generator) form here; new(str) and new() forms are handled by #initialize
143 144 145 146 147 148 149 |
# File 'lib/openssl/pkey.rb', line 143 def new(*args, &blk) # :nodoc: if args[0].is_a?(Integer) generate(*args, &blk) else super end end |
Instance Method Details
#compute_key(pub_bn) ⇒ Object
:call-seq:
dh.compute_key(pub_bn) -> string
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
-
pub_bn is a OpenSSL::BN, not the DH instance returned by DH#public_key as that contains the DH parameters only.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/openssl/pkey.rb', line 64 def compute_key(pub_bn) # FIXME: This is constructing an X.509 SubjectPublicKeyInfo and is very # inefficient obj = OpenSSL::ASN1.Sequence([ OpenSSL::ASN1.Sequence([ OpenSSL::ASN1.ObjectId("dhKeyAgreement"), OpenSSL::ASN1.Sequence([ OpenSSL::ASN1.Integer(p), OpenSSL::ASN1.Integer(g), ]), ]), OpenSSL::ASN1.BitString(OpenSSL::ASN1.Integer(pub_bn).to_der), ]) derive(OpenSSL::PKey.read(obj.to_der)) end |
#export ⇒ aString #to_pem ⇒ aString #to_s ⇒ aString Also known as: to_pem, to_s
Serializes the DH parameters to a PEM-encoding.
Note that any existing per-session public/private keys will not get encoded, just the Diffie-Hellman parameters will be encoded.
PEM-encoded parameters will look like:
-----BEGIN DH PARAMETERS-----
[...]
-----END DH PARAMETERS-----
See also #public_to_pem (X.509 SubjectPublicKeyInfo) and #private_to_pem (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) for serialization with the private or public key components.
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'ext/openssl/ossl_pkey_dh.c', line 243 static VALUE ossl_dh_export(VALUE self) { OSSL_3_const DH *dh; BIO *out; VALUE str; GetDH(self, dh); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(ePKeyError, NULL); } if (!PEM_write_bio_DHparams(out, dh)) { BIO_free(out); ossl_raise(ePKeyError, NULL); } str = ossl_membio2str(out); return str; } |
#generate_key! ⇒ Object
:call-seq:
dh.generate_key! -> 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 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.
Deprecated in version 3.0. This method is incompatible with OpenSSL 3.0.0 or later.
See also OpenSSL::PKey.generate_key.
Example:
# DEPRECATED USAGE: This will not work on OpenSSL 3.0 or later
dh0 = OpenSSL::PKey::DH.new(2048)
dh = dh0.public_key # #public_key only copies the DH parameters (contrary to the name)
dh.generate_key!
puts dh.private? # => true
puts dh0.pub_key == dh.pub_key #=> false
# With OpenSSL::PKey.generate_key
dh0 = OpenSSL::PKey::DH.new(2048)
dh = OpenSSL::PKey.generate_key(dh0)
puts dh0.pub_key == dh.pub_key #=> false
106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/openssl/pkey.rb', line 106 def generate_key! if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000 raise PKeyError, "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \ "use OpenSSL::PKey.generate_key instead" end unless priv_key tmp = OpenSSL::PKey.generate_key(self) set_key(tmp.pub_key, tmp.priv_key) end self end |
#initialize_copy(other) ⇒ Object
:nodoc:
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'ext/openssl/ossl_pkey_dh.c', line 140 static VALUE ossl_dh_initialize_copy(VALUE self, VALUE other) { EVP_PKEY *pkey; DH *dh, *dh_other; const BIGNUM *pub, *priv; TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); if (pkey) rb_raise(rb_eTypeError, "pkey already initialized"); GetDH(other, dh_other); dh = DHparams_dup(dh_other); if (!dh) ossl_raise(ePKeyError, "DHparams_dup"); 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(ePKeyError, "BN_dup"); } DH_set0_key(dh, pub2, priv2); } pkey = EVP_PKEY_new(); if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) { EVP_PKEY_free(pkey); DH_free(dh); ossl_raise(ePKeyError, "EVP_PKEY_assign_DH"); } RTYPEDDATA_DATA(self) = pkey; return self; } |
#params ⇒ Object
:call-seq:
dh.params -> hash
Stores all parameters of key to a Hash.
The hash has keys ‘p’, ‘q’, ‘g’, ‘pub_key’, and ‘priv_key’.
46 47 48 49 50 |
# File 'lib/openssl/pkey.rb', line 46 def params %w{p q g pub_key priv_key}.map { |name| [name, send(name)] }.to_h end |
#params_ok? ⇒ Boolean
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).
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'ext/openssl/ossl_pkey_dh.c', line 306 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(ePKeyError, "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? ⇒ Boolean
Indicates whether this DH instance has a private key associated with it or not. The private key may be retrieved with DH#priv_key.
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'ext/openssl/ossl_pkey_dh.c', line 206 static VALUE ossl_dh_is_private(VALUE self) { OSSL_3_const 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 *)dh)) ? Qtrue : Qfalse; #else return bn ? Qtrue : Qfalse; #endif } |
#public? ⇒ Boolean
Indicates whether this DH instance has a public key associated with it or not. The public key may be retrieved with DH#pub_key.
187 188 189 190 191 192 193 194 195 196 197 |
# File 'ext/openssl/ossl_pkey_dh.c', line 187 static VALUE ossl_dh_is_public(VALUE self) { OSSL_3_const DH *dh; const BIGNUM *bn; GetDH(self, dh); DH_get0_key(dh, &bn, NULL); return bn ? Qtrue : Qfalse; } |
#public_key ⇒ Object
:call-seq:
dh.public_key -> dhnew
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
36 37 38 |
# File 'lib/openssl/pkey.rb', line 36 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
Serializes the DH parameters to a DER-encoding
Note that any existing per-session public/private keys will not get encoded, just the Diffie-Hellman parameters will be encoded.
See also #public_to_der (X.509 SubjectPublicKeyInfo) and #private_to_der (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) for serialization with the private or public key components.
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'ext/openssl/ossl_pkey_dh.c', line 276 static VALUE ossl_dh_to_der(VALUE self) { OSSL_3_const DH *dh; unsigned char *p; long len; VALUE str; GetDH(self, dh); if((len = i2d_DHparams(dh, NULL)) <= 0) ossl_raise(ePKeyError, NULL); str = rb_str_new(0, len); p = (unsigned char *)RSTRING_PTR(str); if(i2d_DHparams(dh, &p) < 0) ossl_raise(ePKeyError, NULL); ossl_str_adjust(str, p); return str; } |