philip@axis.UUCP (02/21/87)
Since posting the original article, it has become apparent that many UNIX systems (and DOS) lack the makekey program, and sometimes even the crypt(3) functions. This is not actually too important - I only used makekey/crypt because it was there. The crypt(3) function is complicated - based upon the DES algorithms. It is used normally on UNIX to generate the encrypted passwords which are stored in the password file. Since these are publicly available, a good encryption routine is needed to stop people deriving the password from its crypted form. In my crypt program, the result of this routine is used simply to seed a pseudo-random number generator. The 'string' used to do this is never stored anywhere outside the program, thus it is not too important if it is possible to derive the input key from this initialisation string. What this means is that you can replace crypt(3) with just about anything. You can even use the password that the user gives directly, although I would suggest using some method of generating something a little longer to use as the intialisation string - like replicating the users key (for example). Doing this should not do too much damage to the security of the system (but then I am no expert in these matters ...) The following is a hacked version of the original, without any calls to makekey or crypt(3) - it should be suitable for UNIX systems with no encryption available, and even for DOS - if you can write your own version of getpass(3). This version simply replicates the input key until it is 13 characters long, and uses that to seed the random number generator. If it is important that data encrypted on one machine should be decryptable on another, this is probably the version to use, since some vendors seem to have replaced the DES based crypt(3) with their own version, and thus systems using that will not be compatible. Philip ============================================================================= #include <stdio.h> #define ROTORSIZ 256 #define MASK 0377 #define EMPTY 07777 #define X_SIZE 4099 char *strrchr(); unsigned r1[ROTORSIZ]; unsigned r2[ROTORSIZ]; unsigned r3[ROTORSIZ]; unsigned char x[X_SIZE]; init(password, decrypt) char *password; int decrypt; { register int index; register int i; unsigned random; long seed = 123L; char buf[14]; strncpy(buf, password, 13); while (strlen(buf) < 13) strncat(buf, password, 13 - strlen(buf)); for (i = 0 ; i < ROTORSIZ; i++) r1[i] = r2[i] = r3[i] = EMPTY; for (i = 0; i < 13; i++) seed = seed * buf[i] + i; i = 0; while (i < ROTORSIZ) { seed = (long)(5L * seed + (long)i); random = (unsigned)(seed % 65521L); index = (int)(random & MASK); if (r1[index] == EMPTY) r1[index] = i++; else continue; } i = 0; while (i < ROTORSIZ) { seed = (long)(5L * seed + (long)i); random = (unsigned)(seed % 65521L); index = (int)(random & MASK); if (r2[index] == EMPTY) r2[index] = i++; else continue; } i = 0; while (i < ROTORSIZ) { seed = (long)(5L * seed + (long)i); random = (unsigned)(seed % 65521L); index = (int)(random & MASK); if (r3[index] == EMPTY) r3[index] = i++; else continue; } for (i = 0; i < X_SIZE; i++) { seed = (long)(5L * seed + (long)i); random = (unsigned)(seed % 65521L); x[i] = random & 03; } if (decrypt) { invert(r1); invert(r2); invert(r3); } } invert(r) unsigned r[ROTORSIZ]; { unsigned t[ROTORSIZ]; register int i; for (i = 0; i < ROTORSIZ; i++) t[i] = r[i]; for (i = 0; i < ROTORSIZ; i++) r[t[i]] = i; } crypt() { register int ch; register int i = 0; register unsigned ofs1 = 0; register unsigned ofs2 = 0; register unsigned ofs3 = 0; while ((ch = getchar()) != EOF) { putchar(r3[r2[r1[ch+ofs1&MASK]+ofs2&MASK]+ofs3&MASK]); switch (x[i]){ case 00: ofs1 = ++ofs1 & MASK; break; case 01: ofs2 = ++ofs2 & MASK; break; case 02: ofs3 = ++ofs3 & MASK; break; } if (ofs1 == 0) ofs2 = ++ofs2 & MASK; if (ofs2 == 0) ofs3 = ++ofs3 & MASK; if (++i == X_SIZE) i = 0; } } decrypt() { register int ch; register int i = 0; register unsigned ofs1 = 0; register unsigned ofs2 = 0; register unsigned ofs3 = 0; while ((ch = getchar()) != EOF) { putchar(r1[r2[r3[ch]-ofs3&MASK]-ofs2&MASK]-ofs1&MASK); switch (x[i]){ case 00: ofs1 = ++ofs1 & MASK; break; case 01: ofs2 = ++ofs2 & MASK; break; case 02: ofs3 = ++ofs3 & MASK; break; } if (ofs1 == 0) ofs2 = ++ofs2 & MASK; if (ofs2 == 0) ofs3 = ++ofs3 & MASK; if (++i == X_SIZE) i = 0; } } main(argc, argv) int argc; char *argv[]; { int flag; char *p; p = strrchr(argv[0], '/'); if (p == NULL) p = argv[0]; else ++p; if (strcmp(p, "crypt") == 0) flag = 0; else flag = 1; if (argc != 2) init(getpass("Enter key: "), flag); else init(argv[1], flag); if (flag) decrypt(); else crypt(); }