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

Annotation of palm/Palm-Keyring/lib/Palm/Keyring.pm, Revision 1.27

1.14      andrew      1: package Palm::Keyring;
1.27    ! andrew      2: # $RedRiver: Keyring.pm,v 1.26 2007/02/06 02:58:50 andrew Exp $
        !             3: ########################################################################
        !             4: # Keyring.pm *** Perl class for Keyring for Palm OS databases.
        !             5: #
        !             6: #   This started as Memo.pm, I just made it work for Keyring.
1.1       andrew      7: #
1.27    ! andrew      8: # 2006.01.26 #*#*# andrew fresh <andrew@cpan.org>
        !             9: ########################################################################
        !            10: # Copyright (C) 2006, 2007 by Andrew Fresh
1.1       andrew     11: #
1.27    ! andrew     12: # This program is free software; you can redistribute it and/or modify
        !            13: # it under the same terms as Perl itself.
        !            14: ########################################################################
1.1       andrew     15: use strict;
1.14      andrew     16: use warnings;
1.27    ! andrew     17:
1.14      andrew     18: use Carp;
                     19:
                     20: use base qw/ Palm::StdAppInfo /;
1.1       andrew     21:
                     22: use Digest::MD5 qw(md5);
1.2       andrew     23: use Crypt::DES;
1.14      andrew     24:
1.24      andrew     25: my $ENCRYPT    = 1;
                     26: my $DECRYPT    = 0;
                     27: my $MD5_CBLOCK = 64;
                     28: my $kSalt_Size = 4;
                     29: my $EMPTY      = q{};
                     30: my $SPACE      = q{ };
                     31: my $NULL       = chr 0;
1.14      andrew     32:
1.26      andrew     33: our $VERSION = 0.94;
1.1       andrew     34:
1.14      andrew     35: sub new {
                     36:     my $classname = shift;
                     37:     my $pass      = shift;
1.1       andrew     38:
1.14      andrew     39:     # Create a generic PDB. No need to rebless it, though.
                     40:     my $self = $classname->SUPER::new(@_);
1.1       andrew     41:
1.14      andrew     42:     $self->{'name'}    = 'Keys-Gtkr';    # Default
                     43:     $self->{'creator'} = 'Gtkr';
                     44:     $self->{'type'}    = 'Gkyr';
                     45:
                     46:     # The PDB is not a resource database by
                     47:     # default, but it's worth emphasizing,
                     48:     # since MemoDB is explicitly not a PRC.
                     49:     $self->{'attributes'}{'resource'} = 0;
1.1       andrew     50:
1.14      andrew     51:     # Initialize the AppInfo block
                     52:     $self->{'appinfo'} = {};
1.1       andrew     53:
1.14      andrew     54:     # Add the standard AppInfo block stuff
                     55:     Palm::StdAppInfo::seed_StdAppInfo( $self->{'appinfo'} );
1.1       andrew     56:
1.14      andrew     57:     # Set the version
                     58:     $self->{'version'} = 4;
1.1       andrew     59:
1.14      andrew     60:     if ( defined $pass ) {
1.16      andrew     61:         $self->Password($pass);
1.14      andrew     62:     }
1.1       andrew     63:
1.14      andrew     64:     return $self;
                     65: }
1.1       andrew     66:
1.14      andrew     67: sub import {
                     68:     Palm::PDB::RegisterPDBHandlers( __PACKAGE__, [ 'Gtkr', 'Gkyr' ], );
                     69:     return 1;
                     70: }
