[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.1 and 1.12

version 1.1, 2006/01/26 20:54:19 version 1.12, 2007/01/28 00:18:46
Line 8 
Line 8 
 #  #
 #   This started as Memo.pm, I just made it work for Keyring.  #   This started as Memo.pm, I just made it work for Keyring.
 #  #
 # $Id$  # $RedRiver: Keyring.pm,v 1.11 2007/01/27 23:59:29 andrew Exp $
 # $RedRiver$  
   
 use strict;  use strict;
 package Palm::Keyring;  package Palm::Keyring;
Line 18 
Line 17 
 use vars qw( $VERSION @ISA );  use vars qw( $VERSION @ISA );
   
 use Digest::MD5 qw(md5);  use Digest::MD5 qw(md5);
 use Crypt::TripleDES;  use Crypt::DES;
   
 use constant ENCRYPT    =>  1;  use constant ENCRYPT    =>  1;
 use constant DECRYPT    =>  0;  use constant DECRYPT    =>  0;
Line 37 
Line 36 
   
 =head1 SYNOPSIS  =head1 SYNOPSIS
   
     use Palm::Keyring;          use Palm::PDB;
         $pdb->Decrypt('mypassword');          use Palm::Keyring;
           my $pdb = new Palm::PDB;
           $pdb->Load($file);
           foreach my $record (@{ $pdb->{'records'} }) {
                   print "$record->{'plaintext'}->{'name'}\n";
           }
           $pdb->Decrypt($password);
           # do something with the decrypted parts
   
 =head1 DESCRIPTION  =head1 DESCRIPTION
   
 The Keyring PDB handler is a helper class for the Palm::PDB package. It  The Keyring PDB handler is a helper class for the Palm::PDB package. It
 parses Keyring databases.  See  parses Keyring for Palm OS databases.  See
 L<http://gnukeyring.sourceforge.net/>.  L<http://gnukeyring.sourceforge.net/>.
   
 It is just the standard Palm::Raw with 2 additional public methods.  Decrypt and Encrypt.  It has the standard Palm::PDB methods with 2 additional public methods.
   Decrypt and Encrypt.
   
   It currently supports the v4 Keyring databases.  The v5 databases from the pre-release keyring-2.0 are not supported.
   
 =cut  =cut
   
 =head2 new  =head2 new
   
   $pdb = new Palm::Keyring ('password');          $pdb = new Palm::Keyring([$password]);
   
 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.
   
 Use this method if you're creating a Keyring PDB from scratch.  Use this method if you're creating a Keyring PDB from scratch otherwise you
   can just use Palm::PDB::new().
   
 =cut  =cut
 #'  
 sub new  sub new
 {  {
         my $classname   = shift;          my $classname   = shift;
         my $pass = shift;          my $pass = shift;
   
           # Create a generic PDB. No need to rebless it, though.
         my $self        = $classname->SUPER::new(@_);          my $self        = $classname->SUPER::new(@_);
                         # Create a generic PDB. No need to rebless it,  
                         # though.  
   
         $self->{name} = "Keys-Gtkr";    # Default          $self->{name} = "Keys-Gtkr";    # Default
         $self->{creator} = "Gtkr";          $self->{creator} = "Gtkr";
         $self->{type} = "Gkyr";          $self->{type} = "Gkyr";
           # The PDB is not a resource database by
           # default, but it's worth emphasizing,
           # since MemoDB is explicitly not a PRC.
         $self->{attributes}{resource} = 0;          $self->{attributes}{resource} = 0;
                                 # The PDB is not a resource database by  
                                 # default, but it's worth emphasizing,  
                                 # since MemoDB is explicitly not a PRC.  
   
         # Initialize the AppInfo block          # Initialize the AppInfo block
         $self->{appinfo} = {};          $self->{appinfo} = {};
Line 87 
Line 97 
         $self->{version} = 4;          $self->{version} = 4;
   
         # Give the PDB the first record that will hold the encrypted password          # Give the PDB the first record that will hold the encrypted password
         $self->{records} = [          $self->{records} = [ $self->new_Record ];
                 {  
                   'category' => 0,  
                   'attributes' => {  
                                                         'private' => 1,  
                                                         'Secret' => 1,  
                                                         'Dirty' => 1,  
                                                         'dirty' => 1  
                                                   },  
                 },  
         ];  
   
         if ($pass) {          if (defined $pass) {
                 $self->Encrypt($pass);                  $self->Encrypt($pass);
         }          }
   
Line 113 
Line 113 
                 );                  );
 }  }
   
   =pod
   
   =head2 Load
   
           $pdb->Load($filename[, $password]);
   
   Overrides the standard Palm::Raw Load() to add
   $record->{'plaintext'}->{'name'} and
   $record->{'encrypted'} fields.
   $record->{'plaintext'}->{'name'} holds the name of the record,
   $record->{'encrypted'} is the encrypted information in the PDB.
   
   It also takes an additional optional parameter, which is the password to use to
   decrypt the database.
   
   See Decrypt() for the additional fields that are available after decryption.
   
   =cut
   
   sub Load
   {
           my $self     = shift;
           my $filename = shift;
           my $password = shift;
   
           $self->{'appinfo'} = {};
           $self->{'records'} = [];
           $self->SUPER::Load($filename);
   
           foreach my $record (@{ $self->{records} }) {
                   next unless exists $record->{data};
                   my ($name, $encrypted) = split /\000/, $record->{data}, 2;
                   next unless $encrypted;
                   $record->{plaintext}->{name} = $name;
           $record->{encrypted} = $encrypted;
           }
   
           return $self->Decrypt($password) if defined $password;
   
           1;
   }
   
   =pod
   
   =head2 Write
   
           $pdb->Write($filename[, $password]);
   
   Just like the Palm::Raw::Write() but encrypts everything before saving.
   
   Also takes an optional password to encrypt with a new password, not needed
   unless you are changing the password.
   
   =cut
   
   sub Write
   {
           my $self = shift;
           my $filename = shift;
           my $password = shift;
   
           $self->Encrypt($password) || return undef;
           return $self->SUPER::Write($filename);
   }
   
   =pod
   
   =head2 Encrypt
   
           $pdb->Encrypt([$password]);
   
   Encrypts the PDB, either with the password used to decrypt or create it, or
   optionally with a password that is passed.
   
   See Decrypt() for an what plaintext fields are available to be encrypted.
   
   =cut
   
 sub Encrypt  sub Encrypt
 {  {
         my $self = shift;          my $self = shift;
         my $pass = shift;          my $pass = shift;
   
         if ($pass) {          if ($pass) {
                 unless ($self->_keyring_verify($pass) ) {                  unless (exists $self->{'records'}->[0]->{'data'} &&
                       $self->_keyring_verify($pass) ) {
                         # This would encrypt with a new password.                          # This would encrypt with a new password.
                         # First decrypting everything with the old password of course.                          # First decrypting everything with the old password of course.
                         $self->_keyring_update($pass) || return undef;                          $self->_keyring_update($pass) || return undef;
Line 127 
Line 206 
                 }                  }
         }          }
   
         my $seen_enc_pass = 0;          $self->{digest} ||= _calc_keys($self->{password});
         foreach my $record (@{ $self->{records} }) {  
                 unless ($seen_enc_pass) {  
                         $seen_enc_pass = 1;  
                         next;  
                 }  
   
           foreach my $record (@{ $self->{records} }) {
                 next unless defined $record->{plaintext};                  next unless defined $record->{plaintext};
   
                 my $name        = defined $record->{plaintext}->{name}        ? $record->{plaintext}->{name}        : '';                  my $name        = defined $record->{plaintext}->{name}        ?
                 my $account     = defined $record->{plaintext}->{account}     ? $record->{plaintext}->{account}     : '';                          $record->{plaintext}->{name}        : '';
                 my $password    = defined $record->{plaintext}->{password}    ? $record->{plaintext}->{password}    : '';                  my $account     = defined $record->{plaintext}->{account}     ?
                 my $description = defined $record->{plaintext}->{description} ? $record->{plaintext}->{description} : '';                          $record->{plaintext}->{account}     : '';
                   my $password    = defined $record->{plaintext}->{password}    ?
                           $record->{plaintext}->{password}    : '';
                   my $description = defined $record->{plaintext}->{description} ?
                           $record->{plaintext}->{description} : '';
                 my $extra       = '';                  my $extra       = '';
   
                 my $plaintext = join("\0", $account, $password, $description, $extra);                  my $plaintext = join("\000", $account, $password, $description, $extra);
   
                 my $encrypted = $self->_crypt($plaintext, ENCRYPT);                  my $encrypted = _crypt3des($plaintext, $self->{digest}, ENCRYPT);
   
                 $record->{data} = join("\0", $name, $encrypted);                  $record->{data} = join("\000", $name, $encrypted);
         }          }
   
         return 1;          1;
 }  }
   
   =head2 Decrypt
   
           $pdb->Decrypt([$password]);
   
   Decrypts the PDB and fills out the rest of the fields available in
   $record->{'plaintext'}.
   
   The plaintext should now be this, before encryption or after decryption:
   
           $record->{'plaintext'} = {
                   name        => $name,
                   account     => $account,
                   password    => $account_password,
                   description => $description,
           };
   
   =cut
   
 sub Decrypt  sub Decrypt
 {  {
         my $self = shift;          my $self = shift;
Line 161 
Line 258 
                 $self->_keyring_verify($pass) || return undef;                  $self->_keyring_verify($pass) || return undef;
         }          }
   
         my $seen_enc_pass = 0;          $self->{digest} ||= _calc_keys($self->{password});
         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;  
                 }  
   
           foreach my $record (@{ $self->{records} }) {
                 next unless defined $record->{data};                  next unless defined $record->{data};
   
                 my ($name, $encrypted) = split /\0/, $record->{data};                  my ($name, $encrypted) = split /\000/, $record->{data}, 2;
                   next unless $encrypted;
   
                 $record->{plaintext}->{name} = $name;                  $record->{plaintext}->{name} = $name;
   
                 my $decrypted = $self->_crypt($encrypted, DECRYPT);                  my $decrypted = _crypt3des($encrypted, $self->{digest}, DECRYPT);
                 my ($account, $password, $description, $extra)                  my ($account, $password, $description, $extra)
                       = split /\0/, $decrypted, 4;                        = split /\000/, $decrypted, 4;
   
                 $record->{plaintext}->{account}     = defined $account     ? $account     : '';                  $record->{plaintext}->{account}     = defined $account     ?
                 $record->{plaintext}->{password}    = defined $password    ? $password    : '';                          $account     : '';
                 $record->{plaintext}->{description} = defined $description ? $description : '';                  $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 "Extra: $extra\n";                  #print "Extra: $extra\n";
                   #exit;
                 #--------------------------------------------------                  #--------------------------------------------------
                 # print "Account:     $account\n";                  # print "Account:     $account\n";
                 # print "Password:    $password\n";                  # print "Password:    $password\n";
Line 191 
Line 297 
   
         }          }
   
         return 1;          1;
 }  }
   
 sub _crypt  
 {  
         my $self = shift;  
         my $original = shift;  
         my $flag = shift;  
   
         my $digest = $self->{digest} || $self->_calc_keys();  
         #print "DIGEST: $digest\n";  
   
         my $des = new Crypt::TripleDES;  
   
         if ($flag == ENCRYPT) {  
                 return $des->encrypt3($original, $digest);  
         } else {  
                 return $des->decrypt3($original, $digest);  
         }  
 }  
   
 sub _calc_keys  sub _calc_keys
 {  {
         my $self = shift;          my $pass = shift;
   
         my $pass = $self->{'password'};  
         die "No password defined!" unless defined $pass;          die "No password defined!" unless defined $pass;
   
         my $digest = md5($pass);          my $digest = md5($pass);
Line 233 
Line 319 
         # print length $digest, "\n";          # print length $digest, "\n";
         #--------------------------------------------------          #--------------------------------------------------
   
         $self->{digest} = $digest;  
         return $digest;          return $digest;
 }  }
   
