password encryption...

I am trying to create a sript that will change the users passwd.
At first I thought it would be as simple as calling the passwd prorgam using the user-login and new password as comand line arguments.
Realising that I could not include the passwd at comand line, my other option is to edit the /etc/shadow file directly BUT I need to use the same encryption method and/or salt formula that passwd uses to encrypt the password or else the user will not be able to login. (the clashing of the encryption methods will not allow for password matching).
wow.. talk about a run-on sentence...
The reason for this is that I need to create over 700 accounts and I would like to use a random password generator.
basically what this script does is create the account, asign the password and create a passwd.txt file in the root directory so that later I can inform the users of their initial password.

Marcelo Iturbe
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

perl -i.txt -pe 'BEGIN{($u,$p)=splice@ARGV,0,2; srand($$+time) if $]<5.004; @s=("a".."z","A".."Z","0".."9",".","/"); $s=$s[rand(64)].$s[rand(64)]; $c=crypt($p,$s)} s/^\Q$u\E:[^:]*:/$u:$c:/' $user $password /etc/shadow

sinner052397Author Commented:
Thanks for the code Ozo, but I am having probs trying to implement it.
I tried to place it on multiple lines so that I could implement it in my perl script (and try to understand it)  and came out with something like...
    srand($$+time) if $]<5.004;
