9

I'm writing a Perl script that needs to connect to an SMTP server in order to send a mail, but I really don't like this kind of things :

my $pass = '123456';

And I found Data::Encrypted, that should allow the user to prompt it the first time and then store it encrypted.

use Data::Encrypted file => ".passwd", qw(encrypted);
my $password = encrypted('password');

But I cannot make it work, it makes a running time error :

Bad key file format at /Library/Perl/5.12/Data/Encrypted.pm line 78

Is anybody having the same issue, or know another way to hide/protect password?

3
  • 3
    even if it works, how are you going to decrypt it? Commented Aug 3, 2012 at 10:23
  • maybe md5 will helps you, checking sum and all... Commented Aug 3, 2012 at 10:29
  • Yes, I see it too. The problem is in Crypt::RSA::Key::Private::SSH::deserialize line 68. croak "Bad key file format" unless $id eq PRIVKEY_ID; $id is -----BEGIN RSA PRIVATE KEY-----, PRIVKEY_ID is SSH PRIVATE KEY FILE FORMAT 1.1. Commented Aug 3, 2012 at 11:11

4 Answers 4

12

The Data::Encrypted module was last released in 2001. I'd say that's a good sign not to use it.

Normally, I'd say storing passwords at all is a bad idea even encrypted. However, if you must store a password for use contacting another system, encrypting it is the way to go. The way I would do it is something like this:

# Rijndael is also known as AES, which is the encryption standard used by the NSA
use Crypt::Rijndael;
use IO::Prompter;

# This secret is exactly 32 bytes long, you could prompt for this as a
# passphrase or something and pad it with spaces or whatever you need
my $app_secret = 'this_is_the_key_the_app_uses....';

# Setup the encryption system
my $crypto = Crypt::Rijndael->new( $app_secret, Crypt::Rijndael::MODE_CBC() );

# Ask the user to enter the password the first time
my $password = prompt "password: ", -echo => ''; # from IO::Prompter

# Encrypt the password. You can save this off into a file however you need to
my $enc_password = $crypto->encrypt($password);

# Later load it from the file and decrypt it:
my $password = $crypto->decrypt($password);

For more information see Crypt::Rijndael and IO::Prompter.

Sign up to request clarification or add additional context in comments.

3 Comments

A bit off topic, but what do you gain with this? If you prompt for the passphrase, you could just as well prompt for the password directly. And if you hard code the passphrase, it doesn't help much in hiding your 'encrypted' password. Or an I missing something?
You don't have to prompt for the passphrase, that's just one possible way of making it more secure. Also, if there are multiple passwords to protect, one passphrase is easier to type and remember than multiple passwords.
Even without a passphrase and just storing the app secret in a separate file or even in the script itself, you can avoid someone accidentally reading your real SMTP password inadvertantly. If someone is able to steal the password file, but doesn't get the app secret, you get a delay between the password being stolen and the password being cracked. It's pretty thin as far as security goes, but it's slightly better than nothing.
3

Thanks ! Here is my final solution :

sub smtp_passwd(){
    #The secret pass phrase
    my $app_secret = 'd.<,3eJ8sh[(#@1jHD829J,Z!*dGsH34';

    #password file name
    my $passwd_file_name = ".passwd";

    # Setup the encryption system
    my $crypto = Crypt::Rijndael->new( $app_secret, Crypt::Rijndael::MODE_CBC() );

    #File Handler
    my $passwd_file;

    #If we cannot open the password file we initiate a new one
    unless ( open ( $passwd_file, '<', $passwd_file_name) ) {

        #Create a new file in write mode
        open ( $passwd_file, '>', $passwd_file_name);

        # Ask the user to enter the password the first time
        my $password = prompt "password: ", -echo => ''; # from IO::Prompter

        #Password must be multiple of 16 (we deliberately chose 16)
        my $pass_length = 16;

        #If password is to short we complete with blank
        $password = $password." "x ($pass_length - length ( $password ) ) if ( length ( $password ) < $pass_length );

        #If password is to long we cut it
        $password = substr ( $password, 0, $pass_length ) if ( length ( $password ) > $pass_length );

        #Encryption of the password
        my $enc_password = $crypto->encrypt($password);

        #we save the password in a file
        print $passwd_file $enc_password;

        #we close the file ( Writing mode )
        close $passwd_file;

        #Reopen the file in reading mode
        open ( $passwd_file, '<', $passwd_file_name)
    }

    #Loading the password en decrypt it
    my $password = $crypto->decrypt( <$passwd_file> );

    #Close the file
    close $passwd_file;

    #Return the password ( Here the password is not protected )
    return $password;
}

