#!/usr/bin/perl -w

# Dump GNU Keyring database entries to stdout
#
# Dobrica Pavlinusic <dpavlin@rot13.org> 2000-08-01
#
# 2003-02-23 security update: read password only from terminal (no more
# 		passwords in shell history files), verify passwords
# 
# http://www.rot13.org/~dpavlin/
# http://gnukeyring.sourceforge.net/
#
# PDA::Pilot comes with source of pilot-link, others are from CPAN
#
# 

use strict;
use PDA::Pilot;
use Crypt::DES; 
use Digest::MD5 qw(md5);
use Getopt::Std;
use Term::ReadPassword;

my %opts;
$opts{d} = $ENV{'HOME'}."/.jpilot/backup/Keys-Gtkr.pdb";

if ((! getopts('d:h46',\%opts) && (! -f $opts{d} || -r $opts{d})) || $opts{h}) {
	print "Usage: $0 [-d dbname][-h][-4][-6]\n";
	print "Dump all records from your GNU keyring database protected\n";
	print "by password.\nOptions:\n";
	print "\t-4 produce 4-field ZSafe 1.x compatibile format\n\n";
	print "\t-6 produce 6-field ZSafe 2.x compatibile format\n\n";
	exit;
}

die "Can't open $opts{d}" if (! -f $opts{d} || ! -r $opts{d});
my $db = PDA::Pilot::File::open($opts{d});

my $passwd = read_password('GNU keyring password: ');

my $key = md5($passwd);
my $c1 = new Crypt::DES substr($key,0,8);
my $c2 = new Crypt::DES substr($key,8,8);

# check password
my $r = $db->getRecord(0);
my $msg = substr($r->{raw},0,4).$passwd."\000" x 64;
$msg = substr($msg,0,64);	# cut to 64 bytes
my $digest = md5($msg);
if (substr($r->{raw},4,length($digest)) ne $digest) {
	print "Wrong password!\n";
	exit 1;
}

my $i=1;
while(defined(my $r = $db->getRecord($i++))) {
	my ($name,$raw)=split(/\000/,$r->{raw},2);
	warn "record not 8 byte padded" if (length($raw) % 8) != 0;
	my $out="";
	for (my $j=0; $j<int(length($raw) / 8); $j++) {
		my $to=$c1->decrypt( substr($raw,$j*8,8) );
		my $other=$c2->encrypt($to);
		$to=$c1->decrypt($other);
		$out.=$to;
	}
	my ($acc,$pass,$note,undef)=split(/\000/,$out,4);
	if ($opts{4}) {
		$note =~ s/\n$//sg;	# kill extra lf
		$note =~ s/\n/<br>/sg;
		printf "\"palm\";\"$name\";\"$acc\";\"$pass\";\"$note\"\n";
	} elsif ($opts{6}) {
		$note =~ s/\n$//sg;	# kill extra lf
		$note =~ s/\n/<br>/sg;
		printf "\"palm\";\"$name\";\"$acc\";\"$pass\";\"$note\";\"\";\"\"\n";
	} else {
		print "Name: $name\n";
		print "Account: $acc\nPassword: $pass\nNote:\n$note\n\n";
	}
}

