http://www.perlmonks.org?node_id=223643

eoin has asked for the wisdom of the Perl Monks concerning the following question:

Alright everyone, I have this user registration program that i'm writing, i've decided not to use conventional
password scripts\fields mainly because i'm only starting with perl and don't no how. So i've decided to use
random mnemonic passwords, encripted.I use,
my( $s ) = @_; srand( $s ^ time ); my @c = split / */, "bcdfghjklmnpqrstvwxyz"; my @v = split / */, "aeiou"; for($i = 1; $i <= 4;$i++){ print $c[int(rand(20))], $v[int(rand(5))]);
to generate a password. (This creates eazy to prenounce passwords made upof 4 sylables. e.g.votahubo,
instead of a jumble of nums and letters)

And I use this little number supplied by "ergowolf" to encrypt it:
sub encryption{ my( $type ) = @_; chomp($type); $password =~ tr/N-ZA-M/A-Z/; $password =~ tr/n-za-m/a-z/; return $type;

(Full script is available in the code section\cryptography
under Cheseey Crypt or the likes. Its the first link anyway.)

Ok the problem i'm having is probably very simple to solve, but be kind, I'm only new to this.
Instead of using print to display the password created using the for function in the first piece of code displayed above, I want to get it to save to a variable so i can encrypt it but since its in a for loop the value created just overrights the previous value rather than appending to the end of it.
Can any one help??
Thanks, appreciate it, Eoin..

Replies are listed 'Best First'.
Re: ??Mnemonic Passwords??
by tachyon (Chancellor) on Jan 02, 2003 at 00:50 UTC

    I suggest you read my rather comprehensive answer to your coding problems with this script posted at Re: To register or not (2)!!! which shows you how to do this as well as fixing a number of other issues with your script.

    You have to be joking about using ROT13 encryption right? - that cipher was broken when Ceasar was king. If you want to store passwords you don't need a crappy weak pointless cipher like that. Just do this:

    my $password = password(5); my $salt = 'Na'; # any two char string will do my $encrypted = crypt( $password, $salt ); print "The encrypted version of $password is $encrypted\n"; print 'Gimmee the password: '; chomp( my $answer = <> ); print check_password($answer) ? "OK" : "Wrong"; sub check_password { my $to_check = shift; # I would normally use return COND ? TRUE : FALSE; # like this # return (crypt( $to_check, $salt ) eq $encrypted) ? 1 : 0; # but here it is in baby perl if ( crypt( $to_check, $salt ) eq $encrypted ) { return 1 } else { return 0 } } sub password{ my $s = shift; srand( $s ^ time ^ $$ ); @c = split //, "bcdfghjklmnpqrstvwxyz"; @v = split //, "aeiou"; my $password = ''; $password .= $c[int(rand(21))] .$v[int(rand(5))] for 1..4; return $password; }

    crypt is a one way hashing algorithm so to check a password you encrypt it and see it it matches the encrypted password. You only store the encrypted password. You can't decrypt one way hashes - thus they are generally more secure than ciphers as the only real way to attack them is a brute force dicttionary attack where you encrypt words and see if they match the hashed value.

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      crypt and other one-way hashing algorithms are not appropriate for every application. Ever try to maintain thousands of user accounts where everyone's password is crypt'ed? It's no fun when you have no way of reminding them what their password is when they forget. Storing passwords in the clear may not be the most secure thing in the world, but if the application isn't critical the convenience may FAR outweigh the lack of security. Both Slashdot and Perlmonks store their password lists un-crypt'ed for that very reason, so that they can email it to people who forget.

      The original poster's ROT13 encryption might not be secure, but it's at least reversable, which gives you (slightly) more security than storing plaintext passwords. Sure, he's putting up a chain-link fence instead of a guard tower, but there's a reason why people still use chain-link fences. :-)

      Gary Blackburn
      Trained Killer

        Given that you can have an industrial strength fence for essentially the same price as a decorative ROT13 one why not just:

        use Crypt::Blowfish; use Crypt::CBC; $KEY = 'GNUisnotUnix'; # Blowfish will take 56 bytes (448 bits) of ke +y my $cipher = new Crypt::CBC( $KEY, 'Blowfish' ); my $enc = encrypt('Hello World'); my $dec = decrypt($enc); print "$enc\n$dec\n"; sub decrypt { defined $_[0] ? $cipher->decrypt_hex($_[0]) : '' } sub encrypt { defined $_[0] ? $cipher->encrypt_hex($_[0]) : '' }

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      In addition to everything else tachyon (and others) have said, I'm going to repeat something I've already mentioned twice and which has gone ignored --

      The arguments to rand() should not be hard-coded "magic" numbers, but should be the lengths of the arrays themselves.

      It is also worth noting that the int() calls are superfluous, because array indices are automatically int-ified. So:
      $c[ rand @c ] , $v[ rand @v ]

      jdporter
      The 6th Rule of Perl Club is -- There is no Rule #6.

        # map returns a list so although print password(5); # result abcdefgh $p = password(5); print $p ; # result 8 # one fix is to use return join '',map { $c[ rand @c ], $v[ rand @v ] } 1..4;

        poj
        JD, when i applied your teqnique for my password generation
        sub password { my( $s ) = @_; srand( $s ^ time ); my @c = split / */, "bcdfghjklmnpqrstvwxyz"; my @v = split / */, "aeiou"; return map { $c[ rand @c ], $v[ rand @v ] } 1..4; }
        It returned the length of the total array, which is 8.(4 two letter sylables). And that isn't what i wanted to do. I wasn't sure how to fix this because $me = newbie.
