Alt-Crypt-RSA-BigInt
view release on metacpan or search on metacpan
lib/Crypt/RSA/SS/PSS.pm view on Meta::CPAN
package Crypt::RSA::SS::PSS;
use strict;
use warnings;
## Crypt::RSA::SS:PSS
##
## Copyright (c) 2001, Vipul Ved Prakash. All rights reserved.
## This code is free software; you can redistribute it and/or modify
## it under the same terms as Perl itself.
use base 'Crypt::RSA::Errorhandler';
use Math::Prime::Util qw/random_bytes/;
use Crypt::RSA::DataFormat qw(octet_len os2ip i2osp octet_xor mgf1);
use Crypt::RSA::Primitives;
use Crypt::RSA::Debug qw(debug);
use Digest::SHA qw(sha1);
$Crypt::RSA::SS::PSS::VERSION = '1.99';
sub new {
my ($class, %params) = @_;
my $self = bless { primitives => new Crypt::RSA::Primitives,
hlen => 20,
VERSION => $Crypt::RSA::SS::PSS::VERSION,
}, $class;
if ($params{Version}) {
# do versioning here
}
return $self;
}
sub sign {
my ($self, %params) = @_;
my $key = $params{Key}; my $M = $params{Message} || $params{Plaintext};
return $self->error("No Key parameter", \$M, \%params) unless $key;
return $self->error("No Message or Plaintext parameter", \$key, \%params) unless $M;
my $k = octet_len ($key->n);
my $salt = random_bytes($self->{hlen});
my $em = $self->encode ($M, $salt, $k-1);
my $m = os2ip ($em);
my $sig = $self->{primitives}->core_sign (Key => $key, Message => $m);
my $S = i2osp ($sig, $k);
return ($S, $salt) if wantarray;
return $S;
}
sub verify_with_salt {
my ($self, %params) = @_;
my $key = $params{Key}; my $M = $params{Message} || $params{Plaintext};
my $S = $params{Signature}; my $salt = $params{Salt};
return $self->error("No Key parameter", \$S, \%params) unless $key;
return $self->error("No Signature parameter", \$key, \%params) unless $S;
my $k = octet_len ($key->n);
my $em;
unless ($em = $self->encode ($M, $salt, $k-1)) {
return if $self->errstr eq "Message too long.";
return $self->error ("Modulus too short.", \$M, \$S, \$key, \%params) if
$self->errstr eq "Intended encoded message length too short.";
}
return $self->error ("Invalid signature.", \$M, \$S, $key, \%params) if length($S) < $k;
my $s = os2ip ($S);
my $m = $self->{primitives}->core_verify (Key => $key, Signature => $s) ||
$self->error ("Invalid signature.", \$M, \$S, $key, \%params);
my $em1 = i2osp ($m, $k-1) ||
return $self->error ("Invalid signature.", \$M, \$S, $key, \%params);
return 1 if $em eq $em1;
return $self->error ("Invalid signature.", \$M, \$S, $key, \%params);
}
sub verify {
my ($self, %params) = @_;
my $key = $params{Key}; my $M = $params{Message} || $params{Plaintext};
my $S = $params{Signature};
return $self->error("No Key parameter", \$S, \$M, \%params) unless $key;
return $self->error("No Signature parameter", \$key, \$M, \%params) unless $S;
return $self->error("No Message or Plaintext parameter", \$key, \$S, \%params) unless $M;
my $k = octet_len ($key->n);
my $s = os2ip ($S);
my $m = $self->{primitives}->core_verify (Key => $key, Signature => $s) ||
$self->error ("Invalid signature.", \$M, \$S, $key, \%params);
my $em1 = i2osp ($m, $k-1) ||
return $self->error ("Invalid signature.", \$M, \$S, $key, \%params);
return 1 if $self->verify_with_salt_recovery ($M, $em1);
return $self->error ("Invalid signature.", \$M, \$S, $key, \%params);
}
sub encode {
my ($self, $M, $salt, $emlen) = @_;
return $self->error ("Intended encoded message length too short.", \$M, \$salt )
if $emlen < 2 * $self->{hlen};
my $H = $self->hash ("$salt$M");
my $padlength = $emlen - (2*$$self{hlen});
my $PS = chr(0)x$padlength;
my $db = $salt . $PS;
my $dbmask = $self->mgf ($H, $emlen - $self->{hlen});
my $maskeddb = octet_xor ($db, $dbmask);
my $em = $H . $maskeddb;
return $em;
}
sub verify_with_salt_recovery {
my ($self, $M, $EM) = @_;
my $hlen = $$self{hlen};
my $emlen = length ($EM);
return $self->error ("Encoded message too short.", \$M, \$EM) if $emlen < (2*$hlen);
my $H = substr $EM, 0, $hlen;
my $maskeddb = substr $EM, $hlen;
my $dbmask = $self->mgf ($H, $emlen-$hlen);
my $db = octet_xor ($maskeddb, $dbmask);
my $salt = substr $db, 0, $hlen;
my $PS = substr $db, $hlen;
my $check = chr(0) x ($emlen-(2*$hlen)); debug ("PS: $PS");
return $self->error ("Inconsistent.") unless $check eq $PS;
my $H1 = $self->hash ("$salt$M");
return 1 if $H eq $H1;
return $self->error ("Inconsistent.");
}
sub hash {
my ($self, $data) = @_;
return sha1 ($data);
}
sub mgf {
my ($self, @data) = @_;
return mgf1 (@data);
}
sub version {
my $self = shift;
return $self->{VERSION};
}
sub signblock {
return -1;
}
sub verifyblock {
my ($self, %params) = @_;
return octet_len($params{Key}->n);
}
1;
=head1 NAME
Crypt::RSA::SS::PSS - Probabilistic Signature Scheme based on RSA.
=head1 SYNOPSIS
my $pss = new Crypt::RSA::SS::PSS;
my $signature = $pss->sign (
Message => $message,
Key => $private,
) || die $pss->errstr;
my $verify = $pss->verify (
Message => $message,
Key => $key,
Signature => $signature,
) || die $pss->errstr;
=head1 DESCRIPTION
( run in 0.701 second using v1.01-cache-2.11-cpan-9288abcf80b )