# Somehow the below verification code excerpt will show how to do
# a verification without loading the entire message into memory at
# once. It assumes the SHA1 hash has already been calculated, and
# is $calculated_hash.
#
# The function takes $sig as the DomainKeys signature header.
# $pubk is the public key as fetched from DNS.
# The DK function computes $expected_hash from the signature.
# If $expected_hash eq $calculated_hash, it is a valid signature.
# From Joshua Tauberer's Thunderbird Extension for Sender Verification
# http://taubz.for.net/code/spf/
use Crypt::RSA::Primitives;
use Crypt::RSA::DataFormat qw(octet_len os2ip i2osp octet_xor mgf1);
use Crypt::RSA::Key::Public;
sub DK {
my $sig = shift;
$sig = Mail::DomainKeys::Signature->parse(String => $sig);
# Fetch the public key
my $pubk = fetch Mail::DomainKeys::Key::Public(
Protocol => $sig->protocol,
Selector => $sig->selector,
Domain => $sig->domain);
if (!defined($pubk)) { return undef; }
if ($pubk->revoked) { return undef; }
# TODO - check granularity
# The following is based on Crypt::RSA::SS::PSS.
# If anyone reading can get this to work with
# $pubk->cork directly, that'd be preferable.
my ($kn, $ke) = $pubk->cork->get_key_parameters();
my $key = bless { e => $ke->to_decimal, n => $kn->to_decimal }, 'Crypt::RSA::Key::Public';
my $rsa = Crypt::RSA::Primitives->new();
my $S = MIME::Base64::decode($sig->signature);
my $k = octet_len ($key->n);
my $s = os2ip ($S);
my $m = $rsa->core_verify (Key => $key, Signature => $s) || return undef;
my $em1 = i2osp ($m, $k-1) || return undef;
$em1 = substr($em1, length($em1) - 20, 20);
$em1 = MIME::Base64::encode($em1);
$em1 =~ s/[=\s]+$//;
return ($sig->domain, $em1);
}
# usage
# ($dkdomain, $expected_hash) = DK($header)
# if ($expected_hash eq $calculated_hash)
# {
# $result = "pass";
# $comment = "Verified from <$dkdomain>"
# }
syntax highlighted by Code2HTML, v. 0.9.1