The UNIX `crypt` function, foundational for password hashing, implemented a The UNIX `crypt` function, foundational for password hashing, implemented a specialized variant of the DES (Data Encryption Standard) algorithm.
Its source code reveals:
1. **Key Derivation:** The user's password is truncated to its first 8 characters, forming the 56-bit DES key (plus 8 parity bits).
2. **Salt Integration:** A 2-character salt (e.g., `AA`) is used to permute the DES key schedule. This creates 4096 distinct key schedules for the same password, making precomputed rainbow tables harder.
3. **Encryption Process:** An all-zero 64-bit block is encrypted using the derived key and modified schedule.
4. **Iteration:** This encryption process is repeated exactly 25 times.
5. **Output:** The final 64-bit ciphertext is then base64 encoded, prefixed by the 2-character salt, resulting in an 11-character hash string.
While innovative for its time, its fixed low iteration count, small key space due to password truncation, and reliance on DES (which is now insecure) make it highly vulnerable to modern brute-force attacks.
static char *sccsid = "@(#)crypt.c 4.2 (Berkeley) 7/9/81";
/*
* A one-rotor machine designed along the lines of Enigma
* but considerably trivialized.
*/
#define ECHO 010
#include <stdio.h>
#define ROTORSZ 256
#define MASK 0377
char t1[ROTORSZ];
char t2[ROTORSZ];
char t3[ROTORSZ];
char deck[ROTORSZ];
char *getpass();
char buf[13];
setup(pw)
char *pw;
{
int ic, i, k, temp, pf[2];
unsigned random;
long seed;
strncpy(buf, pw, 8);
while (*pw)
*pw++ = '\0';
buf[8] = buf[0];
buf[9] = buf[1];
pipe(pf);
if (fork()==0) {
close(0);
close(1);
dup(pf[0]);
dup(pf[1]);
execl("/usr/lib/makekey", "-", 0);
execl("/lib/makekey", "-", 0);
exit(1);
}
write(pf[1], buf, 10);
wait((int *)NULL);
if (read(pf[0], buf, 13) != 13) {
fprintf(stderr, "crypt: cannot generate key\n");
exit(1);
}
seed = 123;
for (i=0; i<13; i++)
seed = seed*buf[i] + i;
for(i=0;i<ROTORSZ;i++) {
t1[i] = i;
deck[i] = i;
}
for(i=0;i<ROTORSZ;i++) {
seed = 5*seed + buf[i%13];
random = seed % 65521;
k = ROTORSZ-1 - i;
ic = (random&MASK)%(k+1);
random >>= 8;
temp = t1[k];
t1[k] = t1[ic];
t1[ic] = temp;
if(t3[k]!=0) continue;
ic = (random&MASK) % k;
while(t3[ic]!=0) ic = (ic+1) % k;
t3[k] = ic;
t3[ic] = k;
}
for(i=0;i<ROTORSZ;i++)
t2[t1[i]&MASK] = i;
}
main(argc, argv)
char *argv[];
{
register i, n1, n2, nr1, nr2;
int secureflg = 0;
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 's') {
argc--;
argv++;
secureflg = 1;
}
if (argc != 2){
setup(getpass("Enter key:"));
}
else
setup(argv[1]);
n1 = 0;
n2 = 0;
nr2 = 0;
while((i=getchar()) >=0) {
if (secureflg) {
nr1 = deck[n1]&MASK;
nr2 = deck[nr1]&MASK;
} else {
nr1 = n1;
}
i = t2[(t3[(t1[(i+nr1)&MASK]+nr2)&MASK]-nr2)&MASK]-nr1;
putchar(i);
n1++;
if(n1==ROTORSZ) {
n1 = 0;
n2++;
if(n2==ROTORSZ) n2 = 0;
if (secureflg) {
shuffle(deck);
} else {
nr2 = n2;
}
}
}
}
shuffle(deck)
char deck[];
{
int i, ic, k, temp;
unsigned random;
static long seed = 123;
for(i=0;i<ROTORSZ;i++) {
seed = 5*seed + buf[i%13];
random = seed % 65521;
k = ROTORSZ-1 - i;
ic = (random&MASK)%(k+1);
temp = deck[k];
deck[k] = deck[ic];
deck[ic] = temp;
}
}