117721Speter/* 217721Speter * Trivially encode strings to protect them from innocent eyes (i.e., 317721Speter * inadvertent password compromises, like a network administrator 417721Speter * who's watching packets for legitimate reasons and accidentally sees 517721Speter * the password protocol go by). 617721Speter * 717721Speter * This is NOT secure encryption. 817721Speter * 917721Speter * It would be tempting to encode the password according to username 1017721Speter * and repository, so that the same password would encode to a 1117721Speter * different string when used with different usernames and/or 1217721Speter * repositories. However, then users would not be able to cut and 1317721Speter * paste passwords around. They're not supposed to anyway, but we all 1417721Speter * know they will, and there's no reason to make it harder for them if 1517721Speter * we're not trying to provide real security anyway. 1617721Speter */ 1717721Speter 1817721Speter/* Set this to test as a standalone program. */ 1917721Speter/* #define DIAGNOSTIC */ 2017721Speter 2117721Speter#ifndef DIAGNOSTIC 2217721Speter#include "cvs.h" 2317721Speter#else /* ! DIAGNOSTIC */ 2417721Speter/* cvs.h won't define this for us */ 2517721Speter#define AUTH_CLIENT_SUPPORT 2617721Speter#define xmalloc malloc 2717721Speter/* Use "gcc -fwritable-strings". */ 2817721Speter#include <stdio.h> 2917721Speter#include <stdio.h> 3017721Speter#include <string.h> 3117721Speter#endif /* ! DIAGNOSTIC */ 3217721Speter 3317721Speter#if defined(AUTH_CLIENT_SUPPORT) || defined(AUTH_SERVER_SUPPORT) 3417721Speter 3517721Speter/* Map characters to each other randomly and symmetrically, A <--> B. 3617721Speter * 3717721Speter * We divide the ASCII character set into 3 domains: control chars (0 3817721Speter * thru 31), printing chars (32 through 126), and "meta"-chars (127 3917721Speter * through 255). The control chars map _to_ themselves, the printing 4017721Speter * chars map _among_ themselves, and the meta chars map _among_ 4117721Speter * themselves. Why is this thus? 4217721Speter * 4317721Speter * No character in any of these domains maps to a character in another 4417721Speter * domain, because I'm not sure what characters are legal in 4517721Speter * passwords, or what tools people are likely to use to cut and paste 4617721Speter * them. It seems prudent not to introduce control or meta chars, 4717721Speter * unless the user introduced them first. And having the control 4817721Speter * chars all map to themselves insures that newline and 4917721Speter * carriage-return are safely handled. 5017721Speter */ 5117721Speter 5217721Speterstatic unsigned char 5332785Spetershifts[] = { 5432785Speter 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 5532785Speter 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 5632785Speter 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87, 5732785Speter 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105, 5832785Speter 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35, 5932785Speter 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56, 6032785Speter 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48, 6132785Speter 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223, 6232785Speter 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190, 6332785Speter 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193, 6432785Speter 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212, 6532785Speter 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246, 6632785Speter 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176, 6732785Speter 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127, 6832785Speter 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195, 6932785Speter 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152 }; 7017721Speter 7117721Speter 7217721Speter/* SCRAMBLE and DESCRAMBLE work like this: 7317721Speter * 7417721Speter * scramble(STR) returns SCRM, a scrambled copy of STR. SCRM[0] is a 7517721Speter * single letter indicating the scrambling method. As of this 7617721Speter * writing, the only legal method is 'A', but check the code for more 7717721Speter * up-to-date information. The copy will have been allocated with 78109655Speter * xmalloc(). 7917721Speter * 80109655Speter * descramble(SCRM) returns STR, again in its own xmalloc'd space. 8117721Speter * descramble() uses SCRM[0] to determine which method of unscrambling 8217721Speter * to use. If it does not recognize the method, it dies with error. 8317721Speter */ 8417721Speter 85109655Speter/* Return a xmalloc'd, scrambled version of STR. */ 8617721Speterchar * 8717721Speterscramble (str) 8832785Speter char *str; 8917721Speter{ 9032785Speter int i; 9132785Speter char *s; 9217721Speter 9332785Speter /* +2 to hold the 'A' prefix that indicates which version of 9432785Speter scrambling this is (the first, obviously, since we only do one 9532785Speter kind of scrambling so far), and then the '\0' of course. */ 9632785Speter s = (char *) xmalloc (strlen (str) + 2); 9717721Speter 9832785Speter /* Scramble (TM) version prefix. */ 9932785Speter s[0] = 'A'; 10032785Speter strcpy (s + 1, str); 10117721Speter 10232785Speter for (i = 1; s[i]; i++) 10332785Speter s[i] = shifts[(unsigned char)(s[i])]; 10417721Speter 10532785Speter return s; 10617721Speter} 10717721Speter 10817721Speter/* Decode the string in place. */ 10917721Speterchar * 11017721Speterdescramble (str) 11132785Speter char *str; 11217721Speter{ 11332785Speter char *s; 11432785Speter int i; 11517721Speter 11632785Speter /* For now we can only handle one kind of scrambling. In the future 11732785Speter there may be other kinds, and this `if' will become a `switch'. */ 11832785Speter if (str[0] != 'A') 11917721Speter#ifndef DIAGNOSTIC 12032785Speter error (1, 0, "descramble: unknown scrambling method"); 12117721Speter#else /* DIAGNOSTIC */ 12232785Speter { 12332785Speter fprintf (stderr, "descramble: unknown scrambling method\n", str); 12432785Speter fflush (stderr); 12532785Speter exit (EXIT_FAILURE); 12632785Speter } 12717721Speter#endif /* DIAGNOSTIC */ 12817721Speter 12932785Speter /* Method `A' is symmetrical, so scramble again to decrypt. */ 13032785Speter s = scramble (str + 1); 13117721Speter 13232785Speter /* Shift the whole string one char to the left, pushing the unwanted 13332785Speter 'A' off the left end. Safe, because s is null-terminated. */ 13432785Speter for (i = 0; s[i]; i++) 13532785Speter s[i] = s[i + 1]; 13617721Speter 13732785Speter return s; 13817721Speter} 13917721Speter 14017721Speter#endif /* (AUTH_CLIENT_SUPPORT || AUTH_SERVER_SUPPORT) from top of file */ 14117721Speter 14217721Speter#ifdef DIAGNOSTIC 14317721Speterint 14417721Spetermain () 14517721Speter{ 14632785Speter int i; 14732785Speter char *e, *m, biggie[256]; 14817721Speter 14932785Speter char *cleartexts[5]; 15032785Speter cleartexts[0] = "first"; 15132785Speter cleartexts[1] = "the second"; 15232785Speter cleartexts[2] = "this is the third"; 15332785Speter cleartexts[3] = "$#% !!\\3"; 15432785Speter cleartexts[4] = biggie; 15517721Speter 15632785Speter /* Set up the most important test string: */ 15732785Speter /* Can't have a real ASCII zero in the string, because we want to 15832785Speter use printf, so we substitute the character zero. */ 15932785Speter biggie[0] = '0'; 16032785Speter /* The rest of the string gets straight ascending ASCII. */ 16132785Speter for (i = 1; i < 256; i++) 16232785Speter biggie[i] = i; 16332785Speter 16432785Speter /* Test all the strings. */ 16532785Speter for (i = 0; i < 5; i++) 16617721Speter { 16732785Speter printf ("clear%d: %s\n", i, cleartexts[i]); 16832785Speter e = scramble (cleartexts[i]); 16932785Speter printf ("scram%d: %s\n", i, e); 17032785Speter m = descramble (e); 17132785Speter free (e); 17232785Speter printf ("clear%d: %s\n\n", i, m); 17332785Speter free (m); 17417721Speter } 17517721Speter 17632785Speter fflush (stdout); 17732785Speter return 0; 17817721Speter} 17917721Speter#endif /* DIAGNOSTIC */ 18017721Speter 18117721Speter/* 18217721Speter * ;;; The Emacs Lisp that did the dirty work ;;; 18317721Speter * (progn 18417721Speter * 18517721Speter * ;; Helper func. 18617721Speter * (defun random-elt (lst) 18717721Speter * (let* ((len (length lst)) 18817721Speter * (rnd (random len))) 18917721Speter * (nth rnd lst))) 19017721Speter * 19117721Speter * ;; A list of all characters under 127, each appearing once. 19217721Speter * (setq non-meta-chars 19317721Speter * (let ((i 0) 19417721Speter * (l nil)) 19517721Speter * (while (< i 127) 19617721Speter * (setq l (cons i l) 19717721Speter * i (1+ i))) 19817721Speter * l)) 19917721Speter * 20017721Speter * ;; A list of all characters 127 and above, each appearing once. 20117721Speter * (setq meta-chars 20217721Speter * (let ((i 127) 20317721Speter * (l nil)) 20417721Speter * (while (< i 256) 20517721Speter * (setq l (cons i l) 20617721Speter * i (1+ i))) 20717721Speter * l)) 20817721Speter * 20917721Speter * ;; A vector that will hold the chars in a random order. 21017721Speter * (setq scrambled-chars (make-vector 256 0)) 21117721Speter * 21217721Speter * ;; These characters should map to themselves. 21317721Speter * (let ((i 0)) 21417721Speter * (while (< i 32) 21517721Speter * (aset scrambled-chars i i) 21617721Speter * (setq non-meta-chars (delete i non-meta-chars) 21717721Speter * i (1+ i)))) 21817721Speter * 21917721Speter * ;; Assign random (but unique) values, within the non-meta chars. 22017721Speter * (let ((i 32)) 22117721Speter * (while (< i 127) 22217721Speter * (let ((ch (random-elt non-meta-chars))) 22317721Speter * (if (= 0 (aref scrambled-chars i)) 22417721Speter * (progn 22517721Speter * (aset scrambled-chars i ch) 22617721Speter * (aset scrambled-chars ch i) 22717721Speter * (setq non-meta-chars (delete ch non-meta-chars) 22817721Speter * non-meta-chars (delete i non-meta-chars)))) 22917721Speter * (setq i (1+ i))))) 23017721Speter * 23117721Speter * ;; Assign random (but unique) values, within the non-meta chars. 23217721Speter * (let ((i 127)) 23317721Speter * (while (< i 256) 23417721Speter * (let ((ch (random-elt meta-chars))) 23517721Speter * (if (= 0 (aref scrambled-chars i)) 23617721Speter * (progn 23717721Speter * (aset scrambled-chars i ch) 23817721Speter * (aset scrambled-chars ch i) 23917721Speter * (setq meta-chars (delete ch meta-chars) 24017721Speter * meta-chars (delete i meta-chars)))) 24117721Speter * (setq i (1+ i))))) 24217721Speter * 24317721Speter * ;; Now use the `scrambled-chars' vector to get your C array. 24417721Speter * ) 24517721Speter */ 246