perl "password safe"-like program -- pws.pl

R

Robert Jacobson

Hi,

On a Windows platform, I typically use the program "Password Safe" to
keep all my passwords. But, as it only works on Windows, I was
looking for a cross-platform solution.

I wrote a program (below) that has the basic functionality of the
program -- it stores your passwords in a database, encrypting both the
keys (except the KEYCHECK key) and the values with blowfish. I guess
someone could brute-force the password by encrypting the string
"JUSTCHECKING" with blowfish, trying a bunch of different passphrases.
How long would that take, assuming, say, an 16 characters passphrase?

Also, the passphrase to encrypt/decrypt is obviously stored in memory.
I don't think there's a way around this -- but how easy would it be
to get it out of memory? AFAIK, the Windows version also stores the
password in memory.

I'm pretty new at perl, so I had hoped someone here could tell me
whether my program really was as secure as I thought. The script is
below. Hold no punches (polite punches appreciated :-D ), tell me how
it is. What works, what doesn't work... whatever.

---BEGIN script---
#!/usr/bin/perl

#------------------------------------------------------------------------
# pws.pl
#"password safe"-like program in perl
# released under the BSD license
# Copyright (c) 2003, Robert Jacobson
# All rights reserved.
#------------------------------------------------------------------------

use Crypt::CBC;
use Term::ReadKey;

$SIG{INT} = clean_up;

sub clean_up {
print "Caught SIGINT, cleaning up...\n";
dbmclose(%PWS) or die "could not close database: $!";
ReadMode 0;
exit;
}

# I have no idea how to use "tie", so I'm stuck with dbm...
dbmopen(%PWS,"pws",0600) or die "Could not open database: $!";

# hash key by title, record contains
# login, pass, notes(??)

$JOIN = " "; # That's a tab, not a space

#Check for correct password
if ($PWS{KEYCHECK} eq "") {
# New database
$keymatch = 0;
while ($keymatch == 0) {
$key = "";
while (length($key) < 8) {
print "Enter new database key: ";
ReadMode 2;
chomp($key = ReadLine);
ReadMode 0;
print "\n";
if (length($key) < 8) {print "Too short\n";}
}

print "Confirm database key: ";
ReadMode 2;
chomp($key2 = ReadLine);
ReadMode 0;
print "\n";
if ("$key" ne "$key2") {
print "Keys don't match, try again\n";
} else {
$keymatch = 1;
}
}

print "Creating database...";
# Create a entry just for checking right key
$plaintext = "JUSTCHECKING";
$cipher = Crypt::CBC->new( {'key' => "$key",
'cipher' => 'Blowfish'} );
$ciphertext = $cipher->encrypt($plaintext);
$PWS{KEYCHECK} = "$ciphertext";
print "\n";
} else {
# Existing database
print "Enter key to database: ";
ReadMode 2;
chomp($key = ReadLine);
ReadMode 0;
print "\n";

# Check for right key
$cipher = Crypt::CBC->new( {'key' => "$key",
'cipher' => 'Blowfish'} );
$plaintext = $cipher->decrypt($PWS{KEYCHECK});
if ($plaintext eq "JUSTCHECKING") {
#print "That's right\n";
} else {
print "incorrect key\n";
dbmclose(%PWS);
exit;
}
}


while (1) {
print "Options:\n";
print "\t1. New Entry\n";
print "\t2. Read Entry\n";
print "\t3. Delete Entry\n";
print "\t4. Exit\n";
print "\nWhich? ";
chomp ($choice = <STDIN>);

if ($choice == 1) {&new_entry};
if ($choice == 2) {&read_entry};
if ($choice == 3) {&delete_entry};
if ($choice == 4) {
dbmclose(%PWS);
exit;
}
}

sub new_entry {
print "Enter title: ";
chomp($title = <STDIN>);

print "Enter login: ";
chomp($login = <STDIN>);

$match = 0;
while ($match == 0) {
$pass1 = "";
print "Enter pass: ";
ReadMode 2;
chomp($pass1 = ReadLine);
ReadMode 0;
print "\n";

print "confirm pass: ";
ReadMode 2;
chomp($pass2 = ReadLine);
ReadMode 0;
print "\n";

#confirm they match
if ("$pass1" ne "$pass2") {
print "They don't match,try again!\n";
} else {
$match = 1;
}
}

&encrypt_string;

#Even the hash key (title) is encrypted
$encrypted_title = $cipher->encrypt("$title");
$PWS { $encrypted_title } = "$ciphertext";
}

sub read_entry {
$showall = 0;
print "Enter title (blank for all entries without passwords): ";
chomp($title = <STDIN>);

if ($title eq "") {
$showall = 1;
} else {
$encrypted_title = $cipher->encrypt("$title");
}

print "\n";
print "Title login\tpass\n";
print "----- -----\t----\n";

for $encrypted_titles (sort keys %PWS) {
#print "key is $encrypted_titles\n";
next if $encrypted_titles eq KEYCHECK;
unless ($showall) {
#print "skipping\n";
next if "$encrypted_titles" ne "$encrypted_title";
}
$plain_title = $cipher->decrypt("$encrypted_titles");
$plaintext = $cipher->decrypt("$PWS{$encrypted_titles}");
if ($showall) {
# Dont show the password
$plaintext =~ s/\t.*/\tHIDDEN/;
}
printf("%-21s%s\n",$plain_title,$plaintext);
}
print "\n";
}

sub delete_entry {
print "Enter title to delete: ";
chomp($title = <STDIN>);

$encrypted_title = $cipher->encrypt("$title");
delete($PWS { $encrypted_title });
}

sub encrypt_string {
# Blowfish encrypt the information
$string_to_encrypt = "$login" . "$JOIN" . "$pass1";

$ciphertext = $cipher->encrypt("$string_to_encrypt");

return 1;
}
 
A

Anno Siegel

Robert Jacobson said:
Hi,

On a Windows platform, I typically use the program "Password Safe" to
keep all my passwords. But, as it only works on Windows, I was
looking for a cross-platform solution.

I wrote a program (below) that has the basic functionality of the
program -- it stores your passwords in a database, encrypting both the
keys (except the KEYCHECK key) and the values with blowfish. I guess
someone could brute-force the password by encrypting the string
"JUSTCHECKING" with blowfish, trying a bunch of different passphrases.
How long would that take, assuming, say, an 16 characters passphrase?

Also, the passphrase to encrypt/decrypt is obviously stored in memory.
I don't think there's a way around this -- but how easy would it be
to get it out of memory? AFAIK, the Windows version also stores the
password in memory.

Sorry to be so blunt, but when you have to ask these questions on Usenet,
you are not enough of a security expert to publish security-related
software. The copyright and license comments in the code below makes me
think you intend to distribute the program in some way.
I'm pretty new at perl,

Another reason not to distribute sensitive software.
so I had hoped someone here could tell me
whether my program really was as secure as I thought. The script is
below. Hold no punches (polite punches appreciated :-D ), tell me how
it is. What works, what doesn't work... whatever.

It is your program, and you will have to account for it. Even if someone
here certified your program as flawless, (no-one sane will), what would
you have gained?

Use the program for yourself for a while. Try to crack it. Make it weaker
until you *can* crack it. Read about computer security, if your interest
goes that way. After a some of this you may develop a sense for the
quality of your program.

[code snipped]

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top