OpenSSL ECDSA public key from private

Hi,

Could anybody please tell me how can I generate a public key from
a private one with OpenSSL (or any other lib/gem) in Ruby? What I’m
trying to do is something like this:

irb(main):001:0> require ‘openssl’
=> true

irb(main):002:0> key = OpenSSL::PKey::EC.new ‘secp256k1’
=> #OpenSSL::PKey::EC:0x7f685ae68420

irb(main):003:0> key.private_key = …
=> …

irb(main):004:0> key.public_key?
=> false

irb(main):005:0> key.public_key
=> nil

Setting the private_key works fine, but I need to calculate the
public_key
too.
I’m sure there’s a way to ask the key object to calculate the
corresponding
public key, I just don’t know how.

u.

Thanks Carlo, but it’s not what I was looking for. I know about
#generate_key.
It creates a random private key and calculates the corresponding public
key
too. But I already have a (non-random) private key. (I mean it is an
input
for my script.)

Now what I need is to set my own private key, and calculate the public
key
that matches my already existing private key. I have a private key
which is
not a random number. Well, maybe it was some time ago in another
software,
but for now, I can read it from a file, and I have no problem setting
that
data as a private key. The problem is that I need the public key that
matches the private one.

So what I need is to ask the ‘key’ object to be so kind and calculate
the
the
public key for me using my private key I’ve just set with #private_key=.

key.private_key =
*
*
key.plese_calculate_the_public_key_from_the_private_one!

u.

Subject: OpenSSL ECDSA public key from private
Date: Sun 28 Oct 12 03:28:36AM +0900

Quoting Nokan E. ([email protected]):

Setting the private_key works fine, but I need to calculate the public_key
too.
I’m sure there’s a way to ask the key object to calculate the corresponding
public key, I just don’t know how.

I have never done this myself before , but I was curious, and gave it
a look.

Your OpenSSL::PKey::EC instance has a method called
#generate_key. After I run

key.generate_key

I find that key.private_key is populated with an instance of
OpenSSL::BN, and key.public_key is populated with an instance of
OpenSSL::PKey::EC::Point.

I hope this is what you were looking for.

Carlo

Subject: Re: OpenSSL ECDSA public key from private
Date: Sun 28 Oct 12 04:23:52AM +0900

Quoting Nokan E. ([email protected]):

So what I need is to ask the ‘key’ object to be so kind and calculate the
the
public key for me using my private key I’ve just set with #private_key=.

key.private_key =
*
*
key.plese_calculate_the_public_key_from_the_private_one!

I had a look at the ruby code. #generate_key just calls openssl
function “EC_KEY_generate_key”. From
openssl.sourcearchive.com, I see
that, within that function, the public key is generated with

  if (eckey->pub_key == NULL)
        {
        pub_key = EC_POINT_new(eckey->group);
        if (pub_key == NULL)
              goto err;
        }

EC_POINT_new is used within Ruby when creating an
OpenSSL::PKey::EC::Point object, when passing it a ‘group’. Now, I
have no idea what a group is, but your key has a ‘group’. And it is
populated, even without calling #generate_key.

If I run

pub_key=OpenSSL::PKey::EC::Point.new(key.group)

I get something. Again, I hope this is what you are looking for.

Carlo

Nokan E. [email protected] wrote:

Could anybody please tell me how can I generate a public key from
a private one with OpenSSL (or any other lib/gem) in Ruby?

I haven’t looked into how to do this in Ruby, but at least with the
command-line stuff from OpenSSL it seems to be trivial. (That’s quite
contrary to my initial assumptions. I was all set to tell you “no,
the whole point is that you can’t derive one from the other”, and was
fact-checking. Apparently asymmetrical crypto is even more
asymmetrical than I thought!) Check out the answers to this question
on SO:

.net - Given a private key, is it possible to derive its public key? - Stack Overflow

-Dave

I haven’t looked into how to do this in Ruby, but at least with the

command-line stuff from OpenSSL it seems to be trivial. (That’s quite
contrary to my initial assumptions. I was all set to tell you “no,
the whole point is that you can’t derive one from the other”, and was
fact-checking. Apparently asymmetrical crypto is even more
asymmetrical than I thought!) Check out the answers to this question
on SO:

Well, this is about RSA, not Elliptic Curve crypto (ECDSA), but the
main thing is all the same: it should be easy to calculate the public
key from the private key, but it must be virtually impossible to do it
the other way. The private key is just a huge random number that is
kept secret, and the public key is calculated from it somehow – we
actually don’t need to know how, that’s something OpenSSL does
internally.

