=================================================================== RCS file: /cvs/palm/Palm-Keyring/lib/Palm/Keyring.pm,v retrieving revision 1.55 retrieving revision 1.62 diff -u -r1.55 -r1.62 --- palm/Palm-Keyring/lib/Palm/Keyring.pm 2008/09/17 15:47:47 1.55 +++ palm/Palm-Keyring/lib/Palm/Keyring.pm 2008/09/19 07:01:00 1.62 @@ -1,5 +1,5 @@ package Palm::Keyring; -# $RedRiver: Keyring.pm,v 1.54 2007/12/05 05:42:29 andrew Exp $ +# $RedRiver: Keyring.pm,v 1.61 2008/09/19 05:55:35 andrew Exp $ ######################################################################## # Keyring.pm *** Perl class for Keyring for Palm OS databases. # @@ -110,6 +110,7 @@ else { $options->{password} = shift; $options->{version} = shift; + $options->{cipher} = shift; } } @@ -141,6 +142,10 @@ $self->{appinfo}->{iter} ||= $self->{options}->{iterations}; }; + if ( defined $options->{file} ) { + $self->Load($options->{file}); + } + if ( defined $options->{password} ) { $self->Password($options->{password}); } @@ -219,13 +224,13 @@ } } - my $rc = $self->SUPER::Write(@_); + my @rc = $self->SUPER::Write(@_); if ($self->{version} == 4) { shift @{ $self->{records} }; } - return $rc; + return @rc; } # ParseRecord @@ -235,7 +240,7 @@ my $self = shift; my $rec = $self->SUPER::ParseRecord(@_); - return $rec if ! exists $rec->{data}; + return $rec if !(defined $rec->{data} && length $rec->{data} ); if ($self->{version} == 4) { # skip the first record because it contains the password. @@ -243,7 +248,7 @@ $self->{encpassword} = $rec->{data}; return '__DELETE_ME__'; } - + if ($self->{records}->[0] eq '__DELETE_ME__') { shift @{ $self->{records} }; } @@ -272,8 +277,9 @@ $rec->{encrypted} = substr $extra, $blocksize; } else { + # XXX Can never get here to test, ParseAppInfoBlock is always run + # XXX first by Load(). croak "Unsupported Version $self->{version}"; - return; } return $rec; @@ -290,11 +296,12 @@ if ($rec->{encrypted}) { my $name = $rec->{plaintext}->{0}->{data} || $EMPTY; $rec->{data} = join $NULL, $name, $rec->{encrypted}; - delete $rec->{plaintext}; - delete $rec->{encrypted}; } } elsif ($self->{version} == 5) { + croak 'No encrypted data in record' if !defined $rec->{encrypted}; + croak 'No ivec!' if !$rec->{ivec}; + my $field; if ($rec->{plaintext}->{0}) { $field = $rec->{plaintext}->{0}; @@ -313,7 +320,12 @@ } else { croak "Unsupported Version $self->{version}"; } + # XXX Should I? + delete $rec->{plaintext}; + delete $rec->{encrypted}; + croak 'No data in record to pack' if !$rec->{data}; + return $self->SUPER::PackRecord($rec, @_); } @@ -340,7 +352,7 @@ # Nothing extra for version 4 } elsif ($self->{version} == 5) { - _parse_appinfo_v5($appinfo) || return; + _parse_appinfo_v5($appinfo); } else { croak "Unsupported Version $self->{version}"; @@ -353,10 +365,7 @@ { my $appinfo = shift; - if (! exists $appinfo->{other}) { - # XXX Corrupt appinfo? - return; - } + croak 'Corrupt appinfo? no {other}' if ! $appinfo->{other}; my $unpackstr = ("C1" x 8) # 8 uint8s in an array for the salt @@ -425,23 +434,25 @@ my $self = shift; my $rec = shift; my $pass = shift || $self->{password}; + + if ( !$rec ) { + croak('Needed parameter [record] not passed!'); + } + my $data = shift || $rec->{plaintext}; my $ivec = shift; + if ( ! $pass && ! $self->{appinfo}->{key}) { - croak("password not set!\n"); + croak('password not set!'); } - if ( ! $rec) { - croak("Needed parameter 'record' not passed!\n"); - } - if ( ! $data) { - croak("Needed 'plaintext' not passed!\n"); + croak('Needed parameter [plaintext] not passed!'); } if ( $pass && ! $self->Password($pass)) { - croak("Incorrect Password!\n"); + croak('Incorrect Password!'); } my $acct; @@ -469,35 +480,26 @@ $encrypted = _encrypt_v4($datav4, $acctv4, $self->{digest}); } elsif ($self->{version} == 5) { - ($encrypted, $ivec) = _encrypt_v5( + ($encrypted, $rec->{ivec}) = _encrypt_v5( $data, $acct, $self->{appinfo}->{key}, $self->{appinfo}->{cipher}, $ivec, ); - if (defined $ivec) { - $rec->{ivec} = $ivec; - } } else { - croak "Unsupported Version $self->{version}"; + croak "Unsupported version $self->{version}"; } $rec->{plaintext}->{0} = $data->{0}; - if ($encrypted) { - if ($encrypted eq '1') { - return 1; - } - + if ($encrypted ne '1') { $rec->{attributes}{Dirty} = 1; $rec->{attributes}{dirty} = 1; $rec->{encrypted} = $encrypted; - - return 1; - } else { - return; } + + return 1; } sub _encrypt_v4 @@ -580,7 +582,9 @@ my $c = crypts($cipher) or croak('Unknown cipher ' . $cipher); if (! defined $ivec) { - $ivec = pack("C*",map {rand(256)} 1..$c->{blocksize}); + while (! $ivec) { + $ivec = pack("C*",map {rand(256)} 1..$c->{blocksize}); + } } my $changed = 0; @@ -610,7 +614,7 @@ } } - return 1, 0 if $changed == 0; + return (1, $ivec) if $changed == 0; if ($need_newdate) { my ($day, $month, $year) = (localtime)[3,4,5]; @@ -1428,7 +1432,7 @@ =head2 new - $pdb = new Palm::Keyring([$password[, $version]]); + $pdb = new Palm::Keyring([$password[, $version[, $cipher]]]); Create a new PDB, initialized with the various Palm::Keyring fields and an empty record list. @@ -1470,6 +1474,10 @@ =item iterations The number of iterations to encrypt with. Only used by somy crypts in v5 databases. + +=item file + +The name of a file to Load(). This will override many of the other options. =back