113571821Stholo /*
213571821Stholo * Trivially encode strings to protect them from innocent eyes (i.e.,
313571821Stholo * inadvertent password compromises, like a network administrator
413571821Stholo * who's watching packets for legitimate reasons and accidentally sees
513571821Stholo * the password protocol go by).
613571821Stholo *
713571821Stholo * This is NOT secure encryption.
813571821Stholo *
913571821Stholo * It would be tempting to encode the password according to username
1013571821Stholo * and repository, so that the same password would encode to a
1113571821Stholo * different string when used with different usernames and/or
1213571821Stholo * repositories. However, then users would not be able to cut and
1313571821Stholo * paste passwords around. They're not supposed to anyway, but we all
1413571821Stholo * know they will, and there's no reason to make it harder for them if
1513571821Stholo * we're not trying to provide real security anyway.
1613571821Stholo */
1713571821Stholo
1813571821Stholo /* Set this to test as a standalone program. */
1913571821Stholo /* #define DIAGNOSTIC */
2013571821Stholo
2113571821Stholo #ifndef DIAGNOSTIC
2213571821Stholo #include "cvs.h"
2313571821Stholo #else /* ! DIAGNOSTIC */
2413571821Stholo /* cvs.h won't define this for us */
2513571821Stholo #define AUTH_CLIENT_SUPPORT
2613571821Stholo #define xmalloc malloc
2713571821Stholo /* Use "gcc -fwritable-strings". */
2813571821Stholo #include <stdio.h>
2913571821Stholo #include <stdio.h>
3013571821Stholo #include <string.h>
3113571821Stholo #endif /* ! DIAGNOSTIC */
3213571821Stholo
3313571821Stholo #if defined(AUTH_CLIENT_SUPPORT) || defined(AUTH_SERVER_SUPPORT)
3413571821Stholo
3513571821Stholo /* Map characters to each other randomly and symmetrically, A <--> B.
3613571821Stholo *
3713571821Stholo * We divide the ASCII character set into 3 domains: control chars (0
3813571821Stholo * thru 31), printing chars (32 through 126), and "meta"-chars (127
3913571821Stholo * through 255). The control chars map _to_ themselves, the printing
4013571821Stholo * chars map _among_ themselves, and the meta chars map _among_
4113571821Stholo * themselves. Why is this thus?
4213571821Stholo *
4313571821Stholo * No character in any of these domains maps to a character in another
4413571821Stholo * domain, because I'm not sure what characters are legal in
4513571821Stholo * passwords, or what tools people are likely to use to cut and paste
4613571821Stholo * them. It seems prudent not to introduce control or meta chars,
4713571821Stholo * unless the user introduced them first. And having the control
4813571821Stholo * chars all map to themselves insures that newline and
4913571821Stholo * carriage-return are safely handled.
5013571821Stholo */
5113571821Stholo
52c26070a5Stholo static unsigned char
53*2286d8edStholo shifts[] = {
54*2286d8edStholo 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
55*2286d8edStholo 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
56*2286d8edStholo 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
57*2286d8edStholo 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
58*2286d8edStholo 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
59*2286d8edStholo 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
60*2286d8edStholo 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
61*2286d8edStholo 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
62*2286d8edStholo 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
63*2286d8edStholo 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
64*2286d8edStholo 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
65*2286d8edStholo 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
66*2286d8edStholo 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
67*2286d8edStholo 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
68*2286d8edStholo 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
69*2286d8edStholo 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152 };
7013571821Stholo
7113571821Stholo
7213571821Stholo /* SCRAMBLE and DESCRAMBLE work like this:
7313571821Stholo *
7413571821Stholo * scramble(STR) returns SCRM, a scrambled copy of STR. SCRM[0] is a
7513571821Stholo * single letter indicating the scrambling method. As of this
7613571821Stholo * writing, the only legal method is 'A', but check the code for more
7713571821Stholo * up-to-date information. The copy will have been allocated with
7813571821Stholo * malloc().
7913571821Stholo *
8013571821Stholo * descramble(SCRM) returns STR, again in its own malloc'd space.
8113571821Stholo * descramble() uses SCRM[0] to determine which method of unscrambling
8213571821Stholo * to use. If it does not recognize the method, it dies with error.
8313571821Stholo */
8413571821Stholo
8513571821Stholo /* Return a malloc'd, scrambled version of STR. */
8613571821Stholo char *
scramble(str)8713571821Stholo scramble (str)
8813571821Stholo char *str;
8913571821Stholo {
9013571821Stholo int i;
9113571821Stholo char *s;
9213571821Stholo
9313571821Stholo /* +2 to hold the 'A' prefix that indicates which version of
94*2286d8edStholo scrambling this is (the first, obviously, since we only do one
95*2286d8edStholo kind of scrambling so far), and then the '\0' of course. */
96c26070a5Stholo s = (char *) xmalloc (strlen (str) + 2);
9713571821Stholo
98*2286d8edStholo /* Scramble (TM) version prefix. */
99*2286d8edStholo s[0] = 'A';
10013571821Stholo strcpy (s + 1, str);
10113571821Stholo
10213571821Stholo for (i = 1; s[i]; i++)
103c26070a5Stholo s[i] = shifts[(unsigned char)(s[i])];
10413571821Stholo
10513571821Stholo return s;
10613571821Stholo }
10713571821Stholo
10813571821Stholo /* Decode the string in place. */
10913571821Stholo char *
descramble(str)11013571821Stholo descramble (str)
11113571821Stholo char *str;
11213571821Stholo {
113c26070a5Stholo char *s;
114c26070a5Stholo int i;
11513571821Stholo
11613571821Stholo /* For now we can only handle one kind of scrambling. In the future
117*2286d8edStholo there may be other kinds, and this `if' will become a `switch'. */
11813571821Stholo if (str[0] != 'A')
11913571821Stholo #ifndef DIAGNOSTIC
12013571821Stholo error (1, 0, "descramble: unknown scrambling method");
12113571821Stholo #else /* DIAGNOSTIC */
12213571821Stholo {
12313571821Stholo fprintf (stderr, "descramble: unknown scrambling method\n", str);
12413571821Stholo fflush (stderr);
125c2c61682Stholo exit (EXIT_FAILURE);
12613571821Stholo }
12713571821Stholo #endif /* DIAGNOSTIC */
12813571821Stholo
12913571821Stholo /* Method `A' is symmetrical, so scramble again to decrypt. */
13013571821Stholo s = scramble (str + 1);
13113571821Stholo
132c26070a5Stholo /* Shift the whole string one char to the left, pushing the unwanted
133c26070a5Stholo 'A' off the left end. Safe, because s is null-terminated. */
134c26070a5Stholo for (i = 0; s[i]; i++)
135c26070a5Stholo s[i] = s[i + 1];
13613571821Stholo
137c26070a5Stholo return s;
13813571821Stholo }
13913571821Stholo
14013571821Stholo #endif /* (AUTH_CLIENT_SUPPORT || AUTH_SERVER_SUPPORT) from top of file */
14113571821Stholo
14213571821Stholo #ifdef DIAGNOSTIC
14313571821Stholo int
main()14413571821Stholo main ()
14513571821Stholo {
14613571821Stholo int i;
14713571821Stholo char *e, *m, biggie[256];
14813571821Stholo
14913571821Stholo char *cleartexts[5];
15013571821Stholo cleartexts[0] = "first";
15113571821Stholo cleartexts[1] = "the second";
15213571821Stholo cleartexts[2] = "this is the third";
15313571821Stholo cleartexts[3] = "$#% !!\\3";
15413571821Stholo cleartexts[4] = biggie;
15513571821Stholo
15613571821Stholo /* Set up the most important test string: */
15713571821Stholo /* Can't have a real ASCII zero in the string, because we want to
15813571821Stholo use printf, so we substitute the character zero. */
15913571821Stholo biggie[0] = '0';
16013571821Stholo /* The rest of the string gets straight ascending ASCII. */
16113571821Stholo for (i = 1; i < 256; i++)
16213571821Stholo biggie[i] = i;
16313571821Stholo
16413571821Stholo /* Test all the strings. */
16513571821Stholo for (i = 0; i < 5; i++)
16613571821Stholo {
16713571821Stholo printf ("clear%d: %s\n", i, cleartexts[i]);
16813571821Stholo e = scramble (cleartexts[i]);
16913571821Stholo printf ("scram%d: %s\n", i, e);
17013571821Stholo m = descramble (e);
17113571821Stholo free (e);
17213571821Stholo printf ("clear%d: %s\n\n", i, m);
17313571821Stholo free (m);
17413571821Stholo }
17513571821Stholo
17613571821Stholo fflush (stdout);
17713571821Stholo return 0;
17813571821Stholo }
17913571821Stholo #endif /* DIAGNOSTIC */
18013571821Stholo
18113571821Stholo /*
18213571821Stholo * ;;; The Emacs Lisp that did the dirty work ;;;
18313571821Stholo * (progn
18413571821Stholo *
18513571821Stholo * ;; Helper func.
18613571821Stholo * (defun random-elt (lst)
18713571821Stholo * (let* ((len (length lst))
18813571821Stholo * (rnd (random len)))
18913571821Stholo * (nth rnd lst)))
19013571821Stholo *
19113571821Stholo * ;; A list of all characters under 127, each appearing once.
19213571821Stholo * (setq non-meta-chars
19313571821Stholo * (let ((i 0)
19413571821Stholo * (l nil))
19513571821Stholo * (while (< i 127)
19613571821Stholo * (setq l (cons i l)
19713571821Stholo * i (1+ i)))
19813571821Stholo * l))
19913571821Stholo *
20013571821Stholo * ;; A list of all characters 127 and above, each appearing once.
20113571821Stholo * (setq meta-chars
20213571821Stholo * (let ((i 127)
20313571821Stholo * (l nil))
20413571821Stholo * (while (< i 256)
20513571821Stholo * (setq l (cons i l)
20613571821Stholo * i (1+ i)))
20713571821Stholo * l))
20813571821Stholo *
20913571821Stholo * ;; A vector that will hold the chars in a random order.
21013571821Stholo * (setq scrambled-chars (make-vector 256 0))
21113571821Stholo *
21213571821Stholo * ;; These characters should map to themselves.
21313571821Stholo * (let ((i 0))
21413571821Stholo * (while (< i 32)
21513571821Stholo * (aset scrambled-chars i i)
21613571821Stholo * (setq non-meta-chars (delete i non-meta-chars)
21713571821Stholo * i (1+ i))))
21813571821Stholo *
21913571821Stholo * ;; Assign random (but unique) values, within the non-meta chars.
22013571821Stholo * (let ((i 32))
22113571821Stholo * (while (< i 127)
22213571821Stholo * (let ((ch (random-elt non-meta-chars)))
22313571821Stholo * (if (= 0 (aref scrambled-chars i))
22413571821Stholo * (progn
22513571821Stholo * (aset scrambled-chars i ch)
22613571821Stholo * (aset scrambled-chars ch i)
22713571821Stholo * (setq non-meta-chars (delete ch non-meta-chars)
22813571821Stholo * non-meta-chars (delete i non-meta-chars))))
22913571821Stholo * (setq i (1+ i)))))
23013571821Stholo *
23113571821Stholo * ;; Assign random (but unique) values, within the non-meta chars.
23213571821Stholo * (let ((i 127))
23313571821Stholo * (while (< i 256)
23413571821Stholo * (let ((ch (random-elt meta-chars)))
23513571821Stholo * (if (= 0 (aref scrambled-chars i))
23613571821Stholo * (progn
23713571821Stholo * (aset scrambled-chars i ch)
23813571821Stholo * (aset scrambled-chars ch i)
23913571821Stholo * (setq meta-chars (delete ch meta-chars)
24013571821Stholo * meta-chars (delete i meta-chars))))
24113571821Stholo * (setq i (1+ i)))))
24213571821Stholo *
24313571821Stholo * ;; Now use the `scrambled-chars' vector to get your C array.
24413571821Stholo * )
24513571821Stholo */
246