Comments

3

When you are dealing with a script that is sending a plain text password to a service without any user interaction, you are already doomed. Any solution you come up with will be just security by obscurity. You can come up with a solution as zostay did. But it is equivalent to buying the most advanced vault but leaving the key under the mat and sticking paper with the text: "Check the mat for the key!" to the front door. Look, I will just copy the script, grep for the password. Then I will find a line like my $password = $crypto->decrypt($password); and place warn $password; Just below the line, run the script. That's it. I don't care what algorithm you use, I don't care where and how you store the password. You can make it harder, but my effort to crack will always be several orders of magnitude less than your effort to make it hard. Your script is the key. Look at the movie industry. They spent billions to come with the bunch of silly crap. They ended up with a special HW, and even the cable had its key. Hilarious! It is harassing only fair users.

Place a plain password in the script if you don't want to look silly. If you want to go with security by obscurity, then don't name variables with sensible names, don't use any standard module (look, method decrypt is a clue!), and don't waste your time with sophistication. I will not look at how you store or encrypt the password, I will look at where you will have to use it and hook up there. It is much easier and much harder to hide.

Comments

0

here is the full blown code which utilizes part of code mentioned above and part taken from the Perlmonk. The script first asks the username and password from the user, encrypts and stores it in the .crypt file. Then reads from it, decrypts and shows the original text. On second time it will use the existing user credentials.

use Crypt::Rijndael;
use IO::Prompter;
use Crypt::CBC;
#keys
my $key = "a" x 32;
my $cipher = Crypt::CBC->new( -cipher => 'Rijndael', -key => $key );
my @plaintext;
my @ciphertext;
#keys

#filefield
#password file name
#my $file_name = ".crypt";
my $file_name = ".crypt";
#File Handler
my $file;


#If we cannot open the password file we initiate a new one
unless ( open ( $file, '<:encoding(UTF-8)', $file_name) ) { #<:encoding(UTF-8)
#Create a new file in write mode
    open ( $file, '>', $file_name);
    $plaintext[0]= prompt "Username:";
    $plaintext[1]= prompt "Password:", -echo => '';
    print "#################################################################################\n";
    print "# User credentials will be encrypted and stored in .crypt file and same is      #\n"; 
    print "# reused next time.  If you need to add new user credentials delete the .crypt  #\n";
    print "# file and re run the same script.                                              #\n";
    print "#################################################################################\n";
    $plaintext[0]=~ s/^\s*(.*?)\s*$/$1/;
    $plaintext[1]=~ s/^\s*(.*?)\s*$/$1/;


    while($plaintext[0] =~ /^\s*$/){
    $plaintext[0]= prompt "Username is mandatory:";
    $plaintext[0]=~ s/^\s*(.*?)\s*$/$1/;
    }
    while($plaintext[1] =~ /^\s*$/){
    $plaintext[1]= prompt "Password is mandatory:";
    $plaintext[1]=~ s/^\s*(.*?)\s*$/$1/;
    }


    $ciphertext[0] = $cipher->encrypt($plaintext[0]);
    $ciphertext[1] = $cipher->encrypt($plaintext[1]);

    #we save the password in a file
    print $file $ciphertext[0];

    #print $file "\n";
    #we save the password in a file
    print $file $ciphertext[1];
     #we close the file ( Writing mode )
    close $file;

    #Reopen the file in reading mode
    open ( $file, '<', $file_name)
 }


 my @holder;
 my $content;
if (open( $file, '<', $file_name)) {
  #chomp(@holder = <$file>);
 local $/;
    $content = <$file>;

} else {
  warn "Could not open file '$filename' $!";
}
@holder = split(/(?=Salted__)/, $content);
  print "Encrypted username:",$holder[0];
  print "\n";
  print "Encrypted password:",$holder[1],"\n";

 #Loading the password en decrypt it
$plaintext[0] = $cipher->decrypt( $holder[0] );
$plaintext[1] = $cipher->decrypt( $holder[1] );

print "\n\n";

print 'Username is:',"$plaintext[0]\n";
print 'Password is:',"$plaintext[1]\n";
#Close the file
close $file;

#filefield

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.