1.1       andrew     71:
1.16      andrew     72: sub ParseRecord {
1.14      andrew     73:     my $self     = shift;
                     74:
1.16      andrew     75:     my $rec = $self->SUPER::ParseRecord(@_);
                     76:
                     77:     # skip the 0 record that holds the password
                     78:     return $rec if ! exists $self->{'records'};
                     79:     return $rec if ! exists $rec->{'data'};
1.14      andrew     80:
1.16      andrew     81:     my ( $name, $encrypted ) = split /$NULL/xm, $rec->{'data'}, 2;
1.1       andrew     82:
1.16      andrew     83:     return $rec if ! $encrypted;
1.19      andrew     84:     delete $rec->{'data'};
                     85:     $rec->{'name'} = $name;
1.16      andrew     86:     $rec->{'encrypted'} = $encrypted;
1.12      andrew     87:
1.16      andrew     88:     return $rec;
1.14      andrew     89: }
1.11      andrew     90:
1.16      andrew     91: sub PackRecord {
                     92:     my $self = shift;
                     93:     my $rec  = shift;
                     94:
1.23      andrew     95:     if ($rec->{'encrypted'}) {
1.22      andrew     96:         if (! defined $rec->{'name'}) {
                     97:             $rec->{'name'} = $EMPTY;
                     98:         }
1.19      andrew     99:         $rec->{'data'} = join $NULL, $rec->{'name'}, $rec->{'encrypted'};
                    100:         delete $rec->{'name'};
1.16      andrew    101:         delete $rec->{'encrypted'};
                    102:     }
1.1       andrew    103:
1.16      andrew    104:     return $self->SUPER::PackRecord($rec, @_);
1.14      andrew    105: }
1.1       andrew    106:
1.14      andrew    107: sub Encrypt {
                    108:     my $self = shift;
1.16      andrew    109:     my $rec  = shift;
                    110:     my $data = shift;
                    111:     my $pass = shift || $self->{'password'};
                    112:
                    113:     if ( ! $pass) {
                    114:         croak("'password' not set!\n");
                    115:     }
                    116:
                    117:     if ( ! $rec) {
                    118:         croak("Needed parameter 'record' not passed!\n");
                    119:     }
1.14      andrew    120:
1.16      andrew    121:     if ( ! $data) {
                    122:         croak("Needed parameter 'data' not passed!\n");
1.14      andrew    123:     }
                    124:
1.16      andrew    125:     if ( ! $self->Password($pass)) {
                    126:         croak("Incorrect Password!\n");
                    127:     }
1.14      andrew    128:
1.22      andrew    129:     $self->{'digest'}   ||= _calc_keys( $pass );
1.14      andrew    130:
1.16      andrew    131:     $data->{'account'}  ||= $EMPTY;
                    132:     $data->{'password'} ||= $EMPTY;
                    133:     $data->{'notes'}    ||= $EMPTY;
1.1       andrew    134:
1.22      andrew    135:     my $changed      = 0;
                    136:     my $need_newdate = 0;
                    137:     my $acct = {};
                    138:     if ($rec->{'encrypted'}) {
                    139:         $acct = $self->Decrypt($rec, $pass);
                    140:         foreach my $key (keys %{ $data }) {
                    141:             next if $key eq 'lastchange';
                    142:             if ($data->{$key} ne $acct->{$key}) {
                    143:                 $changed = 1;
                    144:                 last;
                    145:             }
                    146:         }
                    147:         if ( exists $data->{'lastchange'} && exists $acct->{'lastchange'} && (
                    148:             $data->{'lastchange'}->{day}   != $acct->{'lastchange'}->{day}   ||
                    149:             $data->{'lastchange'}->{month} != $acct->{'lastchange'}->{month} ||
                    150:             $data->{'lastchange'}->{year}  != $acct->{'lastchange'}->{year}
                    151:         )) {
                    152:             $changed = 1;
                    153:             $need_newdate = 0;
                    154:         } else {
                    155:             $need_newdate = 1;
                    156:         }
                    157:
                    158:     } else {
                    159:         $changed = 1;
                    160:     }
                    161:
                    162:     # no need to re-encrypt if it has not changed.
                    163:     return 1 if ! $changed;
                    164:
1.21      andrew    165:     my ($day, $month, $year);
                    166:
1.22      andrew    167:     if ($data->{'lastchange'} && ! $need_newdate ) {
                    168:         $day   = $data->{'lastchange'}->{'day'}   || 1;
                    169:         $month = $data->{'lastchange'}->{'month'} || 0;
                    170:         $year  = $data->{'lastchange'}->{'year'}  || 0;
                    171:
                    172:         # XXX Need to actually validate the above information somehow
                    173:         if ($year >= 1900) {
                    174:             $year -= 1900;
                    175:         }
                    176:     } else {
                    177:         $need_newdate = 1;
                    178:     }
                    179:
                    180:     if ($need_newdate) {
1.21      andrew    181:         ($day, $month, $year) = (localtime)[3,4,5];
                    182:     }
1.22      andrew    183:     $year -= 4;
                    184:     $month++;
                    185:
1.19      andrew    186:
                    187:     my $p = $day | ($month << 5) | ($year << 9);
                    188:     my $packeddate = pack 'n', $p;
                    189:
1.16      andrew    190:     my $plaintext = join $NULL,
1.19      andrew    191:         $data->{'account'}, $data->{'password'}, $data->{'notes'}, $packeddate;
1.1       andrew    192:
1.16      andrew    193:     my $encrypted = _crypt3des( $plaintext, $self->{'digest'}, $ENCRYPT );
1.11      andrew    194:
1.16      andrew    195:     return if ! $encrypted;
1.1       andrew    196:
1.19      andrew    197:     $rec->{'attributes'}{'Dirty'} = 1;
                    198:     $rec->{'attributes'}{'dirty'} = 1;
                    199:     $rec->{'name'}    ||= $data->{'name'};
1.16      andrew    200:     $rec->{'encrypted'} = $encrypted;
1.19      andrew    201:
1.14      andrew    202:     return 1;
                    203: }
