[BACK]Return to Keyring.pm CVS log [TXT][DIR] Up to [local] / palm / Palm-Keyring / lib / Palm

Diff for /palm/Palm-Keyring/lib/Palm/Keyring.pm between version 1.47 and 1.48

version 1.47, 2007/09/12 01:30:10 version 1.48, 2007/09/12 03:44:36
Line 1 
Line 1 
 package Palm::Keyring;  package Palm::Keyring;
 # $RedRiver: Keyring.pm,v 1.46 2007/08/10 04:13:31 andrew Exp $  # $RedRiver: Keyring.pm,v 1.47 2007/09/12 00:30:10 andrew Exp $
 ########################################################################  ########################################################################
 # Keyring.pm *** Perl class for Keyring for Palm OS databases.  # Keyring.pm *** Perl class for Keyring for Palm OS databases.
 #  #
Line 249 
Line 249 
         my ( $name, $encrypted ) = split /$NULL/xm, $rec->{data}, 2;          my ( $name, $encrypted ) = split /$NULL/xm, $rec->{data}, 2;
   
         return $rec if ! $encrypted;          return $rec if ! $encrypted;
         $rec->{decrypted}->{0} = {          $rec->{plaintext}->{0} = {
             label => 'name',              label => 'name',
             label_id => 0,              label_id => 0,
             data  => $name,              data  => $name,
Line 265 
Line 265 
         my ($field, $extra) = _parse_field($rec->{data});          my ($field, $extra) = _parse_field($rec->{data});
         delete $rec->{data};          delete $rec->{data};
   
         $rec->{decrypted}->{0} = $field;          $rec->{plaintext}->{0} = $field;
         $rec->{ivec}      = substr $extra, 0, $blocksize;          $rec->{ivec}      = substr $extra, 0, $blocksize;
         $rec->{encrypted} = substr $extra, $blocksize;          $rec->{encrypted} = substr $extra, $blocksize;
   
Line 286 
Line 286 
   
     if ($self->{version} == 4) {      if ($self->{version} == 4) {
         if ($rec->{encrypted}) {          if ($rec->{encrypted}) {
             my $name = $rec->{decrypted}->{0}->{data} || $EMPTY;              my $name = $rec->{plaintext}->{0}->{data} || $EMPTY;
             $rec->{data} = join $NULL, $name, $rec->{encrypted};              $rec->{data} = join $NULL, $name, $rec->{encrypted};
             delete $rec->{decrypted};              delete $rec->{plaintext};
             delete $rec->{encrypted};              delete $rec->{encrypted};
         }          }
   
     } elsif ($self->{version} == 5) {      } elsif ($self->{version} == 5) {
         my $field;          my $field;
         if ($rec->{decrypted}->{0}) {          if ($rec->{plaintext}->{0}) {
             $field = $rec->{decrypted}->{0};              $field = $rec->{plaintext}->{0};
         } else {          } else {
             $field = {              $field = {
                 'label'    => 'name',                  'label'    => 'name',
Line 422 
Line 422 
 {  {
     my $self = shift;      my $self = shift;
     my $rec  = shift;      my $rec  = shift;
     my $data = shift;  
     my $pass = shift || $self->{password};      my $pass = shift || $self->{password};
       my $data = shift || $rec->{plaintext};
     my $ivec = shift;      my $ivec = shift;
   
     if ( ! $pass && ! $self->{appinfo}->{key}) {      if ( ! $pass && ! $self->{appinfo}->{key}) {
Line 435 
Line 435 
     }      }
   
     if ( ! $data) {      if ( ! $data) {
         croak("Needed parameter 'data' not passed!\n");          croak("Needed 'plaintext' not passed!\n");
     }      }
   
     if ( $pass && ! $self->Password($pass)) {      if ( $pass && ! $self->Password($pass)) {
Line 481 
Line 481 
         croak "Unsupported Version $self->{version}";          croak "Unsupported Version $self->{version}";
     }      }
   
     $rec->{decrypted}->{0} = $data->{0};      $rec->{plaintext}->{0} = $data->{0};
   
     if ($encrypted) {      if ($encrypted) {
         if ($encrypted eq '1') {          if ($encrypted eq '1') {
Line 629 
Line 629 
         }          }
     }      }
   
     my $decrypted;      my $plaintext;
     foreach my $k (keys %{ $new }) {      foreach my $k (keys %{ $new }) {
         $decrypted .= _pack_field($new->{$k});          $plaintext .= _pack_field($new->{$k});
     }      }
   
     my $encrypted;      my $encrypted;
     if ($c->{name} eq 'None') {      if ($c->{name} eq 'None') {
         # do nothing          # do nothing
         $encrypted = $decrypted;          $encrypted = $plaintext;
   
     } elsif ($c->{name} eq 'DES_EDE3' or $c->{name} eq 'Rijndael') {      } elsif ($c->{name} eq 'DES_EDE3' or $c->{name} eq 'Rijndael') {
         require Crypt::CBC;          require Crypt::CBC;
Line 656 
Line 656 
             croak("Unable to set up encryption!");              croak("Unable to set up encryption!");
         }          }
   
         $encrypted = $cbc->encrypt($decrypted);          $encrypted = $cbc->encrypt($plaintext);
   
     } else {      } else {
         croak "Unsupported Crypt $c->{name}";          croak "Unsupported Crypt $c->{name}";
Line 689 
Line 689 
         croak("No encrypted content!");          croak("No encrypted content!");
     }      }
   
       my $plaintext;
     if ($self->{version} == 4) {      if ($self->{version} == 4) {
         $self->{digest} ||= _calc_keys( $pass );          $self->{digest} ||= _calc_keys( $pass );
         my $acct = _decrypt_v4($rec->{encrypted}, $self->{digest});          my $acct = _decrypt_v4($rec->{encrypted}, $self->{digest});
         return {          $plaintext = {
             0 => $rec->{decrypted}->{0},              0 => $rec->{plaintext}->{0},
             1 => {              1 => {
                 label    => 'account',                  label    => 'account',
                 label_id => 1,                  label_id => 1,
Line 721 
Line 722 
         };          };
   
     } elsif ($self->{version} == 5) {      } elsif ($self->{version} == 5) {
         my $decrypted = _decrypt_v5(          $plaintext = _decrypt_v5(
             $rec->{encrypted}, $self->{appinfo}->{key},              $rec->{encrypted}, $self->{appinfo}->{key},
             $self->{appinfo}->{cipher}, $rec->{ivec},              $self->{appinfo}->{cipher}, $rec->{ivec},
         );          );
         $decrypted->{0} ||= $rec->{decrypted}->{0};          $plaintext->{0} ||= $rec->{plaintext}->{0};
         return $decrypted;  
   
     } else {      } else {
         croak "Unsupported Version $self->{version}";          croak "Unsupported Version $self->{version}";
     }      }
   
       if ($plaintext) {
           $rec->{plaintext} = $plaintext;
           return $plaintext;
       }
     return;      return;
 }  }
   
Line 739 
Line 744 
     my $encrypted = shift;      my $encrypted = shift;
     my $digest    = shift;      my $digest    = shift;
   
     my $decrypted = _crypt3des( $encrypted, $digest, $DECRYPT );      my $plaintext = _crypt3des( $encrypted, $digest, $DECRYPT );
     my ( $account, $password, $notes, $packed_date )      my ( $account, $password, $notes, $packed_date )
         = split /$NULL/xm, $decrypted, 4;          = split /$NULL/xm, $plaintext, 4;
   
     my $modified;      my $modified;
     if ($packed_date) {      if ($packed_date) {
Line 766 
Line 771 
   
     my $c = crypts($cipher) or croak('Unknown cipher ' . $cipher);      my $c = crypts($cipher) or croak('Unknown cipher ' . $cipher);
   
     my $decrypted;      my $plaintext;
   
     if ($c->{name} eq 'None') {      if ($c->{name} eq 'None') {
         # do nothing          # do nothing
         $decrypted = $encrypted;          $plaintext = $encrypted;
   
     } elsif ($c->{name} eq 'DES_EDE3' or $c->{name} eq 'Rijndael') {      } elsif ($c->{name} eq 'DES_EDE3' or $c->{name} eq 'Rijndael') {
         require Crypt::CBC;          require Crypt::CBC;
Line 790 
Line 795 
         }          }
         my $len = $c->{blocksize} - length($encrypted) % $c->{blocksize};          my $len = $c->{blocksize} - length($encrypted) % $c->{blocksize};
         $encrypted .= $NULL x $len;          $encrypted .= $NULL x $len;
         $decrypted  = $cbc->decrypt($encrypted);          $plaintext  = $cbc->decrypt($encrypted);
   
     } else {      } else {
         croak "Unsupported Crypt $c->{name}";          croak "Unsupported Crypt $c->{name}";
     }      }
   
     my %fields;      my %fields;
     while ($decrypted) {      while ($plaintext) {
         my $field;          my $field;
         ($field, $decrypted) = _parse_field($decrypted);          ($field, $plaintext) = _parse_field($plaintext);
         if (! $field) {          if (! $field) {
             last;              last;
         }          }
Line 835 
Line 840 
         foreach my $rec (@{ $self->{records} }) {          foreach my $rec (@{ $self->{records} }) {
             my $acct = $self->Decrypt($rec, $pass);              my $acct = $self->Decrypt($rec, $pass);
             if ( ! $acct ) {              if ( ! $acct ) {
                 croak("Couldn't decrypt $rec->{decrypted}->{0}->{data}");                  croak("Couldn't decrypt $rec->{plaintext}->{0}->{data}");
             }              }
             push @accts, $acct;              push @accts, $acct;
         }          }
Line 847 
Line 852 
   
         foreach my $i (0..$#accts) {          foreach my $i (0..$#accts) {
             delete $self->{records}->[$i]->{encrypted};              delete $self->{records}->[$i]->{encrypted};
             $self->Encrypt($self->{records}->[$i], $accts[$i], $pass);              $self->{records}->[$i]->{plaintext} = $accts[$i];
               $self->Encrypt($self->{records}->[$i], $pass);
         }          }
     }      }
   
Line 1037 
Line 1043 
     return $key;      return $key;
 }  }
   
   sub Unlock
   {
       my $self = shift;
       my ($pass) = @_;
       $pass ||= $self->{password};
   
       if ( $pass && ! $self->Password($pass)) {
           croak("Invalid Password!\n");
       }
   
       foreach my $rec (@{ $self->{records} }) {
           $self->Decrypt($rec);
       }
   
       return 1;
   
   }
   
   sub Lock
   {
       my $self = shift;
   
       $self->Password();
   
       foreach my $rec (@{ $self->{records} }) {
           my $name = $rec->{plaintext}->{0};
           delete $rec->{plaintext};
           $rec->{plaintext}->{0} = $name;
       }
   
       return 1;
   }
   
 # Helpers  # Helpers
   
 sub _calc_keys  sub _calc_keys
Line 1360 
Line 1399 
 for accessing v5 databases, so any suggestions on improvements on  for accessing v5 databases, so any suggestions on improvements on
 the interface are appreciated.  the interface are appreciated.
   
 This module doesn't store the decrypted content.  It only keeps it until it  This module doesn't store the plaintext content.  It only keeps it until it
 returns it to you or encrypts it.  returns it to you or encrypts it.
   
 =head1 SYNOPSIS  =head1 SYNOPSIS
Line 1374 
Line 1413 
     $pdb->Load($file);      $pdb->Load($file);
   
     foreach my $rec (@{ $pdb->{records} }) {      foreach my $rec (@{ $pdb->{records} }) {
         my $acct = $pdb->Decrypt($rec, $pass);          my $plaintext = $pdb->Decrypt($rec, $pass);
         print $acct->{0}->{data}, ' - ', $acct->{1}->{data}, "\n";          print $plaintext->{0}->{data}, ' - ', $plaintext->{1}->{data}, "\n";
     }      }
   
 =head1 SUBROUTINES/METHODS  =head1 SUBROUTINES/METHODS
Line 1492 
Line 1531 
   
 =head2 Encrypt  =head2 Encrypt
   
     $pdb->Encrypt($rec, $acct[, $password[, $ivec]]);      $pdb->Encrypt($rec[, $password[, $plaintext[, $ivec]]]);
   
 Encrypts an account into a record, either with the password previously  Encrypts an account into a record, either with the password previously
 used, or with a password that is passed.  used, or with a password that is passed.
Line 1502 
Line 1541 
 randomly.  randomly.
   
 $rec is a record from $pdb->{records} or a new_Record().  $rec is a record from $pdb->{records} or a new_Record().
 The $acct is a hashref in the format below.  $rec->{plaintext} is a hashref in the format below.
   
     my $acct = {      $plaintext = {
         0 => {          0 => {
             label    => 'name',              label    => 'name',
             label_id => 0,              label_id => 0,
Line 1536 
Line 1575 
         },          },
     };      };
   
 The account name is also stored in $rec->{decrypted}->{0}->{data} for both v4  The account name is also stored in $rec->{plaintext}->{0}->{data} for both v4
 and v5 databases.  and v5 databases.
   
     $rec->{decrypted}->{0} => {      $rec->{plaintext}->{0} => {
         label    => 'name',          label    => 'name',
         label_id => 0,          label_id => 0,
         font     => 0,          font     => 0,
Line 1552 
Line 1591 
 If you pass in a lastchange field that is different than the one in the  If you pass in a lastchange field that is different than the one in the
 record, it will honor what you passed in.  record, it will honor what you passed in.
   
   You can either set $rec->{plaintext} or pass in $plaintext.  $plaintext
   is used over anything in $rec->{plaintext}.
   
   
 =head2 Decrypt  =head2 Decrypt
   
     my $acct = $pdb->Decrypt($rec[, $password]);      my $plaintext = $pdb->Decrypt($rec[, $password]);
   
 Decrypts the record and returns a reference for the account as described  Decrypts the record and returns a reference for the plaintext account as
 under Encrypt().  described under L<Encrypt>.
   Also sets $rec->{plaintext} with the same information as $plaintext as
   described in L<Encrypt>.
   
     foreach my $rec (@{ $pdb->{records} }) {      foreach my $rec (@{ $pdb->{records} }) {
         my $acct = $pdb->Decrypt($rec);          my $plaintext = $pdb->Decrypt($rec);
         # do something with $acct          # do something with $plaintext
     }      }
   
   
Line 1602 
Line 1646 
                       or calculated when setting a new password.                        or calculated when setting a new password.
     };      };
   
   =head2 Unlock
   
       $pdb->Unlock([$password]);
   
   Decrypts all the records.  Sets $rec->{plaintext} for all records.
   
   This makes it easy to show all decrypted information.
   
      my $pdb = Palm::KeyRing->new();
      $pdb->Load($keyring_file);
      $pdb->Unlock($password);
      foreach my $plaintext (map { $_->{plaintext} } @{ $pdb->{records} }) {
          # Do something like display the account.
      }
      $pdb->Lock();
   
   =head2 Lock
   
       $pdb->Lock();
   
   Unsets $rec->{plaintext} for all records and unsets the saved password.
   
   This does NOT L<Encrypt> any of the records before clearing them, so if
   you are not careful you will lose information.
   
   B<CAVEAT!> This only does "delete $rec->{plaintext}" and the same for the
   password.  If someone knows of a cross platform reliable way to make
   sure that the information is actually cleared from memory I would
   appreciate it.  Also, if someone knows how to make sure that the stuff
   in $rec->{plaintext} is not written to swap, that would be very handy as
   well.
   
 =head2 Other overridden subroutines/methods  =head2 Other overridden subroutines/methods
   
 =over  =over
Line 1700 
Line 1776 
   
 I am not very happy with the data structures used by Encrypt() and  I am not very happy with the data structures used by Encrypt() and
 Decrypt() for v5 databases, but I am not sure of a better way.  Decrypt() for v5 databases, but I am not sure of a better way.
   
 The v4 compatibility mode does not insert a fake record 0 where  
 normally the encrypted password is stored.  
   
 The date validation for packing new dates is very poor.  The date validation for packing new dates is very poor.
   

Legend:
Removed from v.1.47  
changed lines
  Added in v.1.48

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>