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.
Quoting Nokan Emiro (uzleepito@gmail.com):
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: OpenSSL ECDSA public key from private
Date: Sun 28 Oct 12 03:28:36AM +0900
--
* Se la Strada e la sua Virtu' non fossero state messe da parte,
* K * Carlo E. Prelz - fluido@fluido.as che bisogno ci sarebbe
* di parlare tanto di amore e di rettitudine? (Chuang-Tzu)
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
···
Nokan Emiro <uzleepito@gmail.com> 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?
--
Dave Aronson, the T. Rex of Codosaurus LLC,
secret-cleared freelance software developer
taking contracts in or near NoVa or remote.
See information at http://www.Codosaur.us/\.
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 = *<a paramether from outside>*
···
*
*
key.plese_calculate_the_public_key_from_the_private_one!
u.
On Sat, Oct 27, 2012 at 8:37 PM, Carlo E. Prelz <fluido@fluido.as> wrote:
Subject: OpenSSL ECDSA public key from private
Date: Sun 28 Oct 12 03:28:36AM +0900
Quoting Nokan Emiro (uzleepito@gmail.com):
> 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
--
* Se la Strada e la sua Virtu' non fossero state messe da parte,
* K * Carlo E. Prelz - fluido@fluido.as che bisogno ci sarebbe
* di parlare tanto di amore e di rettitudine? (Chuang-Tzu)
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
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. 
Quoting Nokan Emiro (uzleepito@gmail.com):
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 = *<a paramether from outside>*
*
*
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
···
Subject: Re: OpenSSL ECDSA public key from private
Date: Sun 28 Oct 12 04:23:52AM +0900
--
* Se la Strada e la sua Virtu' non fossero state messe da parte,
* K * Carlo E. Prelz - fluido@fluido.as che bisogno ci sarebbe
* di parlare tanto di amore e di rettitudine? (Chuang-Tzu)
Much better, but it's still not finished... 
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;
}
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.
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.
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. 
Or does it?
The API should support private-to-public key calculations, however...
Quoting Nokan Emiro (uzleepito@gmail.com):
...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. 
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
···
Subject: Re: OpenSSL ECDSA public key from private
Date: Sun 28 Oct 12 05:59:21AM +0900
--
* Se la Strada e la sua Virtu' non fossero state messe da parte,
* K * Carlo E. Prelz - fluido@fluido.as che bisogno ci sarebbe
* di parlare tanto di amore e di rettitudine? (Chuang-Tzu)
#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...
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 >

Quoting Nokan Emiro (uzleepito@gmail.com):
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
···
Subject: Re: OpenSSL ECDSA public key from private
Date: Sun 28 Oct 12 06:46:36PM +0900
--
* Se la Strada e la sua Virtu' non fossero state messe da parte,
* K * Carlo E. Prelz - fluido@fluido.as che bisogno ci sarebbe
* di parlare tanto di amore e di rettitudine? (Chuang-Tzu)
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
···
On Sun, Oct 28, 2012 at 2:46 AM, Nokan Emiro <uzleepito@gmail.com> wrote:
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 >

--
Tony Arcieri