[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.29 and 1.32

version 1.29, 2007/02/19 00:22:42 version 1.32, 2007/02/19 03:33:56
Line 1 
Line 1 
 package Palm::Keyring;  package Palm::Keyring;
 # $RedRiver: Keyring.pm,v 1.28 2007/02/18 05:50:25 andrew Exp $  # $RedRiver: Keyring.pm,v 1.31 2007/02/19 02:55:35 andrew Exp $
 ########################################################################  ########################################################################
 # Keyring.pm *** Perl class for Keyring for Palm OS databases.  # Keyring.pm *** Perl class for Keyring for Palm OS databases.
 #  #
Line 16 
Line 16 
 use warnings;  use warnings;
   
 use Carp;  use Carp;
 use Data::Dumper;  
   
 use base qw/ Palm::StdAppInfo /;  use base qw/ Palm::StdAppInfo /;
   
 use Digest::HMAC_SHA1 qw(hmac_sha1);  
 use Digest::SHA1 qw(sha1);  
 use Crypt::CBC;  
   
 use Digest::MD5 qw(md5);  
 use Crypt::DES;  
   
 my $ENCRYPT    = 1;  my $ENCRYPT    = 1;
 my $DECRYPT    = 0;  my $DECRYPT    = 0;
 my $MD5_CBLOCK = 64;  my $MD5_CBLOCK = 64;
Line 154 
Line 146 
     } elsif ($self->{version} == 5) {      } elsif ($self->{version} == 5) {
         my $blocksize = $CRYPTS[ $self->{appinfo}->{cipher} ]{blocksize};          my $blocksize = $CRYPTS[ $self->{appinfo}->{cipher} ]{blocksize};
         my ($field, $extra) = _parse_field($rec->{data});          my ($field, $extra) = _parse_field($rec->{data});
         my ($ivec, $encrypted) = unpack "A$blocksize A*", $extra;          my $ivec      = substr $extra, 0, $blocksize;
           my $encrypted = substr $extra, $blocksize;
   
         if ($self->{options}->{v4compatible}) {          $rec->{name}      = $field->{data};
             $rec->{name} = $field->{data};  
         } else {  
             $rec->{name} = $field;  
         }  
         $rec->{ivec}      = $ivec;          $rec->{ivec}      = $ivec;
         $rec->{encrypted} = $encrypted;          $rec->{encrypted} = $encrypted;
   
Line 190 
Line 179 
         }          }
   
     } elsif ($self->{version} == 5) {      } elsif ($self->{version} == 5) {
         my $field;          my $field = {
         if ($rec->{name}) {              'label_id' => 1,
             if ($self->{options}->{v4compatible}) {              'data'     => $rec->{name},
                 $field = {              'font'     => 0,
                     label    => 'name',          };
                     font     => 0,          my $packed .= _pack_field($field);
                     data     => $rec->{'name'},  
                 };  
             } else {  
                 $field = $rec->{name};  
             }  
         }  
         my $packed = '';  
         if ($field) {  
             $packed = _pack_field($field);  
         }  
         my $len = length $packed;  
         my $blocksize = $CRYPTS[ $self->{appinfo}->{cipher} ]{blocksize};  
   
         $rec->{data} = pack "A$len A$blocksize A*",          $rec->{data} = join '', $packed, $rec->{ivec}, $rec->{encrypted};
             $packed, $rec->{ivec}, $rec->{encrypted};  
   
     } else {      } else {
         die 'Unsupported Version';          die 'Unsupported Version';
Line 408 
Line 384 
   
 sub _encrypt_v4  sub _encrypt_v4
 {  {
       require Crypt::CBC;
   
     my $new    = shift;      my $new    = shift;
     my $old    = shift;      my $old    = shift;
     my $digest = shift;      my $digest = shift;
Line 481 
Line 459 
     my $old    = shift;      my $old    = shift;
     my $key    = shift;      my $key    = shift;
     my $cipher = shift;      my $cipher = shift;
     my $ivec   = shift || pack("C*",map {rand(256)} 1..8);      my $length = $CRYPTS[ $cipher ]{blocksize};
       my $ivec   = shift || pack("C*",map {rand(256)} 1..$length);
   
     my $keylen      = $CRYPTS[ $cipher ]{keylen};      my $keylen      = $CRYPTS[ $cipher ]{keylen};
     my $cipher_name = $CRYPTS[ $cipher ]{name};      my $cipher_name = $CRYPTS[ $cipher ]{name};
Line 580 
Line 559 
   
 # Decrypt  # Decrypt
   
 sub Decrypt  sub Decrypt
 {  {
     my $self = shift;      my $self = shift;
     my $rec  = shift;      my $rec  = shift;
Line 594 
Line 573 
         croak("Needed parameter 'record' not passed!\n");          croak("Needed parameter 'record' not passed!\n");
     }      }
   
     if ( ! $self->Password($pass)) {      if ( $pass && ! $self->Password($pass)) {
         croak("Invalid Password!\n");          croak("Invalid Password!\n");
     }      }
   
Line 654 
Line 633 
   
 sub _decrypt_v5  sub _decrypt_v5
 {  {
       require Crypt::CBC;
     my $encrypted = shift;      my $encrypted = shift;
     my $key       = shift;      my $key       = shift;
     my $cipher    = shift;      my $cipher    = shift;
Line 713 
Line 693 
   
     if (! $pass) {      if (! $pass) {
         delete $self->{password};          delete $self->{password};
         delete $self->{key};          delete $self->{appinfo}->{key};
         return 1;          return 1;
     }      }
   
Line 791 
Line 771 
   
 sub _password_verify_v4  sub _password_verify_v4
 {  {
       require Digest::MD5;
       import Digest::MD5 qw(md5);
   
     my $pass = shift;      my $pass = shift;
     my $data = shift;      my $data = shift;
   
Line 891 
Line 874 
   
 sub _password_update_v4  sub _password_update_v4
 {  {
       require Digest::MD5;
       import Digest::MD5 qw(md5);
   
     my $pass = shift;      my $pass = shift;
   
     if (! defined $pass) { croak('No password specified!'); };      if (! defined $pass) { croak('No password specified!'); };
Line 968 
Line 954 
 {  {
     my ($pass, $salt, $iter, $keylen, $dop) = @_;      my ($pass, $salt, $iter, $keylen, $dop) = @_;
   
       require Digest::HMAC_SHA1;
       import  Digest::HMAC_SHA1 qw(hmac_sha1);
       require Digest::SHA1;
       import  Digest::SHA1 qw(sha1);
   
     my $key = _pbkdf2( $pass, $salt, $iter, $keylen, \&hmac_sha1 );      my $key = _pbkdf2( $pass, $salt, $iter, $keylen, \&hmac_sha1 );
     if ($dop) { $key = DES_odd_parity($key); }      if ($dop) { $key = DES_odd_parity($key); }
   
Line 978 
Line 969 
   
 sub _crypt3des  sub _crypt3des
 {  {
       require Crypt::DES;
   
     my ( $plaintext, $passphrase, $flag ) = @_;      my ( $plaintext, $passphrase, $flag ) = @_;
   
     $passphrase   .= $SPACE x ( 16 * 3 );      $passphrase   .= $SPACE x ( 16 * 3 );
Line 1041 
Line 1034 
         return undef, $field;          return undef, $field;
     }      }
     my $unpackstr = "S1 C1 C1 A$len";      my $unpackstr = "S1 C1 C1 A$len";
     if ($len % 2) {      if ($len % 2 && $len + 4 < length $field) {
         # trim the 0/1 byte padding for next even address.          # trim the 0/1 byte padding for next even address.
         $unpackstr .= ' x'          $unpackstr .= ' x'
     }      }
Line 1227 
Line 1220 
   
 1;  1;
 __END__  __END__
   
 =head1 NAME  =head1 NAME
   
 Palm::Keyring - Handler for Palm Keyring databases.  Palm::Keyring - Handler for Palm Keyring databases.
Line 1241 
Line 1233 
 It has the standard Palm::PDB methods with 2 additional public methods.  It has the standard Palm::PDB methods with 2 additional public methods.
 Decrypt and Encrypt.  Decrypt and Encrypt.
   
 It currently supports the v4 Keyring databases.  The v5 databases from  It currently supports the v4 Keyring databases.
 the pre-release keyring-2.0 are not supported.  The pre-release v5 databases are mostly supported.  There are definitely some
   bugs,  For example, t/keyring5.t sometimes fails.  I am not sure why yet.
   
 This module doesn't store the decrypted content.  It only keeps it until it  This module doesn't store the decrypted content.  It only keeps it until it
 returns it to you or encrypts it.  returns it to you or encrypts it.
Line 1258 
Line 1251 
     $pdb->Load($file);      $pdb->Load($file);
   
     foreach (0..$#{ $pdb->{records} }) {      foreach (0..$#{ $pdb->{records} }) {
         next if $_ = 0; # skip the password record          # skip the password record for version 4 databases
           next if $_ == 0 && $pdb->{version} == 4;
         my $rec  = $pdb->{records}->[$_];          my $rec  = $pdb->{records}->[$_];
         my $acct = $pdb->Decrypt($rec, $pass);          my $acct = $pdb->Decrypt($rec, $pass);
         print $rec->{name}, ' - ', $acct->{account}, "\n";          print $rec->{name}, ' - ', $acct->{account}, "\n";
Line 1268 
Line 1262 
   
 =head2 new  =head2 new
   
     $pdb = new Palm::Keyring([$password]);      $pdb = new Palm::Keyring([$password[, $version]]);
   
 Create a new PDB, initialized with the various Palm::Keyring fields  Create a new PDB, initialized with the various Palm::Keyring fields
 and an empty record list.  and an empty record list.
Line 1279 
Line 1273 
 If you pass in a password, it will initalize the first record with the encrypted  If you pass in a password, it will initalize the first record with the encrypted
 password.  password.
   
   new() now also takes options in other formats
   
       $pdb = new Palm::Keyring({ key1 => value1,  key2 => value2 });
       $pdb = new Palm::Keyring( -key1 => value1, -key2 => value2);
   
   =head3 Supported options are:
   
   =over
   
   =item password
   
   The password used to initialize the database
   
   =item version
   
   The version of database to create.  Accepts either 4 or 5.  Currently defaults to 4.
   
   =item v4compatible
   
   The format of the fields passed to Encrypt and returned from Decrypt have changed.
   This allows programs to use the newer databases with few changes but with less features.
   
   =item cipher
   
   The cipher to use.  0, 1, 2 or 3.
   
       0 => None
       1 => DES_EDE3
       2 => AES128
       3 => AES256
   
   =item iterations
   
   The number of iterations to encrypt with.
   
   =back
   
 =head2 Encrypt  =head2 Encrypt
   
     $pdb->Encrypt($rec, $acct[, $password]);      $pdb->Encrypt($rec, $acct[, $password]);
Line 1287 
Line 1318 
 used, or with a password that is passed.  used, or with a password that is passed.
   
 $rec is a record from $pdb->{records} or a new_Record().  $rec is a record from $pdb->{records} or a new_Record().
 $acct is a hashref in the format below.  The v4 $acct is a hashref in the format below.
   
     my $acct = {      my $v4acct = {
         name       => $rec->{name},          name       => $rec->{name},
         account    => $account,          account    => $account,
         password   => $password,          password   => $password,
Line 1301 
Line 1332 
         },          },
     };      };
   
   The v5 $acct is an arrayref full of hashrefs that contain each encrypted field.
   
       my $v5acct = [
           {
               'label_id' => 2,
               'data' => 'abcd1234',
               'label' => 'password',
               'font' => 0
           },
           {
               'label_id' => 3,
               'data' => {
                   'month' => 1,
                   'day' => 11,
                   'year' => 107
               },
               'label' => 'lastchange',
               'font' => 0
           },
           {
               'label_id' => 255,
               'data' => 'This is a short note.',
               'label' => 'notes',
               'font' => 0
           }
       ];
   
   
   The account name is stored in $rec->{name} for both v4 and v5 databases.
   It is not returned in the decrypted information for v5.
   
       $rec->{name} = 'account name';
   
 If you have changed anything other than the lastchange, or don't pass in a  If you have changed anything other than the lastchange, or don't pass in a
 lastchange key, Encrypt() will generate a new lastchange date for you.  lastchange key, Encrypt() will generate a new lastchange date for you.
   
Line 1313 
Line 1377 
   
     my $acct = $pdb->Decrypt($rec[, $password]);      my $acct = $pdb->Decrypt($rec[, $password]);
   
 Decrypts the record and returns a hashref for the account as described  Decrypts the record and returns a reference for the account as described
 under Encrypt().  under Encrypt().
   
     foreach (0..$#{ $pdb->{records}) {      foreach (0..$#{ $pdb->{records}) {
         next if $_ == 0;          next if $_ == 0 && $pdb->{version} == 4;
         my $rec = $pdb->{records}->[$_];          my $rec = $pdb->{records}->[$_];
         my $acct = $pdb->Decrypt($rec[, $password]);          my $acct = $pdb->Decrypt($rec);
         # do something with $acct          # do something with $acct
     }      }
   
   
 =head2 Password  =head2 Password
   
     $pdb->Password([$password[, $new_password]]);      $pdb->Password([$password[, $new_password]]);
Line 1386 
Line 1451 
   
 The Keyring for Palm OS website:  The Keyring for Palm OS website:
 L<http://gnukeyring.sourceforge.net/>  L<http://gnukeyring.sourceforge.net/>
   
   The HACKING guide for palm keyring databases:
   L<http://gnukeyring.cvs.sourceforge.net/*checkout*/gnukeyring/keyring/HACKING>
   
 Johan Vromans also has a wxkeyring app that now uses this module, available  Johan Vromans also has a wxkeyring app that now uses this module, available
 from his website at L<http://www.vromans.org/johan/software/sw_palmkeyring.html>  from his website at L<http://www.vromans.org/johan/software/sw_palmkeyring.html>

Legend:
Removed from v.1.29  
changed lines
  Added in v.1.32

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