Dropping /etc/shadow

Ca. 451 ord.

On UNIX-systems a normal user nolonger have access to the encrypted password in /etc/passwd. The encrypted password is stored in /etc/shadow and is only readable by root. This is done so that an attacker cannot check every word in a dictionary and combinations thereof (do a dictionary attack) against the encrypted password.

However, it is possible to make this hard and thereby removing the need for protecting /etc/shadow.

Per user seed

One of the nice features of /etc/shadow is that if you copy the password field from one user to another then the other user will have the same password.

Password crackers use this to encrypt one word (which is expensive) and test the encrypted word against every user's encrypted password. E.g. if enc(foo)=bar and user Quux has the encrypted password bar, then Quux's password is foo. If user Baz' encrypted password is bar then Baz' password is also foo.

This could be avoided if the encryption had to take a seed with it. E.g. Let Quux get a random number r; encrypt Quux's password as enc(foo+r)=fubar. If Baz has another random number q and Baz' encrypted password is also fubar, then it is highly unlikely that Baz' password is foo, as it is highly unlikely that enc(foo+q)==fubar.

The per user seed should be larger than the number of users to avoid two having the same seed and can be stored in the encrypted password field along with the encrypted password. The format could be:

The feature of copying passwords by copying password fields is preserved.

Expensive testing

It is fairly cheap to check if a password is the correct password. Password crackers can try more than 100000 passwords per second. However it does not have to be so. It is possible to make the check much harder. By making it hard to check 1 password then a login will take a bit longer, but checking 100000 passwords will take 100000 times longer.

A simple way to do this is to encrypt the ecrypted password again and again for a period of time. A simple algorithm could be like this:

decrypted_password = "foo";
encrypted_password = encrypt(decrypted_password);

while(time-now() < 1 sec) {
  encrypted_password = encrypt(encrypted_password);

Encryption would take 1 sec. You would need to save both the encrypted_password and the number of times it was encrypted, e.g.

Checking the password would be:
decrypted_password_to_check = "foo";
encrypted_password = encrypt(decrypted_password_to_check);

while(--encrypted_times) {
  encrypted_password = encrypt(encrypted_password);

if(encrypted_password == encrypted_password_from_password_file)
On the same machine this would take 1 sec. On a faster machine this will be faster, but not nearly as fast as a simple hash-function.

Sidst ændret Sat Jul 30 19:22:51 2005