Palm-Keyring

 view release on metacpan or  search on metacpan

lib/Palm/Keyring.pm  view on Meta::CPAN

    my ($key, $hash) = _calc_key_v5(
        $pass, $salt, $iter, 
        $c->{keylen}, 
        $c->{DES_odd_parity},
    );

    $appinfo->{salt}           = unpack "H*", $salt;
    $appinfo->{iter}           = $iter;
    $appinfo->{cipher}         = $cipher;
    $appinfo->{masterhash}     = $hash;
    $appinfo->{key}            = $key;

    return $key;
}

# Helpers

sub _calc_keys 
{
    my $pass = shift;
    if (! defined $pass) { croak('No password defined!'); };

    my $digest = md5($pass);

    my ( $key1, $key2 ) = unpack 'a8a8', $digest;

    #--------------------------------------------------
    # print "key1: $key1: ", length $key1, "\n";
    # print "key2: $key2: ", length $key2, "\n";
    #--------------------------------------------------

    $digest = unpack 'H*', $key1 . $key2 . $key1;

    #--------------------------------------------------
    # print "Digest: ", $digest, "\n";
    # print length $digest, "\n";
    #--------------------------------------------------

    return $digest;
}

sub _calc_key_v5
{
    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 );
    if ($dop) { $key = _DES_odd_parity($key); }

    my $hash = unpack("H*", substr(sha1($key.$salt),0, 8));

    return $key, $hash;
}

sub _crypt3des 
{
    require Crypt::DES;

    my ( $plaintext, $passphrase, $flag ) = @_;

    $passphrase   .= $SPACE x ( 16 * 3 );
    my $cyphertext = $EMPTY;

    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";
        if (! length $pt) { next; };
        if ( (length $pt) < 8 ) {
            if ($flag == $DECRYPT) { croak('record not 8 byte padded'); };
            my $len = 8 - (length $pt);
            $pt .= ($NULL x $len);
        }
        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+$//xm;

    #print "CT: '$cyphertext' - Length: " . length($cyphertext) . "\n";

    return $cyphertext;
}

sub _parse_field 
{
    my $field = shift;

    my @labels;
    $labels[0]   = 'name';
    $labels[1]   = 'account';
    $labels[2]   = 'password';
    $labels[3]   = 'lastchange';
    $labels[255] = 'notes';

    my ($len) = unpack "n1", $field;
    if ($len + 4 > length $field) {
        return undef, $field;
    }
    my $unpackstr = "x2 C1 C1 A$len";
    my $offset    =   2 +1 +1 +$len;
    if ($len % 2) { # && $len + 4 < length $field) {
        # trim the 0/1 byte padding for next even address.
        $offset++;
        $unpackstr .= ' x' 
    }

    my ($label, $font, $data) = unpack $unpackstr, $field;
    my $leftover = substr $field, $offset;

lib/Palm/Keyring.pm  view on Meta::CPAN

    $pdb->{password} = the password that was passed in;

For v5

    $pdb->{appinfo} = {
        # As described under new() with these additional fields
        cipher     => The index number of the cipher being used
        iter       => Number of iterations for the cipher
        key        => The key that is calculated from the password 
                      and salt and is used to decrypt the records.
        masterhash => the hash of the key that is stored in the 
                      database.  Either set when Loading the database
                      or when setting a new password.
        salt       => the salt that is either read out of the database 
                      or calculated when setting a new password.
    };

=head2 Other overridden subroutines/methods

=over

=item ParseAppInfoBlock

Converts the extra returned by Palm::StdAppInfo::ParseAppInfoBlock() into 
the following additions to $pdb->{appinfo}

    $pdb->{appinfo} = {
        cipher     => The index number of the cipher being used (Not v4)
        iter       => Number of iterations for the cipher (Not v4)
    };

=item PackAppInfoBlock

Reverses ParseAppInfoBlock before
sending it on to Palm::StdAppInfo::PackAppInfoBlock()

=item ParseRecord

Adds some fields to a record from Palm::StdAppInfo::ParseRecord()

    $rec = {
        name       => Account name
        ivec       => The IV for the encrypted record.  (Not v4)
        encrypted  => the encrypted information
    };

=item PackRecord

Reverses ParseRecord and then sends it through Palm::StdAppInfo::PackRecord()

=back

=head1 DEPENDENCIES

Palm::StdAppInfo

B<For v4 databases>

Digest::MD5

Crypt::DES

B<For v5 databases>

Digest::HMAC_SHA1

Digest::SHA1

Depending on how the database is encrypted

Crypt::CBC - For any encryption but None

Crypt::DES_EDE3 - DES_EDE3 encryption

Crytp::Rijndael - AES encryption schemes

=head1 THANKS

I would like to thank the helpful Perlmonk shigetsu who gave me some great advice
and helped me get my first module posted.  L<http://perlmonks.org/?node_id=596998>

I would also like to thank 
Johan Vromans
E<lt>jvromans@squirrel.nlE<gt> -- 
L<http://www.squirrel.nl/people/jvromans>.
He had his own Palm::KeyRing module that he posted a couple of days before 
mine was ready and he was kind enough to let me have the namespace as well 
as giving me some very helpful hints about doing a few things that I was 
unsure of.  He is really great.

And finally, 
thanks to Jochen Hoenicke E<lt>hoenicke@gmail.comE<gt> 
(one of the authors of Palm Keyring)
for getting me started on the v5 support as well as providing help
and some subroutines.

=head1 BUGS AND LIMITATIONS

I am sure there are problems with this module.  For example, I have 
not done very extensive testing of the v5 databases.  

I am not sure I am 'require module' the best way, but I don't want to 
depend on modules that you don't need to use.  

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.  

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.

I have not gone through and standardized on how the module fails.  Some 
things fail with croak, some return undef, some may even fail silently.  
Nothing initializes a lasterr method or anything like that.  I need 
to fix all that before it is a 1.0 candidate. 

Please report any bugs or feature requests to
C<bug-palm-keyring at rt.cpan.org>, or through the web interface at
L<http://rt.cpan.org>.  I will be notified, and then you'll automatically be
notified of progress on your bug as I make changes.

=head1 AUTHOR

Andrew Fresh E<lt>andrew@cpan.orgE<gt>

=head1 LICENSE AND COPYRIGHT

Copyright 2004, 2005, 2006, 2007 Andrew Fresh, All Rights Reserved.

This program is free software; you can redistribute it and/or 
modify it under the same terms as Perl itself.



( run in 0.781 second using v1.01-cache-2.11-cpan-39bf76dae61 )