Using Crypt::DSA

M

Mike Friedman

I'm looking at Crypt::DSA, in particular the docs from
CPAN. One thing I can't seem to grasp from the documentation:

How do I extract (and write to disk) just the public key, after
I've generated a DSA key object? Unlike Crypt::RSA, where keygen
returns a list consisting of the public and private keys as
separate scalars, it seems that the DSA keygen method returns
only a single scalar, which supposedly contains both the public
and private portions of the key.

Now, the only way I see to write out a key is with the 'key->write'
method, but when I use $key->write (where '$key' is what's returned
from keygen), I get just one object written and it's labeled
(internally) as a private key.

What if I want to create a file containing just the public portion,
so I can distribute it?

I must admit that the documentation for Crypt::DSA::Key, which
should explain this, is not at all clear to me. The syntax for
Crypt::DSA is supposed to be modeled after that of Crypt::RSA,
but in this area there's clearly a difference and I don't
understand it.

Thanks.

Mike
 
A

A. Sinan Unur

How do I extract (and write to disk) just the public key,
....

I must admit that the documentation for Crypt::DSA::Key, which
should explain this, is not at all clear to me.

I have never used the said modules, but, looking at the documentation:

<URL:http://search.cpan.org/~btrott/Crypt-DSA-0.13/lib/Crypt/DSA/Key.pm>

Any of the key attributes can be accessed through combination get/set
methods. The key attributes are: p, q, g, priv_key, and pub_key. For
example:

$key->p($p);
my $p2 = $key->p;
....

So, I would try

printf "Public key: %s\n", $key->pub_key;

to print the public key.

Sinan
 
M

Mike Friedman

A. Sinan Unur said:
Any of the key attributes can be accessed through combination get/set
methods. The key attributes are: p, q, g, priv_key, and pub_key. For
example:

$key->p($p);
my $p2 = $key->p;
...

So, I would try

printf "Public key: %s\n", $key->pub_key;

to print the public key.

Sinan

Sinan,