Re: ??Mnemonic Passwords??
by Trimbach (Curate) on Jan 02, 2003 at 00:01 UTC
    There's a couple of ways to do this. One way is to simply concatenate the pair of letters onto a scalar variable during the loop, and then "encrypt" the scalar when you're done, like:
    my $password; for($i = 1; $i <= 4;$i++){ $password .= $c[int(rand(20))] . $v[int(rand(5))]); } my $encrypted_pass = encryption($password);
    ..and that's it. Note the "." between the two characters, replacing the comma when you were printing the values to the screen. Hope this helps. :-)

    Gary Blackburn
    Trained Killer

      (Note: for some reason I'm getting logged out when trying to reply to the parent node of this thread, so this isn't really a reply to Trimbach :) What you need is to make sure you are adding your characters to a variable defined in an enclosing scope of your loop. This can be either a global/dynamic variable, or better, a lexical just like Trimbach's example. See What's a reference? What's a variable? What's scope? for an excellent recent discussion. Also, you can skip a step in your array initializations like so:

      my @c = qw/b c d f g .../; my @v = qw/a e i o u/;

      That said, I hope these passwords aren't going to be protecting anything of importance, because they are very weak. The central problem is that there is little entropy, or true randomness, involved in the password generation. Using the current time as a seed is a common technique, but if an attacker determines the clock setting on your server, all of your entropy is gone, and it's just a matter of feeding input values into various functions to find out how you are generating passwords. The fact that you've got alternating consonants and values gives an attacker an easy start.

      Secondly, the "encryption" function is virtually useless because it's a simplistic and static translation. Take a look at the builtin crypt for a good, oneway encryption function.

Re: ??Mnemonic Passwords??
by iguanodon (Priest) on Jan 02, 2003 at 11:11 UTC
    Just FYI, for generating passwords you might be interested in easypass.pl. It uses dictionary words and can easily generate passwords that include numbers or non-alphanumeric characters.
Re: ??Mnemonic Passwords??
by Juerd (Abbot) on Jan 02, 2003 at 13:01 UTC
      Cool, thanks. This is a much better solution for the OP's problem than my response above.
        I dunno, man, that easypass.pl script looks pretty slick. The only special thing about Crypt::RandPasswd is that it attempts to be FIPS-181 compliant. (I'm not sure that it really is, though.)

        jdporter
        The 6th Rule of Perl Club is -- There is no Rule #6.

      This calls on the file "Crypt/RandPasswd.pm " I have it but I can't rename the file with a foward slash(/) in it.What do I do? Can I edit the module to refer to whatever file I want??
      Thanks, Eoin..
        Please tell us why you think you would need to edit the module? If you have Crypt::RandPasswd correctly installed, then Perl should be able to find it without needing any extra help. If you tell us the error message you are getting then maybe we can help you.
Thanks everyone!
by eoin (Monk) on Jan 02, 2003 at 12:42 UTC
    I also had this other idea of using the persons I.P address in someway to generate a password, maybe multiplying (the first and last fields together) and (the middle two together) of the i.p address and then adding them and creating a password from a random choice of a num -to- letter grid. E.g. z=1, x=3, w=5 up to 9 and then down agin on every other number. And then do a different one with the letters I didn't use(using numbers 1-9 so I don't go into duble digits)and maybe one with random letters in it.
    I have a few theories involving password creation via I.P address such as changing to hexdecimal, and changing the value then changing back and converting to an alphanumeric using the method above or perhapse a different method.
    After that i could encrypt it using one of the methods above. Is this a common way of generating passwords??
    Thanks Eoin