Net::SSH::Perl::Key::DSA - DSA key object


Net-SSH-Perl documentation Contained in the Net-SSH-Perl distribution.

Index


Code Index:

NAME

Top

Net::SSH::Perl::Key::DSA - DSA key object

SYNOPSIS

Top

    use Net::SSH::Perl::Key;
    my $key = Net::SSH::Perl::Key->new('DSA');

DESCRIPTION

Top

Net::SSH::Perl::Key::DSA subclasses Net::SSH::Perl::Key to implement a key object, SSH style. This object provides all of the methods needed for a DSA key object; the underlying implementation is provided by Crypt::DSA, and this class wraps around that module to provide SSH-specific functionality (eg. taking in a Net::SSH::Perl::Buffer blob and transforming it into a key object).

USAGE

Top

Net::SSH::Perl::Key::DSA implements the interface described in the documentation for Net::SSH::Perl::Key. Any differences or additions are described here.

$key->sign($data)

Wraps around Crypt::DSA::sign to sign $data using the private key portions of $key, then encodes that signature into an SSH-compatible signature blob.

Returns the signature blob.

$key->verify($signature, $data)

Given a signature blob $signature and the original signed data $data, attempts to verify the signature using the public key portion of $key. This wraps around Crypt::DSA::verify to perform the core verification.

$signature should be an SSH-compatible signature blob, as returned from sign; $data should be a string of data, as passed to sign.

Returns true if the verification succeeds, false otherwise.

AUTHOR & COPYRIGHTS

Top

Please see the Net::SSH::Perl manpage for author, copyright, and license information.


Net-SSH-Perl documentation Contained in the Net-SSH-Perl distribution.

# $Id: DSA.pm,v 1.24 2008/10/02 18:51:15 turnstep Exp $

package Net::SSH::Perl::Key::DSA;
use strict;

use Net::SSH::Perl::Buffer;
use Net::SSH::Perl::Constants qw( SSH_COMPAT_BUG_SIGBLOB );
use Net::SSH::Perl::Util qw( :ssh2mp );

use Net::SSH::Perl::Key;
use base qw( Net::SSH::Perl::Key );

use MIME::Base64;
use Crypt::DSA;
use Crypt::DSA::Key;
use Crypt::DSA::Signature;
use Carp qw( croak );
use Digest::SHA1 qw( sha1 );

use constant INTBLOB_LEN => 20;

sub ssh_name { 'ssh-dss' }

sub init {
    my $key = shift;
    $key->{dsa} = Crypt::DSA::Key->new;

    my($blob, $datafellows) = @_;

    if ($blob) {
        my $b = Net::SSH::Perl::Buffer->new( MP => 'SSH2' );
        $b->append($blob);
        my $ktype = $b->get_str;
        croak __PACKAGE__, "->init: cannot handle type '$ktype'"
            unless $ktype eq $key->ssh_name;
        my $dsa = $key->{dsa};
        $dsa->p( $b->get_mp_int );
        $dsa->q( $b->get_mp_int );
        $dsa->g( $b->get_mp_int );
        $dsa->pub_key( $b->get_mp_int );
    }

    if ($datafellows) {
        $key->{datafellows} = $datafellows;
    }
}

sub keygen {
    my $class = shift;
    my($bits, $datafellows) = @_;
    my $dsa = Crypt::DSA->new;
    my $key = $class->new(undef, $datafellows);
    $key->{dsa} = $dsa->keygen(Size => $bits, Verbosity => 1);
    $key;
}

sub size { $_[0]->{dsa}->size }

sub read_private {
    my $class = shift;
    my($key_file, $passphrase, $datafellows, $keytype) = @_;
    $keytype ||= 'PEM';

    my $key = $class->new(undef, $datafellows);
    $key->{dsa} = Crypt::DSA::Key->new(
                     Filename => $key_file,
                     Type     => $keytype,
                     Password => $passphrase
            );
    return unless $key->{dsa};

    $key;
}

sub write_private {
    my $key = shift;
    my($key_file, $passphrase) = @_;

    $key->{dsa}->write(
                    Filename => $key_file,
                    Type     => 'PEM',
                    Password => $passphrase
            );
}

sub dump_public { $_[0]->ssh_name . ' ' . encode_base64( $_[0]->as_blob, '' ) }

sub sign {
    my $key = shift;
    my($data) = @_;
    my $dsa = Crypt::DSA->new;
    my $sig = $dsa->sign(Digest => sha1($data), Key => $key->{dsa});
    my $sigblob = '';
    $sigblob .= mp2bin($sig->r, INTBLOB_LEN);
    $sigblob .= mp2bin($sig->s, INTBLOB_LEN);

    if (${$key->{datafellows}} & SSH_COMPAT_BUG_SIGBLOB) {
        return $sigblob;
    }
    else {
        my $b = Net::SSH::Perl::Buffer->new( MP => 'SSH2' );
        $b->put_str($key->ssh_name);
        $b->put_str($sigblob);
        $b->bytes;
    }
}

sub verify {
    my $key = shift;
    my($signature, $data) = @_;
    my $sigblob;

    if (${$key->{datafellows}} & SSH_COMPAT_BUG_SIGBLOB) {
        $sigblob = $signature;
    }
    else {
        my $b = Net::SSH::Perl::Buffer->new( MP => 'SSH2' );
        $b->append($signature);
        my $ktype = $b->get_str;
        croak "Can't verify type ", $ktype unless $ktype eq $key->ssh_name;
        $sigblob = $b->get_str;
    }

    my $sig = Crypt::DSA::Signature->new;
    $sig->r( bin2mp(substr $sigblob, 0, INTBLOB_LEN) );
    $sig->s( bin2mp(substr $sigblob, INTBLOB_LEN) );

    my $digest = sha1($data);
    my $dsa = Crypt::DSA->new;
    $dsa->verify( Key => $key->{dsa}, Digest => $digest, Signature => $sig );
}

sub equal {
    my($keyA, $keyB) = @_;
    $keyA->{dsa} && $keyB->{dsa} &&
    $keyA->{dsa}->p == $keyB->{dsa}->p &&
    $keyA->{dsa}->q == $keyB->{dsa}->q &&
    $keyA->{dsa}->g == $keyB->{dsa}->g &&
    $keyA->{dsa}->pub_key == $keyB->{dsa}->pub_key;
}

sub as_blob {
    my $key = shift;
    my $b = Net::SSH::Perl::Buffer->new( MP => 'SSH2' );
    $b->put_str($key->ssh_name);
    $b->put_mp_int($key->{dsa}->p);
    $b->put_mp_int($key->{dsa}->q);
    $b->put_mp_int($key->{dsa}->g);
    $b->put_mp_int($key->{dsa}->pub_key);
    $b->bytes;
}

sub fingerprint_raw { $_[0]->as_blob }

1;
__END__