I had already tried that and, indeed, it might be technically
correct. But what I really want is an output file that is ASN.1
encoded and in a standard PEM key format, which is what you get
when you use the key->write method. It's just that the latter
seems to give only a private key file (which may actually include
the public key, but that's just speculation on my part).

Mike
 
A

A. Sinan Unur

....

I had already tried that and, indeed, it might be technically
correct. But what I really want is an output file that is ASN.1
encoded and in a standard PEM key format, which is what you get
when you use the key->write method. It's just that the latter
seems to give only a private key file (which may actually include
the public key, but that's just speculation on my part).

Hmmm ... Sorry. I misunderstood the question.

Unfortunately, I don't know the answer to your question. Good luck.

Sinan
 
S

Sisyphus

Mike Friedman said:
Sinan,

I had already tried that and, indeed, it might be technically
correct. But what I really want is an output file that is ASN.1
encoded and in a standard PEM key format, which is what you get
when you use the key->write method. It's just that the latter
seems to give only a private key file (which may actually include
the public key, but that's just speculation on my part).

Do you have Convert::pEM installed ? It's not a pre-requisite for
Crypt::DSA, but it might help you get at the answers you want. I don't
understand PEM format at all - if you're in the same boat then maybe there's
something in the openssl/doc/crypto/pem.pod for you.

Included below is a modified version of '04-pem.t' which is part of the
Crypt::DSA test suite. It demonstrates that the pem file does indeed hold
both public and private key information (by extracting that and other
information from
the pem file that '04-pem.t' generates).

Hth.

Cheers,
Rob

# $Id: 04-pem.t,v 1.4 2001/04/22 23:58:39 btrott Exp $

use strict;

use Test;
use Crypt::DSA;
use Crypt::DSA::Key;

my $no_pem;
BEGIN {
eval "use Convert::pEM;";
$no_pem = $@;
if ($no_pem) {
print "1..0 skipping\n";
exit;
}

plan tests => 12;
}


my $keyfile = "./dsa-key.pem";

my $dsa = Crypt::DSA->new;
my $key = $dsa->keygen( Size => 512 );
my $key2;

skip($no_pem, $key->write( Type => 'PEM', Filename => $keyfile));
$key2 = Crypt::DSA::Key->new( Type => 'PEM', Filename => $keyfile );
skip($no_pem, $key->p, $key2->p);
skip($no_pem, $key->q, $key2->q);
skip($no_pem, $key->g, $key2->g);
skip($no_pem, $key->pub_key, $key2->pub_key);
skip($no_pem, $key->priv_key, $key2->priv_key);

# There's an option (not used here)
# to password-protect dsa-key.pem.

skip($no_pem, $key->write( Type => 'PEM', Filename => $keyfile));
$key2 = Crypt::DSA::Key->new( Type => 'PEM', Filename => $keyfile);
skip($no_pem, $key->p, $key2->p);
skip($no_pem, $key->q, $key2->q);
skip($no_pem, $key->g, $key2->g);
skip($no_pem, $key->pub_key, $key2->pub_key);
skip($no_pem, $key->priv_key, $key2->priv_key);

#unlink $keyfile;

print "Public: ", $key->pub_key, "\n";
print "Private: ", $key->priv_key, "\n";
print "Total: ", $key->write, "\n";

# To show that dsa-key.pem does hold both private
# and public key information :

my $pem = Convert::pEM->new(
Name => "DSA PRIVATE KEY",
ASN => qq(
DSAPrivateKey SEQUENCE {
version INTEGER,
p INTEGER,
q INTEGER,
g INTEGER,
pub_key INTEGER,
priv_key INTEGER
}
));


my $pkey = $pem->read(
Filename => $keyfile
);

my %deref = %$pkey;
for(keys(%deref)) {print "\n$_: $deref{$_}\n"}
print "\n";

my %d = %{$deref{DSAPrivateKey}};
for (keys(%d)) {print "$_ : $d{$_}\n"}
 
M

Mike Friedman

Sisyphus said:
Do you have Convert::pEM installed ? It's not a pre-requisite for
Crypt::DSA, but it might help you get at the answers you want. I
don't understand PEM format at all - if you're in the same boat
then maybe there's something in the openssl/doc/crypto/pem.pod
for you.

I've decided for now that just writing out $key->pub_key is sufficient
for my purposes (to create a public key file). I can read in that hex
value and use it to sign a messages.

But now, I've run into another snag with Crypt::DSA. How in the world
do I write out a signature to a file, in a format that can be read
in by another script for the purpose of verifying the signed message?

I tried taking the signature object created by the sign() method,
base64 encoding it and writing it out. When I read that in, base64
decode it and populate a new signature object with it, verify()
complains, I think because I didn't first serialize the signature
(into an ASN.1 encoded format).

The CPAN docs say there's supposed to be a $sig->serialize method
on a signature object. But it appears this isn't true. Not only
does my script fail, complaining about the absence of such a method, but
looking at the source code for Crypt::RSA::Signature seems to reveal
that there is, in fact, no serialize method defined on a signature object.

So, once again, assuming I've signed a message, creating a signature
object, how do I write that signature to a file so it can be used
as input to a verify script?

BTW: if I do the sign and verify in the same script, passing the
signature object returned by the sign() method to the verify() method,
that works fine.

I'd really appreciate a pointer on this.

Thanks.

Mike
 
S

Sisyphus

Mike Friedman said:
So, once again, assuming I've signed a message, creating a signature
object, how do I write that signature to a file so it can be used
as input to a verify script?

It may simply be that you failed to bless() the key and signature retrieved
from file. Here's a script that writes to file, then reads from that file
and verifies the message using information obtained only from that file:

use strict;
use warnings;
use Crypt::DSA;

my $message = "Je suis l'homme a tete de chou.";
for (1..4) {$message .= "\n$message"}

my $dsa = Crypt::DSA->new;
my $key = $dsa->keygen( Size => 512 );

my $sig = $dsa->sign( Message => $message, Key => $key );

# @file contains all of the signature and key information that
# needs to be written to the file.
my @file = ($key->{p}, $key->{q}, $key->{g}, $key->{pub_key},
$sig->{r}, $sig->{s});

# Save @file and $message to file:
open(WR, ">msg.txt") or die "Can't open WR:$!";
for(@file) {print WR $_, "\n"}
print WR $message;
close(WR) or die "Can't close WR: $!";

# Retrieve key, signature and message from file
open(RD, "msg.txt") or die "Can't open RD:$!";
my @msg_from_file = <RD>;
close(RD) or die "Can't close RD: $!";

my %key_from_file;
my %sig_from_file;

$key_from_file{p} = shift(@msg_from_file);
chomp($key_from_file{p});

$key_from_file{q} = shift(@msg_from_file);
chomp($key_from_file{q});

$key_from_file{g} = shift(@msg_from_file);
chomp($key_from_file{g});

$key_from_file{pub_key} = shift(@msg_from_file);
chomp($key_from_file{pub_key});

$sig_from_file{r} = shift(@msg_from_file);
chomp($sig_from_file{r});

$sig_from_file{s} = shift(@msg_from_file);
chomp($sig_from_file{s});

my $message_from_file;
for(@msg_from_file) {$message_from_file .= $_}

my $k = \%key_from_file;
bless($k, "Crypt::DSA::Key");

my $s = \%sig_from_file;
bless($s, "Crypt::DSA::Signature");


# Verify using data read from file:
my $dsa_verify = Crypt::DSA->new;

my $verified = $dsa_verify->verify(
Key => $k,
Message => $message_from_file,
Signature => $s
);

if($verified) {print "Message verified\n"}
else {print "Message NOT verified\n"}

__END__

Cheers,
Rob
 
S

Sisyphus

Sisyphus said:
# @file contains all of the signature and key information that
# needs to be written to the file.
my @file = ($key->{p}, $key->{q}, $key->{g}, $key->{pub_key},
$sig->{r}, $sig->{s});

I was being a little dense there - concentrating on being able to reproduce
the original objects, rather than what would actually be put in the file.
You probably don't want to be saving $key->{p}, $key->{q} and $sig->{r} -
and there's no need to save them to file.

When it comes to creating the key and signature to verify the message you
can simply set those 3 hash keys to zero (if you find there's a need to
specify a value for those hash keys at all).

Cheers,
Rob
 
M

Mike Friedman

Sisyphus said:
It may simply be that you failed to bless() the key and signature
retrieved from file. Here's a script that writes to file, then reads
from that file and verifies the message using information obtained only
from that file:
...

Rob,

Looking at your sample script (but not yet having tried it), it seems that
it will work (and is quite educational, in fact). However, I still have a
concern, which has to do with how I intend to use my scripts.

I want to be able to create a public key file and a signature in formats
that can be distributed to a user community whose applications may be
using other DSA implementations (e.g., Java crypto lib, or other scripting
languages besides perl). So, it's important that the public key file be
in a reasonably standard format. Also, I'd be passing the signature as
a base64-encoded string via a web form field. Once the application
base64-decodes it, the signature should be in a format easily fed to its
DSA verify routine.

I'm thinking of how other products, like SSH, do this sort of thing,
with my main focus being on how various DSA implementations do signature
verification.

Thanks.

Mike
 
S

Sisyphus

[snip]
I want to be able to create a public key file and a signature in formats
that can be distributed to a user community whose applications may be
using other DSA implementations (e.g., Java crypto lib, or other scripting
languages besides perl). So, it's important that the public key file be
in a reasonably standard format.

Which, afaik, would be a pem file. Crypt::DSA can parse them (as long as you
have Convert::pEM) and so, presumably, can the other DSA implementations. To
write a *public* key pem file with Crypt::DSA you just do (as in 04-pem.t):

$key->priv_key(undef);
$key->write( Type => 'PEM', Filename => $keyfile);

Also, I'd be passing the signature as
a base64-encoded string via a web form field. Once the application
base64-decodes it, the signature should be in a format easily fed to its
DSA verify routine.

Are you saying the signature part is not a problem ? I find some ambiguity
with "the signature should be in a format easily fed to its DSA verify
routine" - not sure whether that means the signature is already in a
suitable format, or whether it means that it needs to be in a suitable
format (but isn't).

Cheers,
Rob
 
M

Mike Friedman

Sisyphus said:
Which, afaik, would be a pem file. Crypt::DSA can parse them (as
long as you have Convert::pEM) and so, presumably, can the other
DSA implementations. To write a *public* key pem file with
Crypt::DSA you just do (as in 04-pem.t):

$key->priv_key(undef);
$key->write( Type => 'PEM', Filename => $keyfile);

Rob,

I do have Convert::pEM.

I tried your suggestion above, but I get only a private key. In fact,
my script first writes the key object (using $key->write) returned
from sign(), as-is, to one file, then does the above in attempt to
write the *public* key to another file. But both files are identical!

Here's the entirety of my little test script:

------------------------------------------
#!/usr/local/bin/perl

use Crypt::DSA;
use strict;

my $dsa = new Crypt::DSA;
my $key = Crypt::DSA::Key->new;
my $filename;

$filename = "./dsakey";

$key = $dsa->keygen (
Size => 1024,
Verbosity => 1,
) or die $dsa->errstr();

$key->write(
Type => 'PEM',
Filename => "$filename.priv",
);

$key->priv_key(undef);

$key->write(
Type => 'PEM',
Filename => "$filename.pub",
);

exit;
------------------------------------------

The result is that 'dsakey.priv' and 'dsakey.pub' have exactly
the same contents, including the 'BEGIN DSA PRIVATE KEY',
'END DSA PRIVATE KEY' delimiters, even though I've undefined priv_key.
What am I doing wrong?
Are you saying the signature part is not a problem ? I find some
ambiguity with "the signature should be in a format easily fed to
its DSA verify routine" - not sure whether that means the signature
is already in a suitable format, or whether it means that it needs
to be in a suitable format (but isn't).

I was just expressing my concern that the signature as produced in your
earlier example (by writing out the separate components of the signature
object) wouldn't be 'standard' in some sense. But I haven't yet gotten
far enough to try all that out.

Right now, I'm interested in your idea of how to write out a public
key file in PEM format; it seems it should work, but I'm not getting
the right results. So, probably I'm overlooking something obvious.

Thanks for your help so far.

Mike
 
S

Sisyphus

Mike Friedman said:
Here's the entirety of my little test script:

------------------------------------------
#!/usr/local/bin/perl

use Crypt::DSA;
use strict;

my $dsa = new Crypt::DSA;
my $key = Crypt::DSA::Key->new;
my $filename;

$filename = "./dsakey";

$key = $dsa->keygen (
Size => 1024,
Verbosity => 1,
) or die $dsa->errstr();

$key->write(
Type => 'PEM',
Filename => "$filename.priv",
);

$key->priv_key(undef);

$key->write(
Type => 'PEM',
Filename => "$filename.pub",
);

exit;
------------------------------------------

The result is that 'dsakey.priv' and 'dsakey.pub' have exactly
the same contents, including the 'BEGIN DSA PRIVATE KEY',
'END DSA PRIVATE KEY' delimiters, even though I've undefined priv_key.
What am I doing wrong?

Hmmm ... I run a copy'n'paste of that script and get 2 different files. The
'.priv' file has 'BEGIN DSA PRIVATE KEY', 'END DSA PRIVATE KEY' delimiters
and the '.pub' file has 'BEGIN PUBLIC KEY', 'END PUBLIC KEY' delimiters. The
base64 content is also different. Are we using the same version of
Crypt::DSA ? (I've got 0.13 which, I think, is the latest.)

I'm on Win32 - but I don't think that's going to account for the different
behaviour (in this instance :)

Other than that, check 'perldoc Crypt::DSA::Key' for some possible clues.

Cheers,
Rob
 
M

Mike Friedman

Sisyphus said:
Hmmm ... I run a copy'n'paste of that script and get 2 different files. The
'.priv' file has 'BEGIN DSA PRIVATE KEY', 'END DSA PRIVATE KEY' delimiters
and the '.pub' file has 'BEGIN PUBLIC KEY', 'END PUBLIC KEY' delimiters. The
base64 content is also different. Are we using the same version of
Crypt::DSA ? (I've got 0.13 which, I think, is the latest.)

Rob,

I'm using version 0.12_1, which represents the latest FreeBSD port. I
prefer to install from ports because, especially in the case of software
that has lots of dependencies, installing manually becomes a real headache.
(A while back, when I had a Solaris box, I tried to install Crypt::RSA and
I could never, it seems, get to the end of installing all the dependencies!).

I see from CPAN that there have been some changes between 0.12 and 0.13, some
of which may affect what I've been doing (and asking about). For example,
I earlier inquired about the $sig->serialize method and it turns out that
was introduced in 0.13.

Anyway, there doesn't seem to be a port available yet for 0.13. Since I'm
just doing prototype testing, for an application that probably won't even be
running on FreeBSD, I don't want to get bogged down in version discrepancies.
I may just wait for a while to decide what to do.

Thanks.

Mike
 
S

Sisyphus

Mike Friedman said:
Rob,

I'm using version 0.12_1, which represents the latest FreeBSD port. I
prefer to install from ports because, especially in the case of software
that has lots of dependencies, installing manually becomes a real headache.
(A while back, when I had a Solaris box, I tried to install Crypt::RSA and
I could never, it seems, get to the end of installing all the
dependencies!).

Yep - either use the CPAN module which "does it all" for you ...... or just
persevere. Most people use CPAN, but I prefer to use perseverance :)
I see from CPAN that there have been some changes between 0.12 and 0.13, some
of which may affect what I've been doing (and asking about). For example,
I earlier inquired about the $sig->serialize method and it turns out that
was introduced in 0.13.

Looking at the documentation for Crypt::DSA::Key in version 0.12, I see *no*
mention of being able to write just the public portion of the key to file.
Perhaps it can't be done. Odd that doing '$key->priv_key(undef);' had no
effect on the file that was written. I guess that instruction must be being
ignored on 0.12. (Perhaps if you had used the warnings pragma in that script
you posted, some mention of that might have been made :)
Anyway, there doesn't seem to be a port available yet for 0.13. Since I'm
just doing prototype testing, for an application that probably won't even be
running on FreeBSD, I don't want to get bogged down in version discrepancies.
I may just wait for a while to decide what to do.

I just noticed a module called Crypt::OpenSSL::DSA which is a DSA
implementation that uses OpenSSL. If you have OpenSSL, you may get better
milage with that module.

Cheers,
Rob
 
M

Mike Friedman

Sisyphus said:
I just noticed a module called Crypt::OpenSSL::DSA which is a DSA
implementation that uses OpenSSL. If you have OpenSSL, you may get better
milage with that module.

Rob,

Now that's the best advice I've received in a long time! In just about
15 minutes, I installed Crypt::OpenSSL::DSA (the current version, 0.12)
from a FreeBSD port and created 3 scripts: to generate and write out a
public and private key (each to a PEM format file), to sign a message
and to verify a message.

The interface is so much simpler than with Crypt::DSA.

Thanks very much. I now have something to work with.

Mike
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top