1.1       andrew    204:
1.14      andrew    205: sub Decrypt {
                    206:     my $self = shift;
1.16      andrew    207:     my $rec  = shift;
                    208:     my $pass = shift || $self->{'password'};
                    209:
                    210:     if ( ! $pass) {
                    211:         croak("'password' not set!\n");
                    212:     }
                    213:
                    214:     if ( ! $rec) {
1.19      andrew    215:         croak("Needed parameter 'record' not passed!\n");
1.16      andrew    216:     }
1.14      andrew    217:
1.16      andrew    218:     if ( ! $self->Password($pass)) {
                    219:         croak("Invalid Password!\n");
1.14      andrew    220:     }
                    221:
1.16      andrew    222:     if ( ! $rec->{'encrypted'} ) {
                    223:         croak("No encrypted content!");
                    224:     }
1.14      andrew    225:
1.16      andrew    226:     $self->{'digest'} ||= _calc_keys( $pass );
1.14      andrew    227:
1.16      andrew    228:     my $decrypted =
                    229:         _crypt3des( $rec->{'encrypted'}, $self->{'digest'}, $DECRYPT );
1.19      andrew    230:     my ( $account, $password, $notes, $packeddate ) = split /$NULL/xm,
1.16      andrew    231:           $decrypted, 4;
1.14      andrew    232:
1.19      andrew    233:     my %Modified;
                    234:     if ($packeddate) {
                    235:         my $u = unpack 'n', $packeddate;
                    236:         my $year  = (($u & 0xFE00) >> 9) + 4; # since 1900
                    237:         my $month = (($u & 0x01E0) >> 5) - 1; # 0-11
                    238:         my $day   = (($u & 0x001F) >> 0);     # 1-31
                    239:
                    240:         %Modified = (
                    241:             year   => $year,
                    242:             month  => $month || 0,
                    243:             day    => $day   || 1,
                    244:         );
                    245:     }
                    246:
1.16      andrew    247:     return {
1.20      andrew    248:         name       => $rec->{'name'},
                    249:         account    => $account,
                    250:         password   => $password,
                    251:         notes      => $notes,
                    252:         lastchange => \%Modified,
1.16      andrew    253:     };
                    254: }
