version 1.5, 2006/11/10 04:52:27 |
version 1.7, 2006/11/10 16:45:42 |
|
|
# 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$ |
# $Id$ |
# $RedRiver: Keyring.pm,v 1.4 2006/11/10 04:21:17 andrew Exp $ |
# $RedRiver: Keyring.pm,v 1.6 2006/11/10 16:18:59 andrew Exp $ |
|
|
use strict; |
use strict; |
package Palm::Keyring; |
package Palm::Keyring; |
|
|
'private' => 1, |
'private' => 1, |
'Secret' => 1, |
'Secret' => 1, |
'Dirty' => 1, |
'Dirty' => 1, |
'dirty' => 1 |
'dirty' => 1, |
}, |
}, |
}, ]; |
}, ]; |
|
|
|
|
my $self = shift; |
my $self = shift; |
$self->SUPER::Load(@_); |
$self->SUPER::Load(@_); |
|
|
# Skip the first 2 records because they are special |
|
# and don't have any plaintext |
|
my $skip = 0; |
|
foreach my $record (@{ $self->{records} }) { |
foreach my $record (@{ $self->{records} }) { |
if ($skip < 2) { |
next unless exists $record->{data}; |
$skip++; |
|
next; |
|
} |
|
my ($name, $encrypted) = split /\000/, $record->{data}, 2; |
my ($name, $encrypted) = split /\000/, $record->{data}, 2; |
|
next unless $encrypted; |
$record->{plaintext}->{name} = $name; |
$record->{plaintext}->{name} = $name; |
$record->{encrypted} = $encrypted; |
$record->{encrypted} = $encrypted; |
} |
} |
1; |
1; |
} |
} |
|
|
|
sub Write |
|
{ |
|
my $self = shift; |
|
$self->Encrypt() || return undef; |
|
return $self->SUPER::Load(@_); |
|
} |
|
|
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 ($self->_keyring_verify($pass) ) { |
# This would encrypt with a new password. |
# This would encrypt with a new password. |
|
|
} |
} |
} |
} |
|
|
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("\000", $account, $password, $description, $extra); |
my $plaintext = join("\000", $account, $password, $description, $extra); |
|
|
my $encrypted = $self->_crypt3des($plaintext, ENCRYPT); |
my $encrypted = _crypt3des($plaintext, $self->{digest}, ENCRYPT); |
|
|
$record->{data} = join("\000", $name, $encrypted); |
$record->{data} = join("\000", $name, $encrypted); |
} |
} |
|
|
$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 /\000/, $record->{data}, 2; |
my ($name, $encrypted) = split /\000/, $record->{data}, 2; |
|
next unless $encrypted; |
|
|
$record->{plaintext}->{name} = $name; |
$record->{plaintext}->{name} = $name; |
|
|
my $decrypted = $self->_crypt3des($encrypted, DECRYPT); |
my $decrypted = _crypt3des($encrypted, $self->{digest}, DECRYPT); |
my ($account, $password, $description, $extra) |
my ($account, $password, $description, $extra) |
= split /\000/, $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 "Name: '$name'\n"; |
#print "Encrypted: '$encrypted' - Length: " . length($encrypted) . "\n"; |
#print "Encrypted: '$encrypted' - Length: " . length($encrypted) . "\n"; |
#print "Hex: '" . unpack("H*", $encrypted) . "'\n"; |
#print " Hex: '" . unpack("H*", $encrypted) . "'\n"; |
#print "Binary: '" . unpack("b*", $encrypted) . "'\n"; |
#print " Binary:'" . unpack("b*", $encrypted) . "'\n"; |
#print "Decrypted: '$decrypted' - Length: " . length($decrypted) . "\n"; |
#print "Decrypted: '$decrypted' - Length: " . length($decrypted) . "\n"; |
#print "Hex: '" . unpack("H*", $decrypted) . "'\n"; |
#print " Hex: '" . unpack("H*", $decrypted) . "'\n"; |
#print "Binary: '" . unpack("b*", $decrypted) . "'\n"; |
#print " Binary:'" . unpack("b*", $decrypted) . "'\n"; |
#print "\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"; |
|
|
|
|
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); |
|
|
# print length $digest, "\n"; |
# print length $digest, "\n"; |
#-------------------------------------------------- |
#-------------------------------------------------- |
|
|
$self->{digest} = $digest; |
|
return $digest; |
return $digest; |
} |
} |
|
|
|
|
|
|
# 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 |
my $data = $self->{records}->[0]->{data}; |
my $data = $self->{records}->[1]->{data}; |
#die "No encrypted password in file!" unless defined $data; |
#die "No encrypted password in file!" unless defined $data; |
return undef unless defined $data; |
return undef unless defined $data; |
|
|
|
|
|
|
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($self->{password}); |
|
if ($self->{digest}) { |
return 1; |
return 1; |
} else { |
} else { |
return undef; |
return undef; |
|
|
die "No password specified!" unless $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}->[1]->{data}) { |
# Make sure everything is decrypted before we update the keyring |
# Make sure everything is decrypted before we update the keyring |
$self->Decrypt() || return undef; |
$self->Decrypt() || return undef; |
} |
} |
|
|
|
|
# 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 |
$self->{records}->[0]->{data} = $data; |
$self->{records}->[1]->{data} = $data; |
|
|
$self->{password} = $pass; |
$self->{password} = $pass; |
$self->_calc_keys(); |
$self->{digest} = _calc_keys($self->{password}); |
|
|
return 1; |
return 1; |
} |
} |
|
|
# XXX Have to make this encrypt as well as decrypting, but w00 h00! |
# XXX Have to make this encrypt as well as decrypting, but w00 h00! |
# do null padding on the end of a cleartext if we are going to encrypt it |
# do null padding on the end of a cleartext if we are going to encrypt it |
sub _crypt3des { |
sub _crypt3des { |
my ( $self, $plaintext, $flag ) = @_; |
my ( $plaintext, $passphrase, $flag ) = @_; |
|
|
my $passphrase = $self->{digest} || $self->_calc_keys(); |
|
$passphrase .= ' ' x (16*3); |
$passphrase .= ' ' x (16*3); |
my $cyphertext = ""; |
my $cyphertext = ""; |
|
|