I think the Ruby API just misses a very important piece here. :frowning:

Subject: Re: OpenSSL ECDSA public key from private
Date: Sun 28 Oct 12 05:59:21AM +0900

Quoting Nokan E. ([email protected]):

…I think EC_POINT_mul() could be a solution. It’s a C function
in OpenSSL, and it does the calculation I need. But I don’t know
much about how Ruby and C are married in native gems, and
I think the Ruby API does not allow me to call this C function. :frowning:

Or does it?

These mappings are generally done with quite a lot of care. Indeed,
you can call EC_POINT_mul() - the OpenSSL::PKey::EC::Point class has a
#mul method.

It can be called in four ways:

point.mul(bn) => point
point.mul(bn, bn) => point
point.mul([bn], [point]) => point
point.mul([bn], [point], bn) => point

The EC_POINT_mul function is called if you pass one or two OpenSSL::BN
objects to it.

If I execute this script:

require ‘openssl’
key=OpenSSL::PKey::EC.new(‘secp256k1’)
bn1=OpenSSL::BN::new(‘123’)
bn2=OpenSSL::BN::new(‘456’)
pubkey=OpenSSL::PKey::EC::Point.new(key.group).mul(bn1,bn2)
p pubkey.to_bn.to_s

I get a beautiful 155-digit number. Then, I have no idea about what
all these big numbers should be…

The Openssl mapping is included in Matz’s Ruby sources, under
ext/openssl.

Carlo

Much better, but it’s still not finished… :wink:

I had a look at the ruby code. #generate_key just calls openssl

Thanks for looking at the source. I guess this is just the creation
(memory allocation?) of the point object (yes, the public key is a
point with X and Y coordinates in Elliptic Curve crypto), but the
calculation of this point using the private key (which is a number,
not a point) must be somewhere in the next few lines in the source.

As far as I can see this creates a point with (0, 0) coordinates.
(The .to_bn converts a point to an OpenSSL::BN, which is a
Big Number, where (I think) the first N bit belongs to the X
coordinate and the other bits to the Y, but to_bn answers 0.)

According to this…

…I think EC_POINT_mul() could be a solution. It’s a C function
in OpenSSL, and it does the calculation I need. But I don’t know
much about how Ruby and C are married in native gems, and
I think the Ruby API does not allow me to call this C function. :frowning:

Or does it?

The API should support private-to-public key calculations, however…

Subject: Re: OpenSSL ECDSA public key from private
Date: Sun 28 Oct 12 06:46:36PM +0900

Quoting Nokan E. ([email protected]):

1.9.3-p194 :003 > OpenSSL::PKey::EC::Point.new(key.group).methods.grep /mul/
=> []

Indeed… I get

=> [:mul]

I compile my own Ruby from Matz’s repository (this one on my laptop
was last updated a week ago). If you work under Linux, it should not
be too difficult to compile your own SSL extensions. Of course I have
never done it while running a different Ruby executable, but it should
be enough to do

cd /usr/src
svn co http://svn.ruby-lang.org/repos/ruby/trunk ruby
cd ruby/ext/openssl
ruby extconf.rb
make
sudo make install

Good luck!

Carlo

p pubkey.to_bn.to_s

I get a beautiful 155-digit number. Then, I have no idea about what
all these big numbers should be…

I’m sure I made a mistake but for me this script does not work. The
problem is that OpenSSL::PKey::EC::Point does not have a #mul
method in it.

1.9.3-p194 :001 > require ‘openssl’
=> true
1.9.3-p194 :002 > key = OpenSSL::PKey::EC.new ‘secp256k1’
=> #OpenSSL::PKey::EC:0x00000001cbb960
1.9.3-p194 :003 > OpenSSL::PKey::EC::Point.new(key.group).methods.grep
/mul/
=> []
1.9.3-p194 :004 >

:frowning:

On Sun, Oct 28, 2012 at 2:46 AM, Nokan E. [email protected]
wrote:

=> []
1.9.3-p194 :004 >

:frowning:

I ran into this same problem. #mul is only available on the absolute
latest
builds of Ruby.

You might consider using my red25519 gem instead if you’re simply
looking
for a signature algorithm and do not specifically need ECDSA:

You can most certainly generate public keys from private ones using this
gem:

Ed25519::SigningKey.new(private_key).verify_key.to_bytes