Line 242 
Line 327 
         my $self = shift;          my $self = shift;
         my $pass = shift;          my $pass = shift;
   
         die "No password specified!" unless defined $pass;          die "No password specified!" unless $pass;
         $self->{password} = $pass;  
   
         # AFAIK the thing we use to test the password is          # AFAIK the thing we use to test the password is
         #     always in the first entry          #     always in the first entry
Line 263 
Line 347 
   
         if ($data eq $salt . $digest) {          if ($data eq $salt . $digest) {
                 # May as well generate the keys we need now, since we know the password is right                  # May as well generate the keys we need now, since we know the password is right
                 if ($self->_calc_keys()) {                  $self->{digest} = _calc_keys($pass);
                   if ($self->{digest}) {
                           $self->{password} = $pass;
                         return 1;                          return 1;
                 } else {                  } else {
                         return undef;                          return undef;
Line 282 
Line 368 
         my $self = shift;          my $self = shift;
         my $pass = shift;          my $pass = shift;
   
         die "No password specified!" unless defined $pass;          die "No password specified!" unless $pass;
   
         # if the database already has a password in it          # if the database already has a password in it
         if ($self->{records}->[0]->{data}) {          if ($self->{records}->[0]->{data}) {
Line 308 
Line 394 
         $self->{records}->[0]->{data} = $data;          $self->{records}->[0]->{data} = $data;
   
         $self->{password} = $pass;          $self->{password} = $pass;
         $self->_calc_keys();          $self->{digest}   = _calc_keys($self->{password});
   
         return 1;          return 1;
 }  }
   
   sub _crypt3des {
           my ( $plaintext, $passphrase, $flag ) = @_;
           my $NULL = chr(0);
   
           $passphrase .= ' ' x (16*3);
           my $cyphertext = "";
   
           my $size = length ( $plaintext );
           #print "STRING: '$plaintext' - Length: " . length($plaintext) . "\n";
   
           my @C;
           for ( 0..2 ) {
                   $C[$_] = new Crypt::DES( pack( "H*", substr($passphrase, 16*$_, 16 )));
           }
   
           for ( 0 .. (($size)/8)) {
                   my $pt = substr( $plaintext, $_*8, 8 );
                   #print "PT: '$pt' - Length: " . length($pt) . "\n";
                   next unless length($pt);
                   if (length($pt) < 8) {
                           die "record not 8 byte padded" if  $flag == DECRYPT;
                           my $len = 8 - length($pt);
                           #print "LENGTH: $len\n";
                           #print "Binary:    '" . unpack("b*", $pt) . "'\n";
                           $pt .= ($NULL x $len);
                           #print "PT: '$pt' - Length: " . length($pt) . "\n";
                           #print "Binary:    '" . unpack("b*", $pt) . "'\n";
                   }
                   if ($flag == ENCRYPT) {
                           $pt = $C[0]->encrypt( $pt );
                           $pt = $C[1]->decrypt( $pt );
                           $pt = $C[2]->encrypt( $pt );
                   } else {
                           $pt = $C[0]->decrypt( $pt );
                           $pt = $C[1]->encrypt( $pt );
                           $pt = $C[2]->decrypt( $pt );
                   }
                   #print "PT: '$pt' - Length: " . length($pt) . "\n";
                   $cyphertext .= $pt;
           }
   
           $cyphertext =~ s/$NULL+$//;
           #print "CT: '$cyphertext' - Length: " . length($cyphertext) . "\n";
   
           return $cyphertext;
   }
   
 1;  1;
 __END__  __END__
   
 =head1 AUTHOR  =head1 AUTHOR
   
 Andrew Fresh E<lt>andrew@mad-techies.org<gt>  Andrew Fresh E<lt>andrew@mad-techies.orgE<gt>
   
 =head1 SEE ALSO  =head1 SEE ALSO
   
 Palm::PDB(3)  Palm::PDB(3)
   
 Palm::StdAppInfo(3)  Palm::StdAppInfo(3)
   
   The Keyring for Palm OS website:
   L<http://gnukeyring.sourceforge.net/>
   
 =cut  =cut

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.12

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