1.14      andrew    255:
1.16      andrew    256: sub Password {
                    257:     my $self = shift;
1.24      andrew    258:     my $pass = shift;
1.16      andrew    259:     my $new_pass = shift;
1.14      andrew    260:
1.24      andrew    261:     if (! $pass) {
                    262:         delete $self->{password};
                    263:        return 1;
                    264:     }
                    265:
1.16      andrew    266:     if (! exists $self->{'records'}) {
                    267:         # Give the PDB the first record that will hold the encrypted password
                    268:         $self->{'records'} = [ $self->new_Record ];
                    269:
                    270:         return $self->_password_update($pass);
                    271:     }
                    272:
                    273:     if ($new_pass) {
                    274:         my @accts = ();
                    275:         foreach my $i (0..$#{ $self->{'records'} }) {
                    276:             if ($i == 0) {
                    277:                 push @accts, undef;
                    278:                 next;
                    279:             }
                    280:             my $acct = $self->Decrypt($self->{'records'}->[$i], $pass);
                    281:             if ( ! $acct ) {
1.19      andrew    282:                 croak("Couldn't decrypt $self->{'records'}->[$i]->{'name'}");
1.16      andrew    283:             }
                    284:             push @accts, $acct;
                    285:         }
1.14      andrew    286:
1.16      andrew    287:         if ( ! $self->_password_update($new_pass)) {
                    288:             croak("Couldn't set new password!");
                    289:         }
                    290:         $pass = $new_pass;
1.1       andrew    291:
1.16      andrew    292:         foreach my $i (0..$#accts) {
                    293:             next if $i == 0;
1.22      andrew    294:             delete $self->{'records'}->[$i]->{'encrypted'};
1.16      andrew    295:             $self->Encrypt($self->{'records'}->[$i], $accts[$i], $pass);
                    296:         }
1.14      andrew    297:     }
1.1       andrew    298:
1.16      andrew    299:     return $self->_password_verify($pass);
1.1       andrew    300: }
                    301:
1.14      andrew    302: sub _calc_keys {
                    303:     my $pass = shift;
                    304:     if (! defined $pass) { croak('No password defined!'); };
                    305:
                    306:     my $digest = md5($pass);
                    307:
                    308:     my ( $key1, $key2 ) = unpack 'a8a8', $digest;
                    309:
                    310:     #--------------------------------------------------
                    311:     # print "key1: $key1: ", length $key1, "\n";
                    312:     # print "key2: $key2: ", length $key2, "\n";
                    313:     #--------------------------------------------------
                    314:
                    315:     $digest = unpack 'H*', $key1 . $key2 . $key1;
                    316:
                    317:     #--------------------------------------------------
                    318:     # print "Digest: ", $digest, "\n";
                    319:     # print length $digest, "\n";
                    320:     #--------------------------------------------------
                    321:
                    322:     return $digest;
1.3       andrew    323: }
                    324:
1.16      andrew    325: sub _password_verify {
1.14      andrew    326:     my $self = shift;
                    327:     my $pass = shift;
                    328:
                    329:     if (! $pass) { croak('No password specified!'); };
1.11      andrew    330:
1.16      andrew    331:     if (defined $self->{'password'} && $pass eq $self->{'password'}) {
                    332:         # already verified this password
                    333:         return 1;
                    334:     }
                    335:
1.14      andrew    336:     # AFAIK the thing we use to test the password is
                    337:     #     always in the first entry
                    338:     my $data = $self->{'records'}->[0]->{'data'};
1.11      andrew    339:
1.14      andrew    340:     #die "No encrypted password in file!" unless defined $data;
1.16      andrew    341:     if ( ! defined $data) { return; };
1.11      andrew    342:
1.14      andrew    343:     $data =~ s/$NULL$//xm;
1.11      andrew    344:
1.14      andrew    345:     my $salt = substr $data, 0, $kSalt_Size;
1.11      andrew    346:
1.14      andrew    347:     my $msg = $salt . $pass;
1.11      andrew    348:
1.14      andrew    349:     $msg .= "\0" x ( $MD5_CBLOCK - length $msg );
1.11      andrew    350:
1.14      andrew    351:     my $digest = md5($msg);
1.11      andrew    352:
1.14      andrew    353:     if ( $data eq $salt . $digest ) {
1.11      andrew    354:
1.14      andrew    355: # May as well generate the keys we need now, since we know the password is right
                    356:         $self->{'digest'} = _calc_keys($pass);
                    357:         if ( $self->{'digest'} ) {
                    358:             $self->{'password'} = $pass;
                    359:             return 1;
                    360:         }
                    361:     }
                    362:     return;
1.6       andrew    363: }
                    364:
