#!/usr/bin/perl -w
################################################################################
#			archivehash.pl
################################################################################
# This script reads in an archive file and computes a hash of each file
# contained in the archive. The only archive format currently supported is Zip
# and the only hash algorithm currently supported is MD5.
# Future enhancements will add support for more archive formats (rar, 7z,
# tar.bz2, tar.gz) and more hashes (SHA-1/224/256/384/512, RIPEMD160, Skein)
# Another possible future enhancement is the ability to look up hashes on an
# online database of malware, to allow checking for the existence of malware in
# your archive without having to extract it to disk first.
#
# This script requires Archive::Zip available from
# http://search.cpan.org/dist/Archive-Zip/
# and the Digest and Digest::MD5 modules available from
# http://search.cpan.org/~gaas/
#
# Usage:
# 	archivehash.pl archive.zip
#
# Author: Tom Samstag http://modtwo.com
# Version: 0.1
# Date: 2009-11-20
#
# Copyright 2009 Tom Samstag, modtwo (at) modtwo (dot) com
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

use strict;
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
use Archive::Zip::MemberRead;
use Digest;

foreach my $file (@ARGV)
{
	my $zip = Archive::Zip->new();
	die "Unable to open $file" unless($zip->read($file) == AZ_OK);

	foreach my $member ($zip->members())
	{
		my $fh = $member->readFileHandle();
		my $md5  = Digest->new("MD5");

		while (1)
		{
			my $buffer;
			my $read = $fh->read($buffer, 1024);
			die "FATAL ERROR reading from zip file $file on member ".$member->fileName()."!\n" if (!defined($read));
			last if (!$read);
			$md5->add($buffer);
		}

		print $md5->hexdigest . "  " .  $member->fileName() . "\n";
	}
}

