| version 1.34, 2007/02/21 05:24:14 | version 1.36, 2007/02/22 05:16:04 | 
|  |  | 
| package Palm::Keyring; | package Palm::Keyring; | 
| # $RedRiver: Keyring.pm,v 1.33 2007/02/21 01:26:07 andrew Exp $ | # $RedRiver: Keyring.pm,v 1.35 2007/02/22 04:11:35 andrew Exp $ | 
| ######################################################################## | ######################################################################## | 
| # Keyring.pm *** Perl class for Keyring for Palm OS databases. | # Keyring.pm *** Perl class for Keyring for Palm OS databases. | 
| # | # | 
|  |  | 
| use warnings; | use warnings; | 
|  |  | 
| use Carp; | use Carp; | 
|  | $Carp::Verbose = 1; | 
|  |  | 
| use base qw/ Palm::StdAppInfo /; | use base qw/ Palm::StdAppInfo /; | 
|  |  | 
|  |  | 
|  |  | 
| my $unpackstr | my $unpackstr | 
| = ("C1" x 8)  # 8 uint8s in an array for the salt | = ("C1" x 8)  # 8 uint8s in an array for the salt | 
| . ("S1" x 2)  # the iter (uint16) and the cipher (uint16) | . ("n1" x 2)  # the iter (uint16) and the cipher (uint16) | 
| . ("C1" x 8); # and finally 8 more uint8s for the hash | . ("C1" x 8); # and finally 8 more uint8s for the hash | 
|  |  | 
| my (@salt, $iter, $cipher, @hash); | my (@salt, $iter, $cipher, @hash); | 
|  |  | 
|  |  | 
| my $packstr | my $packstr | 
| = ("C1" x 8)  # 8 uint8s in an array for the salt | = ("C1" x 8)  # 8 uint8s in an array for the salt | 
| . ("S1" x 2)  # the iter (uint16) and the cipher (uint16) | . ("n1" x 2)  # the iter (uint16) and the cipher (uint16) | 
| . ("C1" x 8); # and finally 8 more uint8s for the hash | . ("C1" x 8); # and finally 8 more uint8s for the hash | 
|  |  | 
| my @salt = map { hex $_ } $appinfo->{salt} =~ /../gxm; | my @salt = map { hex $_ } $appinfo->{salt} =~ /../gxm; | 
|  |  | 
|  |  | 
| 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; | 
|  |  | 
| $encrypted = $decrypted; | $encrypted = $decrypted; | 
|  |  | 
| } elsif ($cipher_name eq 'DES_EDE3' or $cipher_name eq 'Rijndael') { | } elsif ($cipher_name eq 'DES_EDE3' or $cipher_name eq 'Rijndael') { | 
|  | require Crypt::CBC; | 
| my $c = Crypt::CBC->new( | my $c = Crypt::CBC->new( | 
| -literal_key => 1, |  | 
| -key         => $key, | -key         => $key, | 
|  | -literal_key => 1, | 
| -iv          => $ivec, | -iv          => $ivec, | 
| -cipher      => $cipher_name, | -cipher      => $cipher_name, | 
| -keysize     => $keylen, | -keysize     => $keylen, | 
|  |  | 
|  |  | 
| sub _decrypt_v5 | sub _decrypt_v5 | 
| { | { | 
| require Crypt::CBC; |  | 
|  |  | 
| my $encrypted = shift; | my $encrypted = shift; | 
| my $key       = shift; | my $key       = shift; | 
|  |  | 
| $decrypted = $encrypted; | $decrypted = $encrypted; | 
|  |  | 
| } elsif ($cipher_name eq 'DES_EDE3' or $cipher_name eq 'Rijndael') { | } elsif ($cipher_name eq 'DES_EDE3' or $cipher_name eq 'Rijndael') { | 
|  | require Crypt::CBC; | 
| my $c = Crypt::CBC->new( | my $c = Crypt::CBC->new( | 
| -literal_key => 1, |  | 
| -key         => $key, | -key         => $key, | 
|  | -literal_key => 1, | 
| -iv          => $ivec, | -iv          => $ivec, | 
| -cipher      => $cipher_name, | -cipher      => $cipher_name, | 
| -keysize     => $keylen, | -keysize     => $keylen, | 
|  |  | 
| } | } | 
| } | } | 
| } elsif ($self->{version} == 5) { | } elsif ($self->{version} == 5) { | 
| return _password_verify_v5($pass, $self->{appinfo}); | return _password_verify_v5($self->{appinfo}, $pass); | 
| } else { | } else { | 
| # XXX unsupported version | # XXX unsupported version | 
| } | } | 
|  |  | 
|  |  | 
| sub _password_verify_v5 | sub _password_verify_v5 | 
| { | { | 
| my $pass    = shift; |  | 
| my $appinfo = shift; | my $appinfo = shift; | 
|  | my $pass    = shift; | 
|  |  | 
| my $salt = pack("H*", $appinfo->{salt}); | my $salt = pack("H*", $appinfo->{salt}); | 
|  |  | 
|  |  | 
| $CRYPTS[ $appinfo->{cipher} ]{DES_odd_parity}, | $CRYPTS[ $appinfo->{cipher} ]{DES_odd_parity}, | 
| ); | ); | 
|  |  | 
|  | #print "Iter: '" . $appinfo->{iter} . "'\n"; | 
| #print "Key:  '". unpack("H*", $key) . "'\n"; | #print "Key:  '". unpack("H*", $key) . "'\n"; | 
|  | #print "Salt: '". unpack("H*", $salt) . "'\n"; | 
| #print "Hash: '". $hash . "'\n"; | #print "Hash: '". $hash . "'\n"; | 
| #print "Hash: '". $appinfo->{masterhash} . "'\n"; | #print "Hash: '". $appinfo->{masterhash} . "'\n"; | 
|  |  | 
|  |  | 
| $labels[3]   = 'lastchange'; | $labels[3]   = 'lastchange'; | 
| $labels[255] = 'notes'; | $labels[255] = 'notes'; | 
|  |  | 
| my ($len) = unpack "S1", $field; | my ($len) = unpack "n1", $field; | 
| if ($len + 4 > length $field) { | if ($len + 4 > length $field) { | 
| return undef, $field; | return undef, $field; | 
| } | } | 
|  |  | 
| $data = _pack_keyring_date($data); | $data = _pack_keyring_date($data); | 
| } | } | 
| my $len = length $data; | my $len = length $data; | 
| my $packstr = "S1 C1 C1 A*"; | my $packstr = "n1 C1 C1 A*"; | 
|  |  | 
| my $packed = pack $packstr, ($len, $label, $font, $data); | my $packed = pack $packstr, ($len, $label, $font, $data); | 
|  |  | 
|  |  | 
|  |  | 
| =back | =back | 
|  |  | 
|  | For v5 databases there are some additional appinfo fields set. | 
|  |  | 
|  | $pdb->{appinfo} = { | 
|  | # normal appinfo stuff described in L<Palm::StdAppInfo> | 
|  | cipher     => The index number of the cipher being used | 
|  | iter       => Number of iterations for the cipher | 
|  | }; | 
|  |  | 
| =head2 crypt | =head2 crypt | 
|  |  | 
| Pass in the alias of the crypt to use, or the index. | Pass in the alias of the crypt to use, or the index. | 
|  |  | 
| default_iter => <default iterations for the cipher>, | default_iter => <default iterations for the cipher>, | 
| }; | }; | 
|  |  | 
|  |  | 
| =head2 Encrypt | =head2 Encrypt | 
|  |  | 
| $pdb->Encrypt($rec, $acct[, $password[, $ivec]]); | $pdb->Encrypt($rec, $acct[, $password[, $ivec]]); | 
|  |  | 
| the password. | the password. | 
|  |  | 
| If nothing is passed, it forgets the password that it was remembering. | If nothing is passed, it forgets the password that it was remembering. | 
|  |  | 
|  | After a successful password verification the following fields are set | 
|  |  | 
|  | For v4 | 
|  |  | 
|  | $pdb->{digest}   = the calculated digest used from the key; | 
|  | $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. | 
|  | }; | 
|  |  | 
| =head1 DEPENDENCIES | =head1 DEPENDENCIES | 
|  |  |