1.16      andrew    365: sub _password_update {
1.14      andrew    366:
                    367:     # It is very important to Encrypt after calling this
                    368:     #     (Although it is generally only called by Encrypt)
                    369:     # because otherwise the data will be out of sync with the
                    370:     # password, and that would suck!
                    371:     my $self = shift;
                    372:     my $pass = shift;
                    373:
1.16      andrew    374:     if (! defined $pass) { croak('No password specified!'); };
1.14      andrew    375:
                    376:     my $salt;
                    377:     for ( 1 .. $kSalt_Size ) {
                    378:         $salt .= chr int rand 255;
                    379:     }
                    380:
                    381:     my $msg = $salt . $pass;
1.11      andrew    382:
1.14      andrew    383:     $msg .= "\0" x ( $MD5_CBLOCK - length $msg );
1.11      andrew    384:
1.14      andrew    385:     my $digest = md5($msg);
1.11      andrew    386:
1.14      andrew    387:     my $data = $salt . $digest;    # . "\0";
1.11      andrew    388:
1.14      andrew    389:     # AFAIK the thing we use to test the password is
                    390:     #     always in the first entry
                    391:     $self->{'records'}->[0]->{'data'} = $data;
1.11      andrew    392:
1.14      andrew    393:     $self->{'password'} = $pass;
                    394:     $self->{'digest'}   = _calc_keys( $self->{'password'} );
1.11      andrew    395:
1.14      andrew    396:     return 1;
1.1       andrew    397: }
                    398:
1.14      andrew    399: sub _crypt3des {
                    400:     my ( $plaintext, $passphrase, $flag ) = @_;
                    401:
                    402:     $passphrase   .= $SPACE x ( 16 * 3 );
                    403:     my $cyphertext = $EMPTY;
                    404:
                    405:     my $size = length $plaintext;
1.11      andrew    406:
1.14      andrew    407:     #print "STRING: '$plaintext' - Length: " . (length $plaintext) . "\n";
                    408:
                    409:     my @C;
                    410:     for ( 0 .. 2 ) {
                    411:         $C[$_] =
                    412:           new Crypt::DES( pack 'H*', ( substr $passphrase, 16 * $_, 16 ));
                    413:     }
                    414:
                    415:     for ( 0 .. ( ($size) / 8 ) ) {
                    416:         my $pt = substr $plaintext, $_ * 8, 8;
                    417:
                    418:         #print "PT: '$pt' - Length: " . length($pt) . "\n";
                    419:         if (! length $pt) { next; };
                    420:         if ( (length $pt) < 8 ) {
1.16      andrew    421:             if ($flag == $DECRYPT) { croak('record not 8 byte padded'); };
1.14      andrew    422:             my $len = 8 - (length $pt);
                    423:
                    424:             #print "LENGTH: $len\n";
                    425:             #print "Binary:    '" . unpack("b*", $pt) . "'\n";
                    426:             $pt .= ($NULL x $len);
                    427:
                    428:             #print "PT: '$pt' - Length: " . length($pt) . "\n";
                    429:             #print "Binary:    '" . unpack("b*", $pt) . "'\n";
                    430:         }
                    431:         if ( $flag == $ENCRYPT ) {
                    432:             $pt = $C[0]->encrypt($pt);
                    433:             $pt = $C[1]->decrypt($pt);
                    434:             $pt = $C[2]->encrypt($pt);
                    435:         }
                    436:         else {
                    437:             $pt = $C[0]->decrypt($pt);
                    438:             $pt = $C[1]->encrypt($pt);
                    439:             $pt = $C[2]->decrypt($pt);
                    440:         }
                    441:
                    442:         #print "PT: '$pt' - Length: " . length($pt) . "\n";
                    443:         $cyphertext .= $pt;
                    444:     }
                    445:
                    446:     $cyphertext =~ s/$NULL+$//xm;
1.11      andrew    447:
1.14      andrew    448:     #print "CT: '$cyphertext' - Length: " . length($cyphertext) . "\n";
1.11      andrew    449:
1.14      andrew    450:     return $cyphertext;
                    451: }