s/^\Q$u\E:[^:]*:/$u:$c:/' $user $password /etc/shadow
but I could not get it to work... my guess is that it wouls have something to do with the IF construct?
Could you help me out?
$user $password /etc/shadow
were not part of the script itself, they were the command line arguments to call it with.
-i.txt -p
are also important switches in the call.
the -i could be replaced by setting $^I
and the -p could be replaced by putting a loop around code:
while( <> ){

Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

sinner052397Author Commented:
I modified the code to place it in my script and it works perfect!
It ended up looking something like:
@ARGV = ("shadow");
$^I = ".bak";
srand($$+time) if $]<5.004;
while (<>) {
    if (s/^\Q$u\E:[^:]*:/$u:$c:/) {
    } else {

The found was so that if the account was not found it needs to be created...
Anyways, thanks a bunch and if you would care to close the question with an answer I'll grade it!

sinner052397Author Commented:
The above code has a bug in it... It changes the password, but I cannot use the set password to log in.
I tried taking out the if statement and just have
      while (<>) {
              if (s/^\Q$u\E:[^:]*:/$u:$c:/) {; ...
But that did not work either!

Thanks again!

sinner052397Author Commented:
The above code has a bug in it... It changes the password, but I cannot use the set password to log in.
I tried taking out the if statement and just have
      while (<>) {
              if (s/^\Q$u\E:[^:]*:/$u:$c:/) {; ...
But that did not work either!

Thanks again!

PS. I also tried a few other srand codes I had 'lying' around but they did not work either...
Hmm, without compromising your security, could you post an example of password and corresponding line in /etc/shadow that does work?
(it should be safe enough if you make it a dummy account which you disable before posting)
I just want to verify that the script can duplicate that working entry.
sinner052397Author Commented:
G'day ozzo!
Not to worried about security since I am using dummy accounts on a computer that is not on a network (test puter).

The original passwd file contains (or parts thereof):

Once I ran my script the file looks like


the password that was assigned to abc111 is k8830
In this example I used a 3 salt charecter, I have tried from using 1 salt character upto 5 and no luck.

Are you saying
is the entry that worked for password k8830 or the one that didn't work?
I was interested in an entry that worked, but this is also interesting.
I get crypt('k8830','qS') eq 'qSFY/2n/RbmNw', not 'qSYXnODQQpAJs'
Are you sure you had $p = 'k8830'?
I don't see where you're seting $p in your script
sinner052397Author Commented:
I placed a print statement to print out the password and salt key before it encrypts the password.
The scrypt is now:
        @ARGV = ("/etc/shadow");
        $^I = ".bak";
        srand($$+time) if $]<5.004;
print "Password is $p and salt key is $s\n";
        while (<>) {

The result of the script and entry en /etc/shadow are:
Password is o3529 and salt key is Sb

I then set the password to o3529 using the system passwd program and gave me the following:

I guess the secret is trying to get the right srand call??

perl -e 'print crypt("o3529","w5")'
gives me w5nRObeGk1nhI
which matches your system passwd program, but
perl -e 'print crypt("o3529","Sb")'
gives me SbYebgDiovthY
which doesn't match your perl program
Could your perl have a buggy implementation of crypt?
What do the above two perl commands give you?
And what does
perl -v
How about
perl -V

(I don't think the salt selection should matter much,
I just coded it to pick one randomly, but you could also pass the salt to the script too if you prefer.)

sinner052397Author Commented:
Ok, I think I know where the problem lies, it is in the password
generator: Here is why,
When I hard code the password and salt key such as

    print "Password is c7564 and salt key is w5\n";
    print "Encrypted password is $c \n";

it gives me the same result from the command line:
perl -e 'print crypt("c7564","w5")'

which is: w53IaQOaNz/NM

But when the script sets the variable for the password
(in this case to e5908)
    print "Password is -$p- and salt key is w5\n";
    print "Encrypted password is -$c- \n";
I get the following
    Password is -e5908- and salt key is w5
    Encrypted password is -w5zM737FQVHnk-

I encapsulated the password and crypted passwd with the -- to make sure that there were no "invisible" characters.

I then ran the comand line
    perl -e 'print crypt("e5908","w5"), "\n"'
and got:

Different encryptions! So the problem has to be with the vatiable and the variable is set in the follwing function:

sub setPass {
        $num = int(rand(9999)+1000); # picks a number from 1000 to 10000
        $num2 = int(rand(26)+97);    # ascii code for a character
        $pack = pack ("c4", $num2);  # turns the ascii number to it's character
        $p = "$pack". $num;          # appends the number to the character and gives me my passwd

I needed a simple password generator since the passwords are internal and they
last no longer than 5 days.

Any thoughts?

The reason why I ruled the version of perl our (5.004_4) is because the line
perl -e 'print crypt("o3529","Sb")'
also gave me SbYebgDiovthY

Aha! the pack("c4", $num2);
is giving you
$pack = "e\c@\c@\c@"
$pack = "e"
 pack ("c1", $num2);

(I also think your random password generator may be too predictable, but we can deal with that later)

sinner052397Author Commented:
Wow... I actually have it all working!
I changed the password sub to:
sub setPass {

It's a bit better and it works fine. I did not place any special characters like ! because they were giving me problems. I'm sure the solution was as simple as escaping them \! but I'm just glad it's working!

You have been a great help and very patient!

srand($$+time) is a big improvement over srand($$|time)
but I sitll have some concerns.
One thing I should mention is that 5.004_4 will seed the srand for you and that it's usually better to let it
and you certainly don't want to seed twice, for $pass and for $salt.
But even with only one seeding, there's a danger that someone with just a rough idea when the random number generator was seeded will know that there's only a limited number of passwords that could have been generated during that time period.
And it's even worse if you use the same random number generator for the salt, since knowing what salt was generated could eliminate even more possibilities for the password.
To aleviate the last problem, since the randomness and secrecy of the salt is not critical, I'd suggest taking it from something completely different.
(Perhaps the previous modification time of /etc/passwd)
The limited number of possible password seeds us a more difficult problem, which I'm not sure how to address.
Perhaps you could take some random user input to mix in with the generated random number to keep it from being too predictable?

And one other minor hint, if instead of
you say
then you don't need to change that part of the code if you ever change the set of characters you want to use.
(and you don't get the little bug that you never generate a '9' :-)

#BTW, here's a little trick:
$pass=join'',@s[map rand($_),(0+@s)x6];

Do you have a /dev/random on your machine?

  Ever considered mapping the original password's utility input to a stream, and then simply writing to it to give it the nessesary info?

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Most password utilitys take their input from /dev/tty rather than from stdin,
so mapping the input to a stream may require opening a pty.
Which can be done in Perl, and there are modules like to help you to do it.
But that doesn't address the problem of randomly generating a password.
Or of making sure that it is random enough that someone can't guess the password from a limited number of strings you could have generated based on other clues you may have left, like the time you generated the password, or the salt you generated, or from knowing one of the other 700 passwords generated in the same session...    
 That's not a reason. It'l be VERY hard to guess the password with the simplest
 genereation mechanism (add random numbers) and try to know when is was really
 changed. Also, let the generator source not to be seen by anyone, so they can't even  know the mechanism.  Come on, even FBI could use this as a way. And, if u let the  hacker know the other passwords and other info, that means you're already hacked.
   And no coding will help u then. You can also, to enhance it, use encryption and other
 mathematic functions to create a part of the password, and  these are really hard to break especially if noone sees the source of the generator. And besides does this site
lunches nuclear atacks? That's a LOT of work to pass such security, it's much easier
to adress other unix bugs or even to hack another site. There aren't many sites with that
good of a protection. Trust me, even though I have a lot of ideas of how to protect the site
from potential intruders, for password generation, almost eveything with a 'Random' fits,
as I don't think it's easy nither to get the other 700 passwords nor getting the real Random
table and the CORRECT (and non-covered up) time stamps.  

   Anyway, instead of understing all this, It's MUCH harder to get this generated password
 than to ALL other hacking techniques.  After all, it's better to go for the root not 701 if
 u know 700 already or not.

  Yeah I know, too much of a talk, but the idea should be clear. It's VERY VERY safe.

 Here's a sample:
 Get random number  1 (rnd1)
 Get random number  2 (rnd2)
 wait rnd1 milliseconds
 Get random number 3 (rnd3)
 Combine rnd1 and rnd3 and make it power 2  //   (a*a) is a power 2
 Take the square root of the outcome to xnum1.
 Get random numbe  4 (rnd4)
 if Rnd4 divides with no remainedr on two, then cut any floating point in xnum1 otherwise                                comlete xnum's floating point to one
 Make any adjustments to the number u want (make this as a predifined string selector)
 Use this as a password.

Got a bug there in the generator mechanism - instead of recieving square root out xnum1
 get, for example, the tri-root.
dreamPeace, I think it may be easier to determine the other generated passwords given that you know one than you seem to  suggest.
(and sinner said the users would be informed of their initial password)

Also, where do you get the seed for your Randomize?
The number of different possible seeds limits the number of
possible random sequences you can generate.
The use of  
sub setPass { srand(time|$$); ...
reseeding each invocation with time|$$
was particularly bad, and would make passwords rather easy to guess

 Sorry, I'm was suggesting a general idea, not knowing if it's possible to do.
 I'm not relaying on seed or salt or pepper or anything like this. The simplest random
 mechanism uses the cumputer random table. If the time of the generation of the random
 number is unknown, you have NO way of determining this number.  What's true,
 is that it is possible to reverse the process and retrieve the numbers, but that's cause I'm
 not a cruptography expert. To be sure use the standard RC5 or what's the name by  SOMEHOW  entering the generated numbers and getting a password it'l take, by what
 they say years to decrypt. I know it's already been cracked, so just use another popular
 method. The thing is that hese aren't easy to reverse, and even the army uses them.
 ( Of course, they also have better one's.... :)
Yes, a one way hash like MD5, or using a stream cypher like RC4 to generate a one way hash,
or even using the password crypt hash can make it impractical to directly recover the seed from the hash,
But a days worth of second ticks is only 86400 seeds to test.
With so few possibilitys it could easily be cracked quickly.
Perl 5.004 will try to use a faster clock for the seed if your system has one,
and if you don't sabotage it by reseeding it with a worse one,
but it's still a lot less than the 36^6 possible passwords you may think you're getting.
If you can introduce an additional source of unpredictability,
(and if you're careful how you introduce it so you really get the benefit of both sources, and not just the max, or worse, the min,
of the unpredictability from each source)
then you may be able to improve things.
 OK, I give up guys. I have no expirience with cryptography, and everything I've said
 is good only when the hacker DOESN'T know the agorithm (after all, u CAN hide it,
 and it seems that if anyone get's to the source after u hide it... well u won't need to
 be worried about the passwords he might get. ).  
   I just want to say that every secret police in the world would love to have u. I believe
 that if u can hack custom alogrithms, why not go directly to the root password? I  suppose that compiling a database of all possible passwords and their crypted form
 isn't very hard with a large disk and a very very good PC (and a lot of time). And besides,
 most users trust on the unix password crypting to keep 'em secure, so what's wrong
 with sending a random number with a small modification (+second random)
 DIRECTLY to the cryptoalgorithm and let it take care of it? Comeon, I ask, what will u do
 get the rest of the users and try to guess it? Or maybe u'l login root and get the source?
Well, if you want to depend on keeping the source secret, you might as well just include the list of passwords to return explicitly in yor program.
That way, you can insure they were all produced by a completly random unguessable process.
Otherwise, for someone with little experience in cryptography, and that includes you, me, and 99% of the population, keeping your algorithm a secret only insures that noone will be able to warn you about the exploitable weaknesses that you've probably included in your custom algorithm.

I would hope that the root password on a system would be chosen by a better method than with the generator algorithms presented here,
but in fact, because of the one way hash, even if root can know the contents of the password file,
that doesn't necessarily imply that root can know what the passwords themselves are,
only that root can verify a guess as to what a password is.

A database of all possible passwords, even without their salt, would require an impossibly large disk,
such a database would be useful only if you can restrict the possible passwords in some way,
perhaps to a set of common types of poorly chosen passwords, or to the set of passwords generated by a weak algorithm.

A random number generator is only as unpredictable as its seed,
and another random number from the same source will be completely determined by the earlier ones.
sinner, you still haven't said how you invoke the script
or what sources of randomness you have access to.

If you have someone typing at it, you can extract some randomness from the timing of the keystrokes.

There's also a module to extract randomness from interrupt timing discrepancies .
(but depending on your machine it may be biassed or correlated)

You might also try to do something with disk seek timings...
(although this may be observable by others)

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.