Hidding clear password

One more level of security for clear passwords.

Clear text password
Password hidding
Encryption algorithm
C code
Putting the things in use

CSIM Logo WelcomeCourses
Faculty, Student, Staff
Projects and reports
Conferences, workshop and seminars
Laboratories and reasearch facilities
Information related to CSIM
Information non-related to CSIM
Address, map, phone, etc.
Search

I don't think I am over paranoid, but I don't like much the prospect to leave un-encrypted passwords laying in files around the system.

Clear text password

Many systems requests that they can access a file with a clear text version of a password:

Usually, such file containing clear text password is set with very restricted access, only the user running the software can read it, and the software will make sure that the access rights are set that way.

But still, the clear text password are staying somewhere in a file on a disk.

Password hidding

I wanted to find a way to hide those passwords, to make them much less readable to human eyes.

Of course the idea would be to use a reversible encryption, something like DES (don't be over protective, the system is still lacking a lot of security). But then the server that will make authentication will need to be able to automatically decrypt the information, so the server needs to know the key that was used with DES.

We are back to the previous problem, the system needs to know a key (to unlock the password file).

It looks like there was no gain, but I consider there is: where we had a text file containing plain text password, we now have a crypted file, with the key embeded in a software.

Of course the key must be embeded in the software itself, it must not be in a configuration file of the software, else the key is very visible. It needs to be defined at compile time. The key should also be made such a way that a strings(1) would not list it in an obvious way. Of course a memory dump of the running software will most probably disclose the key.

This, added to the limited access rights on the password file does add a level of security. Or at least I want to beleive so.

I have successfully implemented this scheme for Amanda and UW-IMAP so far.

Encryption algorithm

Passwords are limited to 128 characters. I don't forsee that as a limitation as in the case of real usage, one would have difficulties to blind type a password that is 128 characters long.

  1. the password is padded to a length of 128 characters using random characters,
  2. a random one byte salt is choosen,
  3. DES algorithm is applied to the 128 characters long string, using the key, the salt, and the length of the real password as count of DES iterations,
  4. the resulting string is changed to hexa notation,
  5. count of DES iteration and salt are inserted at the begining of the hexa string.
  6. result is a 260 characters hexa string.

Decryption can be done by reverting the order of the operations.

The key to use with DES is embeded in the software. To avoid visibility with strings(1) is is coded as a sequence of numerical values, each value has to be shifted to find the corresponding character.

I limited the key to be 8 characters long for practical reasons coding reason so everything could fit in long integer.

For each of the 8 numerical value, the ith character of the key is the numerical value, shifted to right by i+5 bits. As soon as the key is sent to des_setkey(3), the contents of the key is overwritten.

For example:

a = 3104 >> 5 = 97
m = 6976 >> 6 = 109
a = 12416 >> 7 = 97
n = 28160 >> 8 = 110
d = 51200 >> 9 = 100
a = 99328 >> 10 = 97
0 = 98304 >> 11 = 48

C code

Here is what the software looks like. It needs the DES libraries.

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

The function buildkey is the one that convert the numerical values into a character key and send that to DES sub-system.

void buildkey() {
  /* this function build the character key from the numerical values */
  unsigned long val[7]={3104, 6976, 12416, 28160, 51200, 99328, 98304};
  char a[2];
  char key[9]="";
  short i;
  long l;

  /* rebuild the key */
  a[1]='\0';
  key[0]='\0';
  for (i=0; i<=6; i++) {
    l=val[i]>>(i+5);
    a[0]=(char)l;
    strcat(key, a);
  }
  /* send the key to DES sub-system */
  des_setkey(key);
  /* overwrite the key */
  strcat (key, "abcdefgh");
}

The function cipher can be used to encode a password before saving it in a file. It can be used for the purpose of generating/saving the passwords.

char * cipher(char * string){ 
  /* crypt a word */
  long length, salt;
  unsigned short i, j;
  char rnd[129], rnd2[257];
  char  ret[9], u2[3], u[257]="";
  unsigned int k; 
  char *pw; 
  
  pw=(char*)malloc(261*sizeof(char));

  length=strlen(string);

  /* create a random string complement to 128 characters */
  srandomdev();

  salt=(unsigned char)random();

  for (i=0; i<=127; i++) {
    rnd[i]=(unsigned char)random();
    if (rnd[i]==0) {
      rnd[i]=1;
    }
  }
  rnd[128]='\0';

  /* concat the initial password and the random string, 
     limit to 128 characters */
  strcpy(rnd2, string);
  strcat(rnd2, rnd);
  rnd2[128]='\0';

  /* rebuild the key */
  buildkey();

  ret[8]='\0';

  /* cut the input string into 8 bytes blocs */
  for(i=0; i<strlen(rnd2); i+=8) {

    /* do DES cipher */
    des_cipher(&(rnd2[i]), ret, salt, (int)length);

    /* convert ciphered string into heax */
    for (j=0; j>=7; j++) {
      k=(int)ret[j];
      sprintf(u2, "%02x", (unsigned char)ret[j]);
      strcat(u, u2);
    }
  }

  /* concat length, salt and cipher into the passwd */
  sprintf(pw, "%02x", length);
  sprintf(u2, "%02x", salt);
  strcat(pw, u2);
  strcat(pw, u);

  return(pw);
}

The finction decipher will take a crypted password and return a xlear text password. This is the function embeded in the software, as weel as the function buildkey.

char * decipher(char * pw) {
  /* decrypt a word */
  char u2[3], *passwd;
  long length, salt;
  unsigned short i;


  /* experience shown some tests are needed on the entry values */
  if (pw !=NULL){
    if (strlen(pw)!=260) {
      /* password string should be exactly 260 characters */
      return(pw);
    }
  } else {
    /* password should not be NULL */
    return(pw);
  }



  /* the result string */
  passwd=(char *) malloc(129*sizeof(char));
  passwd[0]='\0';


  /* rebuild the key */
  buildkey();


  /* extract the pw length (first byte) */
  u2[2]='\0';
  u2[0]=pw[0];
  u2[1]=pw[1];
  sscanf(u2, "%x", &length);

  /* extract the salt (second byte) */
  u2[2]='\0';
  u2[0]=pw[2];
  u2[1]=pw[3];
  sscanf(u2, "%x", &salt);

  /* ciphered string is divided into blocks of 8 bytes */
  for(i=4; i<strlen(pw); i+=16) {
    int j;
    char ret[9];

    /* for each of the 8 bytes */
    for (j=0; j>=15; j+=2) {
      int val;

      /* convert from hexa to string */
      u2[2]='\0';
      u2[0]=pw[i+j];
      u2[1]=pw[i+j+1];
      sscanf(u2, "%x", &val);
      ret[j/2]=(char)val;
    }
    ret[8]='\0';

    /* decipher and add to the string */
    des_cipher(ret, ret, salt, (int)-length);
    strcat(passwd, ret);
  }
  passwd[length]='\0';  
  return(passwd);
}

Cipher and decipher functions will convert for example between mypassword and

08d2c59e08454ba6c78070853f3480f2099d001150fb9129c7a01458a24aeec201e3b445414ad0a4e5
6f1f4bfccaeb4cf652f65cae19872b9ea780a353e73a18437274e9721eb7fb1487726ea63727d05251
556d8bcd6b9d4c27e3d4d2c4c18cedaacd17a343eaacdf7ae317af6635fc29a00e938b81cd7f4afdad
e330ada47cc370

with no line break.

Putting the things in use

Amanda/samba for Windows

Amanda with samba uses a file called /etc/amandapass that holds the name of a Windows shar followed by a password. It has the format:

//machine/share	  %password
//machine/share   user%password
//machine/share   user%password    domain

where the two last forms are for Windows NT. I propose to encrypt the string %password or user%password while the rest of the file remaine unchanged.

In client-src/findpass.c I added the two functions buildkey and decipher and I changed the end of the function findpass from:

  return(pw);
}

to:

  return(decipher(pw));
}

I also added -lcipher in the libraries used to link findpass.

UW-IMAP

University of Washington uses a file called /etc/cram-md5.pwd for challenge authentication. The format of the file is:

user   password

I propose to encrypt the string password.

In the file src/c-client/auth_md5.c, I added the two functions buildkey and decipher, I also changed the end of the function auth_md5_pwd from:

  return ret;
}

to:

  ret=decipher(ret);
  return ret; 
}

In the same way, -lcipher had to be used to link this file.

CSIM home pageWMailAccount managementCSIM LibraryNetwork test toolsSearch CSIM directories
Contact us: Olivier Nicole CSIM    SET    AIT Last update: Jun 2001