1.11      andrew    452:
1.14      andrew    453: 1;
                    454: __END__
1.11      andrew    455:
1.14      andrew    456: =head1 NAME
1.11      andrew    457:
1.14      andrew    458: Palm::Keyring - Handler for Palm Keyring databases.
1.1       andrew    459:
1.14      andrew    460: =head1 DESCRIPTION
1.7       andrew    461:
1.14      andrew    462: The Keyring PDB handler is a helper class for the Palm::PDB package. It
                    463: parses Keyring for Palm OS databases.  See
                    464: L<http://gnukeyring.sourceforge.net/>.
1.1       andrew    465:
1.14      andrew    466: It has the standard Palm::PDB methods with 2 additional public methods.
                    467: Decrypt and Encrypt.
1.1       andrew    468:
1.16      andrew    469: It currently supports the v4 Keyring databases.  The v5 databases from
                    470: the pre-release keyring-2.0 are not supported.
                    471:
                    472: This module doesn't store the decrypted content.  It only keeps it until it
                    473: returns it to you or encrypts it.
1.1       andrew    474:
1.14      andrew    475: =head1 SYNOPSIS
1.1       andrew    476:
1.16      andrew    477:     use Palm::PDB;
                    478:     use Palm::Keyring;
1.17      andrew    479:
                    480:     my $pass = 'password';
1.18      andrew    481:     my $file = 'Keys-Gtkr.pdb';
                    482:     my $pdb  = new Palm::PDB;
1.16      andrew    483:     $pdb->Load($file);
1.17      andrew    484:
                    485:     foreach (0..$#{ $pdb->{'records'} }) {
                    486:         next if $_ = 0; # skip the password record
                    487:         my $rec  = $pdb->{'records'}->[$_];
                    488:         my $acct = $pdb->Decrypt($rec, $pass);
1.19      andrew    489:         print $rec->{'name'}, ' - ', $acct->{'account'}, "\n";
1.16      andrew    490:     }
1.1       andrew    491:
1.14      andrew    492: =head1 SUBROUTINES/METHODS
1.1       andrew    493:
1.14      andrew    494: =head2 new
1.11      andrew    495:
1.16      andrew    496:     $pdb = new Palm::Keyring([$password]);
1.11      andrew    497:
1.14      andrew    498: Create a new PDB, initialized with the various Palm::Keyring fields
                    499: and an empty record list.
1.11      andrew    500:
1.14      andrew    501: Use this method if you're creating a Keyring PDB from scratch otherwise you
1.16      andrew    502: can just use Palm::PDB::new() before calling Load().
1.11      andrew    503:
1.24      andrew    504: If you pass in a password, it will initalize the first record with the encrypted
                    505: password.
                    506:
1.16      andrew    507: =head2 Encrypt
1.11      andrew    508:
1.24      andrew    509:     $pdb->Encrypt($rec, $acct[, $password]);
1.11      andrew    510:
1.16      andrew    511: Encrypts an account into a record, either with the password previously
                    512: used, or with a password that is passed.
1.1       andrew    513:
1.24      andrew    514: $rec is a record from $pdb->{'records'} or a new_Record().
1.16      andrew    515: $acct is a hashref in the format below.
1.1       andrew    516:
1.16      andrew    517:     my $acct = {
1.20      andrew    518:         name       => $rec->{'name'},
                    519:         account    => $account,
                    520:         password   => $password,
                    521:         notes      => $notes,
                    522:         lastchange => {
                    523:             year  => 107, # years since 1900
                    524:             month =>   0, # 0-11, 0 = January, 11 = December
1.21      andrew    525:             day   =>  30, # 1-31, same as localtime
1.20      andrew    526:         },
1.16      andrew    527:     };
1.7       andrew    528:
1.22      andrew    529: If you have changed anything other than the lastchange, or don't pass in a
1.24      andrew    530: lastchange key, Encrypt() will generate a new lastchange date for you.
1.22      andrew    531:
                    532: If you pass in a lastchange field that is different than the one in the
                    533: record, it will honor what you passed in.
                    534:
1.24      andrew    535: Encrypt() only uses the $acct->{'name'} if there is not already a $rec->{'name'}.
1.22      andrew    536:
1.16      andrew    537: =head2 Decrypt
1.1       andrew    538:
1.16      andrew    539:     my $acct = $pdb->Decrypt($rec[, $password]);
1.1       andrew    540:
1.16      andrew    541: Decrypts the record and returns a hashref for the account as described
1.20      andrew    542: under Encrypt().
1.1       andrew    543:
1.16      andrew    544:     foreach (0..$#{ $pdb->{'records'}) {
                    545:         next if $_ == 0;
                    546:         my $rec = $pdb->{'records'}->[$_];
                    547:         my $acct = $pdb->Decrypt($rec[, $password]);
                    548:         # do something with $acct
                    549:     }
1.1       andrew    550:
1.16      andrew    551: =head2 Password
1.1       andrew    552:
1.16      andrew    553:     $pdb->Password([$password[, $new_password]]);
1.1       andrew    554:
1.16      andrew    555: Either sets the password to be used to crypt, or if you pass $new_password,
                    556: changes the password on the database.
1.1       andrew    557:
1.16      andrew    558: If you have created a new $pdb, and you didn't set a password when you
                    559: called new(), you only need to pass one password and it will set that as
                    560: the password.
1.1       andrew    561:
1.24      andrew    562: If nothing is passed, it forgets the password that it was remembering.
1.1       andrew    563:
1.14      andrew    564: =head1 DEPENDENCIES
1.1       andrew    565:
1.14      andrew    566: Palm::StdAppInfo
1.1       andrew    567:
1.14      andrew    568: Digest::MD5
1.9       andrew    569:
1.14      andrew    570: Crypt::DES
1.4       andrew    571:
1.14      andrew    572: Readonly
1.10      andrew    573:
1.24      andrew    574: =head1 THANKS
                    575:
                    576: I would like to thank the helpful Perlmonk shigetsu who gave me some great advice
                    577: and helped me get my first module posted.  L<http://perlmonks.org/?node_id=596998>
                    578:
                    579: I would also like to thank
                    580: Johan Vromans
                    581: E<lt>jvromans@squirrel.nlE<gt> --
                    582: L<http://www.squirrel.nl/people/jvromans>.
                    583: He had his own Palm::KeyRing module that he posted a couple of days before
                    584: mine was ready and he was kind enough to let me have the namespace as well
                    585: as giving me some very helpful hints about doing a few things that I was
                    586: unsure of.  He is really great.
                    587:
1.14      andrew    588: =head1 BUGS AND LIMITATIONS
1.1       andrew    589:
1.14      andrew    590: Please report any bugs or feature requests to
                    591: C<bug-palm-keyring at rt.cpan.org>, or through the web interface at
                    592: L<http://rt.cpan.org>.  I will be notified, and then you'll automatically be
                    593: notified of progress on your bug as I make changes.
1.1       andrew    594:
                    595: =head1 AUTHOR
                    596:
1.27    ! andrew    597: Andrew Fresh E<lt>andrew@cpan.orgE<gt>
1.1       andrew    598:
1.14      andrew    599: =head1 LICENSE AND COPYRIGHT
                    600:
                    601: Copyright 2004, 2005, 2006, 2007 Andrew Fresh, All Rights Reserved.
                    602:
1.15      andrew    603: This program is free software; you can redistribute it and/or
                    604: modify it under the same terms as Perl itself.
1.14      andrew    605:
1.1       andrew    606: =head1 SEE ALSO
                    607:
                    608: Palm::PDB(3)
                    609:
                    610: Palm::StdAppInfo(3)
1.11      andrew    611:
                    612: The Keyring for Palm OS website:
                    613: L<http://gnukeyring.sourceforge.net/>
1.24      andrew    614:
                    615: Johan Vromans also has a wxkeyring app that now uses this module, available
1.27    ! andrew    616: from his website at L<http://www.vromans.org/johan/software/sw_palmkeyring.html>

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