=================================================================== RCS file: /cvs/palm/Palm-Keyring/lib/Palm/Keyring.pm,v retrieving revision 1.5 retrieving revision 1.7 diff -u -r1.5 -r1.7 --- palm/Palm-Keyring/lib/Palm/Keyring.pm 2006/11/10 04:52:27 1.5 +++ palm/Palm-Keyring/lib/Palm/Keyring.pm 2006/11/10 16:45:42 1.7 @@ -8,8 +8,8 @@ # # This started as Memo.pm, I just made it work for Keyring. # -# $Id: Keyring.pm,v 1.5 2006/11/10 04:52:27 andrew Exp $ -# $RedRiver: Keyring.pm,v 1.4 2006/11/10 04:21:17 andrew Exp $ +# $Id: Keyring.pm,v 1.7 2006/11/10 16:45:42 andrew Exp $ +# $RedRiver: Keyring.pm,v 1.6 2006/11/10 16:18:59 andrew Exp $ use strict; package Palm::Keyring; @@ -27,7 +27,7 @@ # One liner, to allow MakeMaker to work. -$VERSION = do { my @r = (q$Revision: 1.5 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; +$VERSION = do { my @r = (q$Revision: 1.7 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; @ISA = qw( Palm::StdAppInfo Palm::Raw ); @@ -92,7 +92,7 @@ 'private' => 1, 'Secret' => 1, 'Dirty' => 1, - 'dirty' => 1 + 'dirty' => 1, }, }, ]; @@ -115,26 +115,29 @@ my $self = shift; $self->SUPER::Load(@_); - # Skip the first 2 records because they are special - # and don't have any plaintext - my $skip = 0; foreach my $record (@{ $self->{records} }) { - if ($skip < 2) { - $skip++; - next; - } + next unless exists $record->{data}; my ($name, $encrypted) = split /\000/, $record->{data}, 2; + next unless $encrypted; $record->{plaintext}->{name} = $name; $record->{encrypted} = $encrypted; } 1; } +sub Write +{ + my $self = shift; + $self->Encrypt() || return undef; + return $self->SUPER::Load(@_); +} + sub Encrypt { my $self = shift; my $pass = shift; + if ($pass) { unless ($self->_keyring_verify($pass) ) { # This would encrypt with a new password. @@ -144,24 +147,24 @@ } } - my $seen_enc_pass = 0; - foreach my $record (@{ $self->{records} }) { - unless ($seen_enc_pass) { - $seen_enc_pass = 1; - next; - } + $self->{digest} ||= _calc_keys($self->{password}); + foreach my $record (@{ $self->{records} }) { next unless defined $record->{plaintext}; - my $name = defined $record->{plaintext}->{name} ? $record->{plaintext}->{name} : ''; - my $account = defined $record->{plaintext}->{account} ? $record->{plaintext}->{account} : ''; - my $password = defined $record->{plaintext}->{password} ? $record->{plaintext}->{password} : ''; - my $description = defined $record->{plaintext}->{description} ? $record->{plaintext}->{description} : ''; + my $name = defined $record->{plaintext}->{name} ? + $record->{plaintext}->{name} : ''; + my $account = defined $record->{plaintext}->{account} ? + $record->{plaintext}->{account} : ''; + my $password = defined $record->{plaintext}->{password} ? + $record->{plaintext}->{password} : ''; + my $description = defined $record->{plaintext}->{description} ? + $record->{plaintext}->{description} : ''; my $extra = ''; my $plaintext = join("\000", $account, $password, $description, $extra); - my $encrypted = $self->_crypt3des($plaintext, ENCRYPT); + my $encrypted = _crypt3des($plaintext, $self->{digest}, ENCRYPT); $record->{data} = join("\000", $name, $encrypted); } @@ -178,36 +181,37 @@ $self->_keyring_verify($pass) || return undef; } - my $seen_enc_pass = 0; - foreach my $record (@{ $self->{records} }) { - unless ($seen_enc_pass) { - # need to skip the first record because it is the encrypted password - $seen_enc_pass = 1; - next; - } + $self->{digest} ||= _calc_keys($self->{password}); + foreach my $record (@{ $self->{records} }) { next unless defined $record->{data}; my ($name, $encrypted) = split /\000/, $record->{data}, 2; + next unless $encrypted; + $record->{plaintext}->{name} = $name; - my $decrypted = $self->_crypt3des($encrypted, DECRYPT); + my $decrypted = _crypt3des($encrypted, $self->{digest}, DECRYPT); my ($account, $password, $description, $extra) = split /\000/, $decrypted, 4; - $record->{plaintext}->{account} = defined $account ? $account : ''; - $record->{plaintext}->{password} = defined $password ? $password : ''; - $record->{plaintext}->{description} = defined $description ? $description : ''; + $record->{plaintext}->{account} = defined $account ? + $account : ''; + $record->{plaintext}->{password} = defined $password ? + $password : ''; + $record->{plaintext}->{description} = defined $description ? + $description : ''; - #print "Name: '$name'\n"; - #print "Encrypted: '$encrypted' - Length: " . length($encrypted) . "\n"; - #print "Hex: '" . unpack("H*", $encrypted) . "'\n"; - #print "Binary: '" . unpack("b*", $encrypted) . "'\n"; - #print "Decrypted: '$decrypted' - Length: " . length($decrypted) . "\n"; - #print "Hex: '" . unpack("H*", $decrypted) . "'\n"; - #print "Binary: '" . unpack("b*", $decrypted) . "'\n"; - #print "\n"; + #print "Name: '$name'\n"; + #print "Encrypted: '$encrypted' - Length: " . length($encrypted) . "\n"; + #print " Hex: '" . unpack("H*", $encrypted) . "'\n"; + #print " Binary:'" . unpack("b*", $encrypted) . "'\n"; + #print "Decrypted: '$decrypted' - Length: " . length($decrypted) . "\n"; + #print " Hex: '" . unpack("H*", $decrypted) . "'\n"; + #print " Binary:'" . unpack("b*", $decrypted) . "'\n"; + #print "\n"; #print "Extra: $extra\n"; + #exit; #-------------------------------------------------- # print "Account: $account\n"; # print "Password: $password\n"; @@ -221,9 +225,7 @@ sub _calc_keys { - my $self = shift; - - my $pass = $self->{'password'}; + my $pass = shift; die "No password defined!" unless defined $pass; my $digest = md5($pass); @@ -240,7 +242,6 @@ # print length $digest, "\n"; #-------------------------------------------------- - $self->{digest} = $digest; return $digest; } @@ -254,7 +255,7 @@ # AFAIK the thing we use to test the password is # always in the first entry - my $data = $self->{records}->[0]->{data}; + my $data = $self->{records}->[1]->{data}; #die "No encrypted password in file!" unless defined $data; return undef unless defined $data; @@ -270,7 +271,8 @@ if ($data eq $salt . $digest) { # May as well generate the keys we need now, since we know the password is right - if ($self->_calc_keys()) { + $self->{digest} = _calc_keys($self->{password}); + if ($self->{digest}) { return 1; } else { return undef; @@ -292,7 +294,7 @@ die "No password specified!" unless $pass; # if the database already has a password in it - if ($self->{records}->[0]->{data}) { + if ($self->{records}->[1]->{data}) { # Make sure everything is decrypted before we update the keyring $self->Decrypt() || return undef; } @@ -312,10 +314,10 @@ # AFAIK the thing we use to test the password is # always in the first entry - $self->{records}->[0]->{data} = $data; + $self->{records}->[1]->{data} = $data; $self->{password} = $pass; - $self->_calc_keys(); + $self->{digest} = _calc_keys($self->{password}); return 1; } @@ -324,9 +326,8 @@ # XXX Have to make this encrypt as well as decrypting, but w00 h00! # do null padding on the end of a cleartext if we are going to encrypt it sub _crypt3des { - my ( $self, $plaintext, $flag ) = @_; + my ( $plaintext, $passphrase, $flag ) = @_; - my $passphrase = $self->{digest} || $self->_calc_keys(); $passphrase .= ' ' x (16*3); my $cyphertext = "";